Add support of PHP8 static return type for withers

This commit is contained in:
Laurent VOULLEMIER 2020-04-30 14:51:38 +02:00
parent 71b3912143
commit 04fdf05cff
8 changed files with 184 additions and 1 deletions

View File

@ -23,6 +23,7 @@ foreach ($loader->getClassMap() as $class => $file) {
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Compiler/OptionalServiceClass.php'):
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ParentNotExists.php'):
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/BadClasses/MissingParent.php'):
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/WitherStaticReturnType.php'):
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/'):
case false !== strpos($file, '/src/Symfony/Component/ErrorHandler/Tests/Fixtures/'):
case false !== strpos($file, '/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php'):

View File

@ -19,6 +19,7 @@ CHANGELOG
* deprecated `Definition::getDeprecationMessage()`, use `Definition::getDeprecation()` instead
* deprecated `Alias::getDeprecationMessage()`, use `Alias::getDeprecation()` instead
* deprecated PHP-DSL's `inline()` function, use `service()` instead
* added support of PHP8 static return type for withers
5.0.0
-----

View File

@ -51,7 +51,7 @@ class AutowireRequiredMethodsPass extends AbstractRecursivePass
while (true) {
if (false !== $doc = $r->getDocComment()) {
if (false !== stripos($doc, '@required') && preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@required(?:\s|\*/$)#i', $doc)) {
if (preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@return\s++static[\s\*]#i', $doc)) {
if ($this->isWither($reflectionMethod, $doc)) {
$withers[] = [$reflectionMethod->name, [], true];
} else {
$value->addMethodCall($reflectionMethod->name, []);
@ -81,4 +81,20 @@ class AutowireRequiredMethodsPass extends AbstractRecursivePass
return $value;
}
private function isWither(\ReflectionMethod $reflectionMethod, string $doc): bool
{
$match = preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@return\s++(static|\$this)[\s\*]#i', $doc, $matches);
if ($match && 'static' === $matches[1]) {
return true;
}
if ($match && '$this' === $matches[1]) {
return false;
}
$reflectionType = $reflectionMethod->hasReturnType() ? $reflectionMethod->getReturnType() : null;
return $reflectionType instanceof \ReflectionNamedType && 'static' === $reflectionType->getName();
}
}

View File

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Compiler\AutowireRequiredMethodsPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Tests\Fixtures\WitherStaticReturnType;
require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php';
@ -99,4 +100,28 @@ class AutowireRequiredMethodsPassTest extends TestCase
];
$this->assertSame($expected, $methodCalls);
}
/**
* @requires PHP 8
*/
public function testWitherWithStaticReturnTypeInjection()
{
$container = new ContainerBuilder();
$container->register(Foo::class);
$container
->register('wither', WitherStaticReturnType::class)
->setAutowired(true);
(new ResolveClassPass())->process($container);
(new AutowireRequiredMethodsPass())->process($container);
$methodCalls = $container->getDefinition('wither')->getMethodCalls();
$expected = [
['withFoo', [], true],
['setFoo', []],
];
$this->assertSame($expected, $methodCalls);
}
}

View File

@ -46,6 +46,7 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy;
use Symfony\Component\DependencyInjection\Tests\Fixtures\WitherStaticReturnType;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\ExpressionLanguage\Expression;
@ -1624,6 +1625,25 @@ class ContainerBuilderTest extends TestCase
$this->assertInstanceOf(Foo::class, $wither->foo);
}
/**
* @requires PHP 8
*/
public function testWitherWithStaticReturnType()
{
$container = new ContainerBuilder();
$container->register(Foo::class);
$container
->register('wither', WitherStaticReturnType::class)
->setPublic(true)
->setAutowired(true);
$container->compile();
$wither = $container->get('wither');
$this->assertInstanceOf(Foo::class, $wither->foo);
}
public function testAutoAliasing()
{
$container = new ContainerBuilder();

View File

@ -42,6 +42,7 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber;
use Symfony\Component\DependencyInjection\Tests\Fixtures\WitherStaticReturnType;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\ExpressionLanguage\Expression;
@ -1362,6 +1363,31 @@ class PhpDumperTest extends TestCase
$this->assertInstanceOf(Foo::class, $wither->foo);
}
/**
* @requires PHP 8
*/
public function testWitherWithStaticReturnType()
{
$container = new ContainerBuilder();
$container->register(Foo::class);
$container
->register('wither', WitherStaticReturnType::class)
->setPublic(true)
->setAutowired(true);
$container->compile();
$dumper = new PhpDumper($container);
$dump = $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Service_WitherStaticReturnType']);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_wither_staticreturntype.php', $dump);
eval('?>'.$dump);
$container = new \Symfony_DI_PhpDumper_Service_WitherStaticReturnType();
$wither = $container->get('wither');
$this->assertInstanceOf(Foo::class, $wither->foo);
}
/**
* @group legacy
*/

View File

@ -0,0 +1,30 @@
<?php
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
class WitherStaticReturnType
{
public $foo;
/**
* @required
*/
public function withFoo(Foo $foo): static
{
$new = clone $this;
$new->foo = $foo;
return $new;
}
/**
* @required
* @return $this
*/
public function setFoo(Foo $foo): static
{
$this->foo = $foo;
return $this;
}
}

View File

@ -0,0 +1,64 @@
<?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* @internal This class has been auto-generated by the Symfony Dependency Injection Component.
*/
class Symfony_DI_PhpDumper_Service_WitherStaticReturnType extends Container
{
protected $parameters = [];
public function __construct()
{
$this->services = $this->privates = [];
$this->methodMap = [
'wither' => 'getWitherService',
];
$this->aliases = [];
}
public function compile(): void
{
throw new LogicException('You cannot compile a dumped container that was already compiled.');
}
public function isCompiled(): bool
{
return true;
}
public function getRemovedIds(): array
{
return [
'Psr\\Container\\ContainerInterface' => true,
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
'Symfony\\Component\\DependencyInjection\\Tests\\Compiler\\Foo' => true,
];
}
/**
* Gets the public 'wither' shared autowired service.
*
* @return \Symfony\Component\DependencyInjection\Tests\Compiler\WitherStaticReturnType
*/
protected function getWitherService()
{
$instance = new \Symfony\Component\DependencyInjection\Tests\Compiler\WitherStaticReturnType();
$a = new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo();
$this->services['wither'] = $instance = $instance->withFoo($a);
$instance->setFoo($a);
return $instance;
}
}