From 5197b47075e41278767402ea7560dbd23bb156f2 Mon Sep 17 00:00:00 2001 From: kor3k Date: Thu, 8 Feb 2024 23:46:29 +0100 Subject: [PATCH] [DependencyInjection] fix unable to make lazy service from readonly class --- .../DependencyInjection/Dumper/PhpDumper.php | 4 +++- .../LazyProxy/PhpDumper/LazyServiceDumper.php | 2 +- .../Tests/Fixtures/ReadonlyTest.php | 20 +++++++++++++++++++ .../PhpDumper/LazyServiceDumperTest.php | 13 ++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/ReadonlyTest.php diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 81b500c5ad7a7..23e65483b03d3 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -624,7 +624,9 @@ private function generateProxyClasses(): array $proxyCode = substr(self::stripComments($proxyCode), 5); } - $proxyClass = explode(' ', $this->inlineRequires ? substr($proxyCode, \strlen($code)) : $proxyCode, 3)[1]; + $proxyClass = $this->inlineRequires ? substr($proxyCode, \strlen($code)) : $proxyCode; + $i = strpos($proxyClass, 'class'); + $proxyClass = substr($proxyClass, 6 + $i, strpos($proxyClass, ' ', 7 + $i) - $i - 6); if ($this->asFiles || $this->namespace) { $proxyCode .= "\nif (!\\class_exists('$proxyClass', false)) {\n \\class_alias(__NAMESPACE__.'\\\\$proxyClass', '$proxyClass', false);\n}\n"; diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php index b1df5f0f0cda4..0d4426c44039e 100644 --- a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php +++ b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php @@ -105,7 +105,7 @@ public function getProxyCode(Definition $definition, ?string $id = null): string if ($asGhostObject) { try { - return 'class '.$proxyClass.ProxyHelper::generateLazyGhost($class); + return (\PHP_VERSION_ID >= 80200 && $class?->isReadOnly() ? 'readonly ' : '').'class '.$proxyClass.ProxyHelper::generateLazyGhost($class); } catch (LogicException $e) { throw new InvalidArgumentException(sprintf('Cannot generate lazy ghost for service "%s".', $id ?? $definition->getClass()), 0, $e); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ReadonlyTest.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ReadonlyTest.php new file mode 100644 index 0000000000000..f49931bf39c3b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ReadonlyTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Fixtures; + +readonly class ReadonlyTest +{ + public function say(): string + { + return 'hello'; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/PhpDumper/LazyServiceDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/PhpDumper/LazyServiceDumperTest.php index 064bfc3cc82aa..9a5da0721f0d5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/PhpDumper/LazyServiceDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/LazyProxy/PhpDumper/LazyServiceDumperTest.php @@ -16,6 +16,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\LazyServiceDumper; +use Symfony\Component\DependencyInjection\Tests\Fixtures\ReadonlyTest; class LazyServiceDumperTest extends TestCase { @@ -52,6 +53,18 @@ public function testInvalidClass() $this->expectExceptionMessage('Invalid "proxy" tag for service "stdClass": class "stdClass" doesn\'t implement "Psr\Container\ContainerInterface".'); $dumper->getProxyCode($definition); } + + /** + * @requires PHP 8.2 + */ + public function testReadonlyClass() + { + $dumper = new LazyServiceDumper(); + $definition = (new Definition(ReadonlyTest::class))->setLazy(true); + + $this->assertTrue($dumper->isProxyCandidate($definition)); + $this->assertStringContainsString('readonly class ReadonlyTestGhost', $dumper->getProxyCode($definition)); + } } final class TestContainer implements ContainerInterface