Merge branch '4.4' into 5.1
* 4.4: [DependencyInjection] Support PHP 8 builtin types in CheckTypeDeclarationsPass [DependencyInjection] Fix InvalidParameterTypeException for function parameters [VarDumper] fix mutating $GLOBALS while cloning it
This commit is contained in:
commit
054e00c952
@ -280,15 +280,26 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
|
||||
return;
|
||||
}
|
||||
|
||||
if ('mixed' === $type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_a($class, $type, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$checkFunction = sprintf('is_%s', $type);
|
||||
|
||||
if (!$reflectionType->isBuiltin() || !$checkFunction($value)) {
|
||||
throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : get_debug_type($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 : get_debug_type($value), $parameter);
|
||||
}
|
||||
|
||||
private function getExpressionLanguage(): ExpressionLanguage
|
||||
|
@ -25,6 +25,11 @@ class InvalidParameterTypeException extends InvalidArgumentException
|
||||
$acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType;
|
||||
$this->code = $type;
|
||||
|
||||
parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s::%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $parameter->getDeclaringClass()->getName(), $parameter->getDeclaringFunction()->getName(), $acceptedType, $type));
|
||||
$function = $parameter->getDeclaringFunction();
|
||||
$functionName = $function instanceof \ReflectionMethod
|
||||
? sprintf('%s::%s', $function->getDeclaringClass()->getName(), $function->getName())
|
||||
: $function->getName();
|
||||
|
||||
parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $functionName, $acceptedType, $type));
|
||||
}
|
||||
}
|
||||
|
@ -836,6 +836,22 @@ class CheckTypeDeclarationsPassTest extends TestCase
|
||||
$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 @@ class CheckTypeDeclarationsPassTest extends TestCase
|
||||
$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 @@ class CheckTypeDeclarationsPassTest extends TestCase
|
||||
$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);
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Exception;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException;
|
||||
|
||||
final class InvalidParameterTypeExceptionTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideReflectionParameters
|
||||
*/
|
||||
public function testExceptionMessage(\ReflectionParameter $parameter, string $expectedMessage)
|
||||
{
|
||||
$exception = new InvalidParameterTypeException('my_service', 'int', $parameter);
|
||||
|
||||
self::assertSame($expectedMessage, $exception->getMessage());
|
||||
}
|
||||
|
||||
public function provideReflectionParameters(): iterable
|
||||
{
|
||||
yield 'static method' => [
|
||||
new \ReflectionParameter([MyClass::class, 'doSomething'], 0),
|
||||
'Invalid definition for service "my_service": argument 1 of "Symfony\Component\DependencyInjection\Tests\Exception\MyClass::doSomething()" accepts "array", "int" passed.',
|
||||
];
|
||||
|
||||
yield 'function' => [
|
||||
new \ReflectionParameter(__NAMESPACE__.'\\myFunction', 0),
|
||||
'Invalid definition for service "my_service": argument 1 of "Symfony\Component\DependencyInjection\Tests\Exception\myFunction()" accepts "array", "int" passed.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class MyClass
|
||||
{
|
||||
public static function doSomething(array $arguments): void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
function myFunction(array $arguments): void
|
||||
{
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
}
|
||||
$cursor->hardRefTo = $refs[$r];
|
||||
$cursor->hardRefHandle = $this->useRefHandles & $item->handle;
|
||||
$cursor->hardRefCount = $item->refCount;
|
||||
$cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0;
|
||||
}
|
||||
$cursor->attr = $item->attr;
|
||||
$type = $item->class ?: \gettype($item->value);
|
||||
|
@ -143,13 +143,19 @@ class VarCloner extends AbstractCloner
|
||||
if (Stub::ARRAY_ASSOC === $stub->class) {
|
||||
// Copies of $GLOBALS have very strange behavior,
|
||||
// let's detect them with some black magic
|
||||
$a[$gid] = true;
|
||||
|
||||
// Happens with copies of $GLOBALS
|
||||
if (isset($v[$gid])) {
|
||||
if (\PHP_VERSION_ID < 80100 && ($a[$gid] = true) && isset($v[$gid])) {
|
||||
unset($v[$gid]);
|
||||
$a = [];
|
||||
foreach ($v as $gk => &$gv) {
|
||||
if ($v === $gv) {
|
||||
unset($v);
|
||||
$v = new Stub();
|
||||
$v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0];
|
||||
$v->handle = -1;
|
||||
$gv = &$hardRefs[spl_object_id($v)];
|
||||
$gv = $v;
|
||||
}
|
||||
|
||||
$a[$gk] = &$gv;
|
||||
}
|
||||
unset($gv);
|
||||
|
@ -411,6 +411,7 @@ EOTXT
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
* @requires PHP < 8.1
|
||||
*/
|
||||
public function testSpecialVars56()
|
||||
{
|
||||
@ -425,11 +426,11 @@ array:3 [
|
||||
]
|
||||
]
|
||||
1 => array:1 [
|
||||
"GLOBALS" => &2 array:1 [
|
||||
"GLOBALS" => &2 array:1 [&2]
|
||||
]
|
||||
"GLOBALS" => & array:1 [ …1]
|
||||
]
|
||||
2 => &3 array:1 [
|
||||
"GLOBALS" => &3 array:1 [&3]
|
||||
]
|
||||
2 => &2 array:1 [&2]
|
||||
]
|
||||
EOTXT
|
||||
,
|
||||
@ -440,6 +441,7 @@ EOTXT
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
* @requires PHP < 8.1
|
||||
*/
|
||||
public function testGlobals()
|
||||
{
|
||||
@ -462,11 +464,11 @@ EOTXT
|
||||
<<<'EOTXT'
|
||||
array:2 [
|
||||
1 => array:1 [
|
||||
"GLOBALS" => &1 array:1 [
|
||||
"GLOBALS" => &1 array:1 [&1]
|
||||
]
|
||||
"GLOBALS" => & array:1 [ …1]
|
||||
]
|
||||
2 => &2 array:1 [
|
||||
"GLOBALS" => &2 array:1 [&2]
|
||||
]
|
||||
2 => &1 array:1 [&1]
|
||||
]
|
||||
|
||||
EOTXT
|
||||
@ -556,6 +558,6 @@ EOTXT
|
||||
return $var;
|
||||
};
|
||||
|
||||
return [$var(), $GLOBALS, &$GLOBALS];
|
||||
return eval('return [$var(), $GLOBALS, &$GLOBALS];');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user