orm: Problem with Proxies on PHP 7.4.2 with typed properties
(I’m sorry if this is wrong place to report that issue, please transfer me to the proper one if this is the case)
We encountered this problem on the Behat testing phase with generated entity proxies. There is fatal error:
Typed property Proxies_CG_\App\Entity\EntityName:😒 must not be accessed before initialization (in __sleep)
This happened when we upgraded PHP to 7.4.2 (everything was ok on 7.4.1). We used typed properties before the upgrade as well. After playing with the entity for a bit we discovered that now every typed object property must be initialized immediately (previously they were initialized in the constructor) like:
private ?DateTimeInterface $property = null;
public function __construct()
{
$this->property = new DateTime();
}
because this doesn’t work anymore:
private DateTimeInterface $property;
public function __construct()
{
$this->property = new DateTime();
}
This is was already reported in Symfony https://github.com/symfony/symfony/issues/35574 but closed.
Installed Doctrine package | Version |
---|---|
doctrine/annotations | v1.8.0 |
doctrine/cache | 1.10.0 |
doctrine/collections | 1.6.4 |
doctrine/common | 2.12.0 |
doctrine/data-fixtures | 1.4.2 |
doctrine/dbal | v2.10.1 |
doctrine/doctrine-bundle | 2.0.7 |
doctrine/doctrine-migrations-bundle | 2.1.2 |
doctrine/event-manager | 1.1.0 |
doctrine/inflector | 1.3.1 |
doctrine/instantiator | 1.3.0 |
doctrine/lexer | 1.2.0 |
doctrine/migrations | 2.2.1 |
doctrine/mongodb-odm | 2.0.5 |
doctrine/mongodb-odm-bundle | 4.1.0 |
doctrine/orm | v2.7.1 |
doctrine/persistence | 1.3.6 |
doctrine/reflection | v1.1.0 |
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 25 (10 by maintainers)
Commits related to this issue
- bug #36332 [Serializer] Fix unitialized properties (from PHP 7.4.2) when serializing context for the cache key (alanpoulain) This PR was squashed before being merged into the 3.4 branch. Discussion ... — committed to symfony/symfony by fabpot 4 years ago
- bug #36340 [Serializer] Fix configuration of the cache key (dunglas) This PR was squashed before being merged into the 4.4 branch. Discussion ---------- [Serializer] Fix configuration of the cache ... — committed to symfony/symfony by fabpot 4 years ago
I was wondering why doctrine/common’s ProxyLogicTypedPropertiesTest passes when there is at least one uninitialized typed property in tested object and its proxy is serialized in the test.
Turns out that every uninitialized field is actually being initialized in the setup phase of that test which is why this issue I’ve reported goes undetected. You can easily verify it by adding additional
public string $test;
inLazyLoadableObjectWithTypedProperties
and runningDoctrine\Tests\Common\Proxy\ProxyLogicTypedPropertiesTest::testNotInitializedProxyUnserialization
. The result is thenAnd please don’t get me wrong, I know this test is to verify lazy loading and properties should be initialized but still I think it makes my point.
Will it be enough for reproducible test case @beberlei ? Once again sorry for sounding harsh before. You guys are doing great job, and I really appreciate it.
Sorry for the late reply @beberlei. Thanks to @alanpoulain it’s gonna be fixed in Symfony: https://github.com/symfony/symfony/pull/36332
My PR hasn’t been merged in Symfony. Has you can see in the comments, not everybody agree that it’s the proper fix.
@bizley
This example given in your first comment:
will delay the issue presenting itself, but as described in the comment by @EmanuelOster using
PUT
andPATCH
will make it show up again.Consequently, even though it was tongue-in-cheek, this won’t actually work:
Do not use
private
properties in entities: Projects/ORM/Documentation/Architecture#Serializing entities. Doctrine does not have full support for that.Ok, now I understand why it’s happening in PHP 7.4.2 - https://bugs.php.net/bug.php?id=79002
Turns out
serialize
with__sleep
was behaving incorrectly before and allowing objects with uninitialized properties to be serialized (unserialize()
was throwing TypeError then) and it was fixed in 7.4.2 (https://www.php.net/ChangeLog-7.php).Right now I see 3 possible solutions:
Error
inAbstractObjectNormalizer::getCacheKey
(like @EmanuelOster suggested) and returnfalse
there since object with uninitialized property can not be serialized anyway).ReflectionProperty::isInitialized
).