Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable_lazy_ghost_objects: true prevents detection of proxy creation errors at Symfony compile time #11402

Open
chrif opened this issue Mar 22, 2024 · 9 comments
Labels

Comments

@chrif
Copy link

chrif commented Mar 22, 2024

enable_lazy_ghost_objects: false is deprecated, but when it is true, clearing the Symfony cache is not enough to get the Unable to create a proxy for a readonly class error. It is only when the proxy class is used that we get it.

So in dev we have auto_generate_proxy_classes: true and we didn't get an error when developing. I guess the problematic proxy was not used in the development use case.

In production we have auto_generate_proxy_classes: false as recommended. We also have a functional test to check that the prod Symfony cache can be cleared. It passed the test.

It's only when we released and used the proxy class that we got the Unable to create a proxy for a readonly class.

With enable_lazy_ghost_objects: false everything works fine, but we have a deprecation message.

@stof
Copy link
Member

stof commented Mar 22, 2024

Can you share the stack trace of the exception you got to see when it was triggered in each case ?

@chrif
Copy link
Author

chrif commented Mar 22, 2024

Below you will find my initial reply, but I found the trigger in production while trying to get the full stack trace. It is the opcache preload.php file that triggers the error. If I comment opcache.preload=/app/config/preload.php in php.ini, I don't get the error, and if I keep it but set APP_DEBUG=1, I don't get the error either.

Versions

doctrine/doctrine-bundle              2.11.3
doctrine/orm                          2.19.0
symfony/framework-bundle              v6.4.4

Stack trace for the prod cache clear functional test when it fails with enable_lazy_ghost_objects: false

In InvalidArgumentException.php line 102:
                                                                               
  [Doctrine\Common\Proxy\Exception\InvalidArgumentException]                   
  Unable to create a proxy for a readonly class "App\Entity\MyEntity".              
                                                                               

Exception trace:
  at /app/vendor/doctrine/common/src/Proxy/Exception/InvalidArgumentException.php:102
 Doctrine\Common\Proxy\Exception\InvalidArgumentException::classMustNotBeReadOnly() at /app/vendor/doctrine/common/src/Proxy/ProxyGenerator.php:372
 Doctrine\Common\Proxy\ProxyGenerator->verifyClassCanBeProxied() at /app/vendor/doctrine/common/src/Proxy/ProxyGenerator.php:312
 Doctrine\Common\Proxy\ProxyGenerator->generateProxyClass() at /app/vendor/doctrine/common/src/Proxy/AbstractProxyFactory.php:146
 Doctrine\Common\Proxy\AbstractProxyFactory->generateProxyClasses() at /app/vendor/doctrine/orm/src/Proxy/ProxyFactory.php:228
 Doctrine\ORM\Proxy\ProxyFactory->generateProxyClasses() at /app/vendor/symfony/doctrine-bridge/CacheWarmer/ProxyCacheWarmer.php:60
 Symfony\Bridge\Doctrine\CacheWarmer\ProxyCacheWarmer->warmUp() at /app/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php:108
 Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate->warmUp() at /app/vendor/symfony/http-kernel/Kernel.php:545
 Symfony\Component\HttpKernel\Kernel->initializeContainer() at /app/vendor/symfony/http-kernel/Kernel.php:763
 Symfony\Component\HttpKernel\Kernel->preBoot() at /app/vendor/symfony/http-kernel/Kernel.php:126
 Symfony\Component\HttpKernel\Kernel->boot() at /app/library/Common/Application/Kernel.php:34
 App\Kernel->boot() at /app/vendor/symfony/http-kernel/Kernel.php:144
 Symfony\Component\HttpKernel\Kernel->reboot() at /app/vendor/symfony/framework-bundle/Command/CacheClearCommand.php:229
 Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand->warmup() at /app/vendor/symfony/framework-bundle/Command/CacheClearCommand.php:141
 Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand->execute() at /app/vendor/symfony/console/Command/Command.php:326
 Symfony\Component\Console\Command\Command->run() at /app/vendor/symfony/console/Application.php:1096
 Symfony\Component\Console\Application->doRunCommand() at /app/vendor/symfony/framework-bundle/Console/Application.php:126
 Symfony\Bundle\FrameworkBundle\Console\Application->doRunCommand() at /app/vendor/symfony/console/Application.php:324
 Symfony\Component\Console\Application->doRun() at /app/vendor/symfony/framework-bundle/Console/Application.php:80
 Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /app/vendor/symfony/console/Application.php:175
 Symfony\Component\Console\Application->run() at /app/vendor/symfony/runtime/Runner/Symfony/ConsoleApplicationRunner.php:49
 Symfony\Component\Runtime\Runner\Symfony\ConsoleApplicationRunner->run() at /app/vendor/autoload_runtime.php:39
 require_once() at /app/application/console:8

cache:clear [--no-warmup] [--no-optional-warmers] [--maintenance-override MAINTENANCE-OVERRIDE]

In production when it fails with enable_lazy_ghost_objects: true I don't have the full stack trace. If I use APP_DEBUG=true, I don't get the error. If it's not enough, I'll have to figure this out.

<b>Fatal error</b>:  Non-readonly class Proxies\__CG__\App\Entity\MyEntity cannot extend readonly class App\Entity\MyEntity in <b>/app/var/cache/production/doctrine/orm/Proxies/__CG__AppEntityMyEntity.php</b> on line <b>8</b><br />

@stof
Copy link
Member

stof commented Mar 22, 2024

Indeed, the new implementation of ProxyFactory does not seem to validate the compatibility of classes at proxy generation time, but only when the proxy class is used.

/cc @nicolas-grekas

@ostrolucky
Copy link
Member

I guess this is an issue in var-dumper? Shall we close here?

@nicolas-grekas
Copy link
Member

I think this is for the ORM. VarExporter's lazy objects are compatible with readonly classes. But I'm not sure the ORM takes care of them properly (either failing early or generaton readonly proxies.)

@ostrolucky ostrolucky transferred this issue from doctrine/DoctrineBundle Mar 25, 2024
@derrabus derrabus added the Bug label Mar 26, 2024
@derrabus
Copy link
Member

Can you create a reproducer for this issue?

@chrif
Copy link
Author

chrif commented Mar 28, 2024

Can you create a reproducer for this issue?

I'll make time next week for that.

@beberlei
Copy link
Member

The error "the Unable to create a proxy for a readonly class" is only triggered when lazy ghost objects is false during ProxyFactory::generateProxyClasses. There is no other way this exception inside the ProxyGenerator can be triggered, because its from the old code.

https://github.com/doctrine/doctrine2/blob/9d1a4973ae2d8ddedd6b66e958e32ebb58cdf3d6/src/Proxy/ProxyFactory.php#L227-L229

@beberlei
Copy link
Member

Some hints, A reproducer for the fatal error with lazy proxy should be a test with a readonly class, see @requires PHP 8.1 and other uses in the testsuite to restrict run for php with readonly classes. Call $this->_em->getReference() to create a proxy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants