-
Notifications
You must be signed in to change notification settings - Fork 18
Add reflection typed no default property class #24
Add reflection typed no default property class #24
Conversation
alcaeus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic LGTM, not sure about changes to the PHPStan build stage on travis-ci.
.travis.yml
Outdated
|
|
||
| - stage: Lint | ||
| script: vendor/bin/phpstan analyse -l 3 -c phpstan.neon lib tests | ||
| before_script: if grep -si 7.4 <<< "$TRAVIS_PHP_VERSION"; then export TESTS_PATH="tests/Doctrine/Tests tests/Doctrine/Tests_PHP74"; else export TESTS_PATH=tests/Doctrine/Tests; fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to avoid this conditional? Does PHPStan stumble over these test files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, now as I think of it, there is a better way to solve this.
The problem is, that the PHPStan version currently used depends on an older version of nikic/php-parser that does not know the new php 7.4 tokens.
So another solution is to update PHPStan with it's dependecies.
I reverted the changes to the Lint stage of the CI config and updated the packages.
Also fixed two issues that the new version detected.
|
@alcaeus ok, just updated PHPStan myself, I'll revert those changes then? |
|
Yep, no further work necessary on phpstan for now, I'll figure this out when merging. |
| */ | ||
| public function getValue($object = null) | ||
| { | ||
| $name = $this->getName(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should most certainly be cached locally (in the instance). Alternatively, using $this->name in the expression below would work too.
Yes, it's horrible, but this is really performance sensitive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should most certainly be cached locally (in the instance). Alternatively, using
$this->namein the expression below would work too.Yes, it's horrible, but this is really performance sensitive
But what about \Doctrine\Common\Reflection\RuntimePublicReflectionProperty? It is using the same mechanism and a public property on an entity is still a much more common scenario than a typed property, caching should be implemented there too. Maybe a separate issue for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And looking at the tests, adding caching would break the current behavior.
For example in
reflection/tests/Doctrine/Tests/Common/Reflection/RuntimePublicReflectionPropertyTest.php
Lines 13 to 24 in 7a2c95a
| public function testGetValue() : void | |
| { | |
| $object = new RuntimePublicReflectionPropertyTestClass(); | |
| $reflProperty = new RuntimePublicReflectionProperty(RuntimePublicReflectionPropertyTestClass::class, 'test'); | |
| self::assertSame('testValue', $reflProperty->getValue($object)); | |
| unset($object->test); | |
| self::assertNull($reflProperty->getValue($object)); | |
| } |
The RuntimePublicReflectionProperty would not follow the changes to the reflected object's properties, if it was caching the value on first access to the property.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also looking at
The class introduced in this PR will be returned from this method too, and if we add caching only to this new class, it will still break the behavior of the getAccessibleProperty method, as the reflection property classes returned by it would not cache and do track the reflected object changes for some properties and the opposite for other properties.
| { | ||
| $name = $this->getName(); | ||
|
|
||
| return isset($object->$name) ? parent::getValue($object) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an isset($object->$name) will initialize that property starting from ORM 3, because ProxyManager intercepts isset() calls via __isset().
Instead, ReflectionProperty#isInitialized() should be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yes: more performance impact :-(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do this, but again it looks to me as a separate issue, this behavior was copied from another class in the package \Doctrine\Common\Reflection\RuntimePublicReflectionProperty, it has issues then too.
Thanks for the review!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, accessing typed properties via isset() is not side-effect-free, and will break on anything declaring __isset (not just because of ProxyManager)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I understand the problem now, will fix it in the new class, it will also make it's purpose more explicit. Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
reflection/lib/Doctrine/Common/Reflection/TypedNoDefaultReflectionProperty.php
Lines 19 to 22 in f45415e
| public function getValue($object = null) | |
| { | |
| return $object !== null && $this->isInitialized($object) ? parent::getValue($object) : null; | |
| } |
… in php 7.4 syntax doctrine#23
f45415e to
9acbb8c
Compare
Implementation for issue #23
See discussion in doctrine/orm#7857
As suggested by @beberlei, the
\Doctrine\Common\Reflection\TypedNoDefaultReflectionPropertyclass was introduced.It will be returned in
doctrine/persistencepackage class RuntimeReflectionService::getAccessibleProperty if the property is typed and has no default value. Something like this:Also updated phpunit config as suggested in the discussion in the same issue #23.
This allows skipping tests containing php 7.4 specific syntax on builds with lesser php versions.
Also updated
travis-ci.ymlLint job to ignore such tests by phpstan analysis, if the php version is less than 7.4