cycle/orm

Typed property must not be accessed before initialization

Closed this issue Β· 18 comments

Try to add php 7.4 property typing to any of the Entity examples from docs and persist it with db, you will get that exception.

For the reference see also doctrine issue and corresponding PR. As far as I see the issue is partially resolved, see this one.

Not sure whether the issue in Doctrine was only for id (i.e. primary keys), but here we have the issue for any typed field in Entity.

@alexndr-novikov can you comment? I know we are widely using 7.4, not sure is it the same issue we solved earlier or something new.

@armpogart thank you for the report.

@wolfy-j Actually the issue is not directly in this repo, but the dependency you use. You run following code which itself uses Zend Hydrator and there the following line raises the issue.

It's due to the fact that php 7.4 property value can't be accessed even with reflection if it is not initialized, but the fix is rather easy as ReflectionProperty class has new methods for that and I see better fix than Doctrine one.

The problem is I don't see how to apply the fix to this repo as it is in direct dependency. Do I need to report there?
And the second problem is the fix will raise minimum php requirements to 7.4, or can we just do some method_exists check to see if we are on php 7.4 and only do the checks there?

Yes, you might need to report in Zend/Hydrator. Also, check ocramius/generated-hydrator, it is viable alternative (and it works faster). I think PHP7.4 issues were fixed by @Ocramius

This is the example https://github.com/adrianmiu/forked-php-orm-benchmark/blob/master/cycleorm/CycleOrmTestSuiteWithGeneratedMapper.php

Since Zend is kinda dead we might need to switch to Laminas on a later date. In general, hydration/extraction code has nothing to do with the rest of ORM so it's very easy to change the implementation.

Issue on ocramius/generated-hydrator for reference. Will open an issue on laminas/laminas-hydrator (since zend is already depracated and repo is archived) and update here.

I really hope it's not going to end with our own hydration/extraction implementation (hi @vvval). So far it seems that there needs a way to quickly detect if the property has been initialized. I wonder if isset is working.

@wolfy-j Are you following discussion on both repos where I referenced this issue?
Do you agree with the statement that it is implementation problem? (there are comments on that on both cases, though I don't agree with them).

Not really, if I want to get values from the entity - I have to get values from the entity. If they won't fix it on the library level we will have to write our own hydration/extractor with extra check if the property has been initialized and skip its extraction (orm will be fine with that). But I can't express how much I do not want to write another hydration library.

Not only zend-hydrator fails to work with typed properties, its ReflectionHydrator somehow ignores the default constructor (so there's no way to safely bypass the exception without making all of the properties nullable).

It's normal practice to bypass the constructor invocation in Hydration (same as Doctrine).

I'm planning to seriously take a look at this issue during following few weeks.

Released https://github.com/Ocramius/GeneratedHydrator/releases/tag/3.1.0, if you wanna give it a spin.

It still uses an old zendframework/zend-hydrator version for now. I would suggest sending upstream patches to laminas-hydrator meanwhile.

Well, according to Marco comment Ocramius/GeneratedHydrator#124 this can’t be fixed as there design bug.

I can only propose not to declare auto incremental ids in entities at all or stick to uuid or make them nullable.

Yes: of your identifier doesn't exist until after persistence, it is to be null, and the entity mutable.

Otherwise you just left a landmine there, for somebody else to uncover.

EDIT: s/nullable/mutable

Going to add it to PHP 7.4 specific documentation article. Thank you, Marco.

@wolfy-j If I understood correctly, you agree that if not nullable typed property is not initialized that's a design issue. While I agree on the case of identifier (PK) can be nullable until after persistence it is set. What about FK keys which can be also null after persistence (when nulls are allowed), how they would be differentiated?

So also my comment on laminas issue tracker.

If the association is nullable, why isn't it mapped as such in the entity?

@Ocramius Ok, for making an example simpler.
Suppose we have some content field in db that can be null. When using typed properties it would be logical to have it null by default (same goes for any FK that can be null), but how we will differentiate whether it is null by default or it is set to null on purpose (after ORM read operation)?

Now, I'm little bit lost. I need to think more about this...

Why there should be a difference? In theory, your code should know nothing about ORM (since we are not talking about AR) so your code should operate relying only on itself.

It doesn't even need to be null by default: if an association is nullable, it can be hydrated as null when the association isn't set.