6.0 - Entity props with hooks#19381
Conversation
Update tests
It ensures EntityTrait::$restrictProperties stays in sync with the trait's properties
EntityInterface::has() treats properties set to null different than uninitialized properties
This allows using isset() instead of in_array()
- Convert $originalFields to keyed map for O(1) isset() lookups - Simplify setOriginalField() using array_combine and += merge - Swap branches in setHidden/setVirtual/setDirty for common path first - Use truthy checks instead of === true/false comparisons - Hoist $asOriginal in patch() before loop - Pass $this->propertyFields directly in clean() - Improve patch() phpdoc param type
…erty hooks Implement Phase 2 of the concrete entity properties RFC: - Add per-class static $reflectionCache for ReflectionProperty instances - Add getReflectionProperty() for cached reflection lookups - Add setRawValue()/getRawValue() to bypass PHP 8.4 property hooks - Update propertyExists() to use reflection cache - Update patch() to use setRawValue() when setter is false (ORM hydration) - Update isModified() to use getRawValue() for dirty checking - Update getOriginalValues(), hasErrors(), getErrors(), __debugInfo() to use getRawValue() for consistent raw access - Add clearReflectionCache() for testing convenience - Add reflectionCache to restricted properties list
- Check dynamicFields before reflection in getRequiredOrFail(), isModified(), setRawValue(), getRawValue() - Hoist $ref resolution in patch() loop to eliminate redundant propertyExists()/getRawValue()/setRawValue() calls per field - Add isset() fast path in getReflectionProperty() for cache hits - Convert $originalFields from list to keyed map for O(1) isset() lookups instead of O(n) in_array() in isOriginalField()
Verify that restricted (infrastructure) property names cannot be accessed, set, or unset through entity public API methods, and that setting/unsetting fields named after restricted properties stores them as dynamic fields without corrupting internal state.
|
Are you planning to deprecate the |
No I am not. This is not a property which user needs to use directly, so I don't see any need to deprecate or provide a rector. |
|
The docblock "problem" can for sure be easily automated/fixed with dereuromarks ide-helper. But how would a entity look like for fields which are already present in the EntityTrait? I can see that the trait handles it properly via the |
|
What happens when we set properties in a Entity method? |
If you have fields names which overlap the properties names of EntityTrait then they can only be implemented as dynamic fields with docblock.
Setting a property within the entity as |
|
Based on that I'm planning to work on a PHPStan Rule to detect the use of |
Refs #19380, enhanced version of #19313. The key difference between the 2 PRs is the use of reflection to support use of hooked properties with asymmetric visibility.
This implementation allows having clean entity classes like:
Advantages
No docblock required for entity properties.Docblock would not be required for "get" since it's public but would be for using assignment like$entity->foo = 'val';since thesethook is protected.__get(). Writing a value still goes through magic__set()to ensure features like dirty tracking etc. continue to work.Properties can also be declared without asymmetric visibility as
protected string $foo.Why is reflection needed
_setFoo()) when the entity is constructed (from the data fetched from db). PHP's set hook can be skipped only through reflection.hasValue()differentiates between "field not set" vs "value set to null", which is not possible for properties without usingReflectedProperty::isInitialized().What about the overhead of reflection
PhpEnginecache engine, which can be opcache optimized. (This is yet to be added). This would make any overhead added by use of reflection negligible and the benefits achieved greatly out weight it.P.S. Full backwards compatibility is maintained with 5.x, so the new usage with properties become opt-in for those upgrading.