diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index 752633ce17432..41c4db8329577 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -280,15 +280,26 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar return; } - if (is_a($class, $type, true)) { + if ('mixed' === $type) { return; } - $checkFunction = sprintf('is_%s', $type); + if (is_a($class, $type, true)) { + return; + } - if (!$reflectionType->isBuiltin() || !$checkFunction($value)) { - throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : \gettype($value), $parameter); + if ('false' === $type) { + if (false === $value) { + return; + } + } elseif ($reflectionType->isBuiltin()) { + $checkFunction = sprintf('is_%s', $type); + if ($checkFunction($value)) { + return; + } } + + throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : \gettype($value), $parameter); } private function getExpressionLanguage(): ExpressionLanguage diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php index bd69302d43765..e5705dce08db1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -836,6 +836,22 @@ public function testUnionTypePassesWithBuiltin() $this->addToAssertionCount(1); } + /** + * @requires PHP 8 + */ + public function testUnionTypePassesWithFalse() + { + $container = new ContainerBuilder(); + + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'create']) + ->setArguments([false]); + + (new CheckTypeDeclarationsPass(true))->process($container); + + $this->addToAssertionCount(1); + } + /** * @requires PHP 8 */ @@ -851,8 +867,6 @@ public function testUnionTypeFailsWithReference() $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\UnionConstructor::__construct()" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo|int", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo" passed.'); (new CheckTypeDeclarationsPass(true))->process($container); - - $this->addToAssertionCount(1); } /** @@ -869,6 +883,57 @@ public function testUnionTypeFailsWithBuiltin() $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\UnionConstructor::__construct()" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo|int", "array" passed.'); (new CheckTypeDeclarationsPass(true))->process($container); + } + + /** + * @requires PHP 8 + */ + public function testUnionTypeWithFalseFailsWithReference() + { + $container = new ContainerBuilder(); + + $container->register('waldo', Waldo::class); + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'create']) + ->setArguments([new Reference('waldo')]); + + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\UnionConstructor::create()" accepts "array|false", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo" passed.'); + + (new CheckTypeDeclarationsPass(true))->process($container); + } + + /** + * @requires PHP 8 + */ + public function testUnionTypeWithFalseFailsWithTrue() + { + $container = new ContainerBuilder(); + + $container->register('waldo', Waldo::class); + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'create']) + ->setArguments([true]); + + $this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\UnionConstructor::create()" accepts "array|false", "boolean" passed.'); + + (new CheckTypeDeclarationsPass(true))->process($container); + } + + /** + * @requires PHP 8 + */ + public function testReferencePassesMixed() + { + $container = new ContainerBuilder(); + + $container->register('waldo', Waldo::class); + $container->register('union', UnionConstructor::class) + ->setFactory([UnionConstructor::class, 'make']) + ->setArguments([new Reference('waldo')]); + + (new CheckTypeDeclarationsPass(true))->process($container); $this->addToAssertionCount(1); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php index 5ba5972863f0b..144480a9780d5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php @@ -7,4 +7,14 @@ class UnionConstructor public function __construct(Foo|int $arg) { } + + public static function create(array|false $arg): static + { + return new static(0); + } + + public static function make(mixed $arg): static + { + return new static(0); + } }