mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
chore: improves type coverage
This commit is contained in:
@ -51,6 +51,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"pestphp/pest-dev-tools": "^2.0.0",
|
"pestphp/pest-dev-tools": "^2.0.0",
|
||||||
|
"rector/rector": "^0.15.0",
|
||||||
"symfony/process": "^6.2.0"
|
"symfony/process": "^6.2.0"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
@ -66,7 +67,9 @@
|
|||||||
"bin/pest"
|
"bin/pest"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"refacto": "rector",
|
||||||
"lint": "pint",
|
"lint": "pint",
|
||||||
|
"test:refactor": "rector --dry-run",
|
||||||
"test:lint": "pint --test",
|
"test:lint": "pint --test",
|
||||||
"test:types": "phpstan analyse --ansi --memory-limit=-1 --debug",
|
"test:types": "phpstan analyse --ansi --memory-limit=-1 --debug",
|
||||||
"test:unit": "php bin/pest --colors=always --exclude-group=integration --compact",
|
"test:unit": "php bin/pest --colors=always --exclude-group=integration --compact",
|
||||||
@ -75,6 +78,7 @@
|
|||||||
"test:integration": "php bin/pest --colors=always --group=integration -v",
|
"test:integration": "php bin/pest --colors=always --group=integration -v",
|
||||||
"update:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always",
|
"update:snapshots": "REBUILD_SNAPSHOTS=true php bin/pest --colors=always",
|
||||||
"test": [
|
"test": [
|
||||||
|
"@rest:refacto",
|
||||||
"@test:lint",
|
"@test:lint",
|
||||||
"@test:types",
|
"@test:types",
|
||||||
"@test:unit",
|
"@test:unit",
|
||||||
|
|||||||
27
rector.php
Normal file
27
rector.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
|
||||||
|
use Rector\Config\RectorConfig;
|
||||||
|
use Rector\Set\ValueObject\LevelSetList;
|
||||||
|
use Rector\Set\ValueObject\SetList;
|
||||||
|
|
||||||
|
return static function (RectorConfig $rectorConfig): void {
|
||||||
|
$rectorConfig->paths([
|
||||||
|
__DIR__.'/src',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$rectorConfig->rules([
|
||||||
|
InlineConstructorDefaultToPropertyRector::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$rectorConfig->sets([
|
||||||
|
LevelSetList::UP_TO_PHP_81,
|
||||||
|
SetList::CODE_QUALITY,
|
||||||
|
SetList::DEAD_CODE,
|
||||||
|
SetList::EARLY_RETURN,
|
||||||
|
SetList::TYPE_DECLARATION,
|
||||||
|
SetList::PRIVATIZATION,
|
||||||
|
]);
|
||||||
|
};
|
||||||
@ -5,16 +5,17 @@ declare(strict_types=1);
|
|||||||
namespace Pest\Bootstrappers;
|
namespace Pest\Bootstrappers;
|
||||||
|
|
||||||
use NunoMaduro\Collision;
|
use NunoMaduro\Collision;
|
||||||
|
use Pest\Contracts\Bootstrapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
final class BootExceptionHandler
|
final class BootExceptionHandler implements Bootstrapper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Boots the Exception Handler.
|
* Boots the Exception Handler.
|
||||||
*/
|
*/
|
||||||
public function __invoke(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
$handler = new Collision\Provider();
|
$handler = new Collision\Provider();
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest\Bootstrappers;
|
namespace Pest\Bootstrappers;
|
||||||
|
|
||||||
|
use Pest\Contracts\Bootstrapper;
|
||||||
use Pest\Support\DatasetInfo;
|
use Pest\Support\DatasetInfo;
|
||||||
use Pest\Support\Str;
|
use Pest\Support\Str;
|
||||||
use function Pest\testDirectory;
|
use function Pest\testDirectory;
|
||||||
@ -15,7 +16,7 @@ use SebastianBergmann\FileIterator\Facade as PhpUnitFileIterator;
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
final class BootFiles
|
final class BootFiles implements Bootstrapper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The Pest convention.
|
* The Pest convention.
|
||||||
@ -33,7 +34,7 @@ final class BootFiles
|
|||||||
/**
|
/**
|
||||||
* Boots the Subscribers.
|
* Boots the Subscribers.
|
||||||
*/
|
*/
|
||||||
public function __invoke(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
$rootPath = TestSuite::getInstance()->rootPath;
|
$rootPath = TestSuite::getInstance()->rootPath;
|
||||||
$testsPath = $rootPath.DIRECTORY_SEPARATOR.testDirectory();
|
$testsPath = $rootPath.DIRECTORY_SEPARATOR.testDirectory();
|
||||||
|
|||||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest\Bootstrappers;
|
namespace Pest\Bootstrappers;
|
||||||
|
|
||||||
|
use Pest\Contracts\Bootstrapper;
|
||||||
use Pest\Subscribers;
|
use Pest\Subscribers;
|
||||||
use PHPUnit\Event;
|
use PHPUnit\Event;
|
||||||
use PHPUnit\Event\Subscriber;
|
use PHPUnit\Event\Subscriber;
|
||||||
@ -11,7 +12,7 @@ use PHPUnit\Event\Subscriber;
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
final class BootSubscribers
|
final class BootSubscribers implements Bootstrapper
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The Kernel subscribers.
|
* The Kernel subscribers.
|
||||||
@ -28,7 +29,7 @@ final class BootSubscribers
|
|||||||
/**
|
/**
|
||||||
* Boots the Subscribers.
|
* Boots the Subscribers.
|
||||||
*/
|
*/
|
||||||
public function __invoke(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
foreach (self::SUBSCRIBERS as $subscriber) {
|
foreach (self::SUBSCRIBERS as $subscriber) {
|
||||||
Event\Facade::registerSubscriber(
|
Event\Facade::registerSubscriber(
|
||||||
|
|||||||
@ -4,13 +4,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest\Bootstrappers;
|
namespace Pest\Bootstrappers;
|
||||||
|
|
||||||
|
use Pest\Contracts\Bootstrapper;
|
||||||
use Pest\Support\View;
|
use Pest\Support\View;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
final class BootView
|
final class BootView implements Bootstrapper
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly OutputInterface $output
|
private readonly OutputInterface $output
|
||||||
@ -21,7 +22,7 @@ final class BootView
|
|||||||
/**
|
/**
|
||||||
* Boots the view renderer.
|
* Boots the view renderer.
|
||||||
*/
|
*/
|
||||||
public function __invoke(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
View::renderUsing($this->output);
|
View::renderUsing($this->output);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,6 @@ trait Pipeable
|
|||||||
*/
|
*/
|
||||||
private function pipes(string $name, object $context, string $scope): array
|
private function pipes(string $name, object $context, string $scope): array
|
||||||
{
|
{
|
||||||
return array_map(fn (Closure $pipe) => $pipe->bindTo($context, $scope), self::$pipes[$name] ?? []);
|
return array_map(fn (Closure $pipe): \Closure => $pipe->bindTo($context, $scope), self::$pipes[$name] ?? []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -259,7 +259,7 @@ trait Testable
|
|||||||
*/
|
*/
|
||||||
private function __callClosure(Closure $closure, array $arguments): mixed
|
private function __callClosure(Closure $closure, array $arguments): mixed
|
||||||
{
|
{
|
||||||
return ExceptionTrace::ensure(fn () => call_user_func_array(Closure::bind($closure, $this, $this::class), $arguments));
|
return ExceptionTrace::ensure(fn (): mixed => call_user_func_array(Closure::bind($closure, $this, $this::class), $arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
16
src/Contracts/Bootstrapper.php
Normal file
16
src/Contracts/Bootstrapper.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\Contracts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface Bootstrapper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Boots the bootstrapper.
|
||||||
|
*/
|
||||||
|
public function boot(): void;
|
||||||
|
}
|
||||||
@ -12,11 +12,9 @@ use InvalidArgumentException;
|
|||||||
final class InvalidExpectationValue extends InvalidArgumentException
|
final class InvalidExpectationValue extends InvalidArgumentException
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return never
|
|
||||||
*
|
|
||||||
* @throws self
|
* @throws self
|
||||||
*/
|
*/
|
||||||
public static function expected(string $type): void
|
public static function expected(string $type): never
|
||||||
{
|
{
|
||||||
throw new self(sprintf('Invalid expectation value type. Expected [%s].', $type));
|
throw new self(sprintf('Invalid expectation value type. Expected [%s].', $type));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,10 +70,12 @@ final class Expectation
|
|||||||
InvalidExpectationValue::expected('string');
|
InvalidExpectationValue::expected('string');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var array<int|string, mixed>|bool $value */
|
$this->toBeJson();
|
||||||
$value = json_decode($this->value, true, 512);
|
|
||||||
|
|
||||||
return $this->toBeJson()->and($value);
|
/** @var array<int|string, mixed>|bool $value */
|
||||||
|
$value = json_decode($this->value, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
|
||||||
|
return $this->and($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -90,9 +90,8 @@ final class OppositeExpectation
|
|||||||
* Creates a new expectation failed exception with a nice readable message.
|
* Creates a new expectation failed exception with a nice readable message.
|
||||||
*
|
*
|
||||||
* @param array<int, mixed> $arguments
|
* @param array<int, mixed> $arguments
|
||||||
* @return never
|
|
||||||
*/
|
*/
|
||||||
private function throwExpectationFailedException(string $name, array $arguments = []): void
|
private function throwExpectationFailedException(string $name, array $arguments = []): never
|
||||||
{
|
{
|
||||||
$exporter = new Exporter();
|
$exporter = new Exporter();
|
||||||
|
|
||||||
|
|||||||
@ -85,7 +85,7 @@ final class TestCaseFactory
|
|||||||
|
|
||||||
$methods = array_values(array_filter(
|
$methods = array_values(array_filter(
|
||||||
$this->methods,
|
$this->methods,
|
||||||
fn ($method) => $methodsUsingOnly === [] || in_array($method, $methodsUsingOnly, true)
|
fn ($method): bool => $methodsUsingOnly === [] || in_array($method, $methodsUsingOnly, true)
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($methods !== []) {
|
if ($methods !== []) {
|
||||||
@ -165,21 +165,21 @@ final class TestCaseFactory
|
|||||||
$classFQN .= $className;
|
$classFQN .= $className;
|
||||||
}
|
}
|
||||||
|
|
||||||
$classAvailableAttributes = array_filter(self::ATTRIBUTES, fn (string $attribute) => $attribute::ABOVE_CLASS);
|
$classAvailableAttributes = array_filter(self::ATTRIBUTES, fn (string $attribute): bool => $attribute::ABOVE_CLASS);
|
||||||
$methodAvailableAttributes = array_filter(self::ATTRIBUTES, fn (string $attribute) => ! $attribute::ABOVE_CLASS);
|
$methodAvailableAttributes = array_filter(self::ATTRIBUTES, fn (string $attribute): bool => ! $attribute::ABOVE_CLASS);
|
||||||
|
|
||||||
$classAttributes = [];
|
$classAttributes = [];
|
||||||
|
|
||||||
foreach ($classAvailableAttributes as $attribute) {
|
foreach ($classAvailableAttributes as $attribute) {
|
||||||
$classAttributes = array_reduce(
|
$classAttributes = array_reduce(
|
||||||
$methods,
|
$methods,
|
||||||
fn (array $carry, TestCaseMethodFactory $methodFactory) => (new $attribute())->__invoke($methodFactory, $carry),
|
fn (array $carry, TestCaseMethodFactory $methodFactory): array => (new $attribute())->__invoke($methodFactory, $carry),
|
||||||
$classAttributes
|
$classAttributes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$methodsCode = implode('', array_map(
|
$methodsCode = implode('', array_map(
|
||||||
fn (TestCaseMethodFactory $methodFactory) => $methodFactory->buildForEvaluation(
|
fn (TestCaseMethodFactory $methodFactory): string => $methodFactory->buildForEvaluation(
|
||||||
$classFQN,
|
$classFQN,
|
||||||
self::ANNOTATIONS,
|
self::ANNOTATIONS,
|
||||||
$methodAvailableAttributes
|
$methodAvailableAttributes
|
||||||
@ -188,7 +188,7 @@ final class TestCaseFactory
|
|||||||
));
|
));
|
||||||
|
|
||||||
$classAttributesCode = implode('', array_map(
|
$classAttributesCode = implode('', array_map(
|
||||||
static fn (string $attribute) => sprintf("\n%s", $attribute),
|
static fn (string $attribute): string => sprintf("\n%s", $attribute),
|
||||||
array_unique($classAttributes),
|
array_unique($classAttributes),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,7 @@ final class TestCaseMethodFactory
|
|||||||
$testCase->chains->chain($this);
|
$testCase->chains->chain($this);
|
||||||
$method->chains->chain($this);
|
$method->chains->chain($this);
|
||||||
|
|
||||||
return \Pest\Support\Closure::bind($closure, $this, $this::class)(...func_get_args());
|
return \Pest\Support\Closure::bind($closure, $this, self::class)(...func_get_args());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,11 +147,11 @@ final class TestCaseMethodFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
$annotations = implode('', array_map(
|
$annotations = implode('', array_map(
|
||||||
static fn ($annotation) => sprintf("\n * %s", $annotation), $annotations,
|
static fn ($annotation): string => sprintf("\n * %s", $annotation), $annotations,
|
||||||
));
|
));
|
||||||
|
|
||||||
$attributes = implode('', array_map(
|
$attributes = implode('', array_map(
|
||||||
static fn ($attribute) => sprintf("\n %s", $attribute), $attributes,
|
static fn ($attribute): string => sprintf("\n %s", $attribute), $attributes,
|
||||||
));
|
));
|
||||||
|
|
||||||
return <<<PHP
|
return <<<PHP
|
||||||
|
|||||||
@ -89,7 +89,7 @@ if (! function_exists('test')) {
|
|||||||
*
|
*
|
||||||
* @return TestCall|TestCase|mixed
|
* @return TestCall|TestCase|mixed
|
||||||
*/
|
*/
|
||||||
function test(string $description = null, Closure $closure = null)
|
function test(string $description = null, Closure $closure = null): HigherOrderTapProxy|TestCall
|
||||||
{
|
{
|
||||||
if ($description === null && TestSuite::getInstance()->test !== null) {
|
if ($description === null && TestSuite::getInstance()->test !== null) {
|
||||||
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
|
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Pest;
|
namespace Pest;
|
||||||
|
|
||||||
|
use Pest\Contracts\Bootstrapper;
|
||||||
use Pest\Plugins\Actions\CallsAddsOutput;
|
use Pest\Plugins\Actions\CallsAddsOutput;
|
||||||
use Pest\Plugins\Actions\CallsBoot;
|
use Pest\Plugins\Actions\CallsBoot;
|
||||||
use Pest\Plugins\Actions\CallsShutdown;
|
use Pest\Plugins\Actions\CallsShutdown;
|
||||||
@ -49,7 +50,10 @@ final class Kernel
|
|||||||
public static function boot(): self
|
public static function boot(): self
|
||||||
{
|
{
|
||||||
foreach (self::BOOTSTRAPPERS as $bootstrapper) {
|
foreach (self::BOOTSTRAPPERS as $bootstrapper) {
|
||||||
Container::getInstance()->get($bootstrapper)->__invoke();
|
$bootstrapper = Container::getInstance()->get($bootstrapper);
|
||||||
|
assert($bootstrapper instanceof Bootstrapper);
|
||||||
|
|
||||||
|
$bootstrapper->boot();
|
||||||
}
|
}
|
||||||
|
|
||||||
(new CallsBoot())->__invoke();
|
(new CallsBoot())->__invoke();
|
||||||
|
|||||||
@ -154,7 +154,7 @@ final class TestCall
|
|||||||
|
|
||||||
$condition = is_callable($condition)
|
$condition = is_callable($condition)
|
||||||
? $condition
|
? $condition
|
||||||
: fn () => $condition;
|
: fn (): bool => $condition;
|
||||||
|
|
||||||
$message = is_string($conditionOrMessage)
|
$message = is_string($conditionOrMessage)
|
||||||
? $conditionOrMessage
|
? $conditionOrMessage
|
||||||
|
|||||||
@ -90,8 +90,7 @@ final class DatasetsRepository
|
|||||||
*/
|
*/
|
||||||
public static function resolve(array $dataset, string $currentTestFile): array|null
|
public static function resolve(array $dataset, string $currentTestFile): array|null
|
||||||
{
|
{
|
||||||
/* @phpstan-ignore-next-line */
|
if ($dataset === []) {
|
||||||
if (empty($dataset)) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,25 +176,21 @@ final class DatasetsRepository
|
|||||||
/**
|
/**
|
||||||
* @return Closure|iterable<int|string, mixed>
|
* @return Closure|iterable<int|string, mixed>
|
||||||
*/
|
*/
|
||||||
private static function getScopedDataset(string $name, string $currentTestFile)
|
private static function getScopedDataset(string $name, string $currentTestFile): Closure|iterable
|
||||||
{
|
{
|
||||||
$matchingDatasets = array_filter(self::$datasets, function (string $key) use ($name, $currentTestFile) {
|
$matchingDatasets = array_filter(self::$datasets, function (string $key) use ($name, $currentTestFile): bool {
|
||||||
[$datasetScope, $datasetName] = explode(self::SEPARATOR, $key);
|
[$datasetScope, $datasetName] = explode(self::SEPARATOR, $key);
|
||||||
|
|
||||||
if ($name !== $datasetName) {
|
if ($name !== $datasetName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! str_starts_with($currentTestFile, $datasetScope)) {
|
return str_starts_with($currentTestFile, $datasetScope);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, ARRAY_FILTER_USE_KEY);
|
}, ARRAY_FILTER_USE_KEY);
|
||||||
|
|
||||||
$closestScopeDatasetKey = array_reduce(
|
$closestScopeDatasetKey = array_reduce(
|
||||||
array_keys($matchingDatasets),
|
array_keys($matchingDatasets),
|
||||||
fn ($keyA, $keyB) => $keyA !== null && strlen($keyA) > strlen($keyB) ? $keyA : $keyB
|
fn ($keyA, $keyB) => $keyA !== null && strlen((string) $keyA) > strlen($keyB) ? $keyA : $keyB
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($closestScopeDatasetKey === null) {
|
if ($closestScopeDatasetKey === null) {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ final class TestRepository
|
|||||||
*/
|
*/
|
||||||
public function getFilenames(): array
|
public function getFilenames(): array
|
||||||
{
|
{
|
||||||
$testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase) => $testCase->methodsUsingOnly() !== []);
|
$testCases = array_filter($this->testCases, static fn (TestCaseFactory $testCase): bool => $testCase->methodsUsingOnly() !== []);
|
||||||
|
|
||||||
if ($testCases === []) {
|
if ($testCases === []) {
|
||||||
$testCases = $this->testCases;
|
$testCases = $this->testCases;
|
||||||
|
|||||||
@ -22,8 +22,8 @@ final class ChainableClosure
|
|||||||
throw ShouldNotHappen::fromMessage('$this not bound to chainable closure.');
|
throw ShouldNotHappen::fromMessage('$this not bound to chainable closure.');
|
||||||
}
|
}
|
||||||
|
|
||||||
\Pest\Support\Closure::bind($closure, $this, $this::class)(...func_get_args());
|
\Pest\Support\Closure::bind($closure, $this, self::class)(...func_get_args());
|
||||||
\Pest\Support\Closure::bind($next, $this, $this::class)(...func_get_args());
|
\Pest\Support\Closure::bind($next, $this, self::class)(...func_get_args());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ final class Container
|
|||||||
private static ?Container $instance = null;
|
private static ?Container $instance = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, mixed>
|
* @var array<string, object|string>
|
||||||
*/
|
*/
|
||||||
private array $instances = [];
|
private array $instances = [];
|
||||||
|
|
||||||
@ -25,37 +25,30 @@ final class Container
|
|||||||
*/
|
*/
|
||||||
public static function getInstance(): self
|
public static function getInstance(): self
|
||||||
{
|
{
|
||||||
if (static::$instance === null) {
|
if (self::$instance === null) {
|
||||||
static::$instance = new self();
|
self::$instance = new self();
|
||||||
}
|
}
|
||||||
|
|
||||||
return static::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a dependency from the container.
|
* Gets a dependency from the container.
|
||||||
*
|
|
||||||
* @template TObject of object
|
|
||||||
*
|
|
||||||
* @param class-string<TObject> $id
|
|
||||||
* @return TObject
|
|
||||||
*/
|
*/
|
||||||
public function get(string $id): mixed
|
public function get(string $id): object|string
|
||||||
{
|
{
|
||||||
if (! array_key_exists($id, $this->instances)) {
|
if (! array_key_exists($id, $this->instances)) {
|
||||||
|
/** @var class-string $id */
|
||||||
$this->instances[$id] = $this->build($id);
|
$this->instances[$id] = $this->build($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var TObject $concrete */
|
return $this->instances[$id];
|
||||||
$concrete = $this->instances[$id];
|
|
||||||
|
|
||||||
return $concrete;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given instance to the container.
|
* Adds the given instance to the container.
|
||||||
*/
|
*/
|
||||||
public function add(string $id, mixed $instance): void
|
public function add(string $id, object|string $instance): void
|
||||||
{
|
{
|
||||||
$this->instances[$id] = $instance;
|
$this->instances[$id] = $instance;
|
||||||
}
|
}
|
||||||
@ -68,7 +61,7 @@ final class Container
|
|||||||
* @param class-string<TObject> $id
|
* @param class-string<TObject> $id
|
||||||
* @return TObject
|
* @return TObject
|
||||||
*/
|
*/
|
||||||
private function build(string $id): mixed
|
private function build(string $id): object
|
||||||
{
|
{
|
||||||
$reflectionClass = new ReflectionClass($id);
|
$reflectionClass = new ReflectionClass($id);
|
||||||
|
|
||||||
@ -77,7 +70,7 @@ final class Container
|
|||||||
|
|
||||||
if ($constructor !== null) {
|
if ($constructor !== null) {
|
||||||
$params = array_map(
|
$params = array_map(
|
||||||
function (ReflectionParameter $param) use ($id) {
|
function (ReflectionParameter $param) use ($id): object|string {
|
||||||
$candidate = Reflection::getParameterClassName($param);
|
$candidate = Reflection::getParameterClassName($param);
|
||||||
|
|
||||||
if ($candidate === null) {
|
if ($candidate === null) {
|
||||||
@ -90,7 +83,6 @@ final class Container
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
return $this->get($candidate);
|
return $this->get($candidate);
|
||||||
},
|
},
|
||||||
$constructor->getParameters()
|
$constructor->getParameters()
|
||||||
|
|||||||
@ -42,15 +42,15 @@ final class Coverage
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($runtime->hasXdebug()) {
|
if (! $runtime->hasXdebug()) {
|
||||||
if (version_compare((string) phpversion('xdebug'), '3.1', '>=')) {
|
return true;
|
||||||
if (! in_array('coverage', xdebug_info('mode'), true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (! version_compare((string) phpversion('xdebug'), '3.1', '>=')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array('coverage', xdebug_info('mode'), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user