Skip to content

Expose zend_reflection_property_set_raw_value, zend_reflection_property_set_raw_value_without_lazy_initialization#21763

Open
arnaud-lb wants to merge 4 commits intophp:masterfrom
arnaud-lb:expose-refl-set-raw-value
Open

Expose zend_reflection_property_set_raw_value, zend_reflection_property_set_raw_value_without_lazy_initialization#21763
arnaud-lb wants to merge 4 commits intophp:masterfrom
arnaud-lb:expose-refl-set-raw-value

Conversation

@arnaud-lb
Copy link
Copy Markdown
Member

@arnaud-lb arnaud-lb commented Apr 15, 2026

This exposes the functionality of ReflectionProperty::setRawValue() and ReflectionProperty::setRawValueWithoutLazyInitialiation() to C extensions.

Test failure unrelated.

…ty_set_raw_value_without_lazy_initialization
@arnaud-lb arnaud-lb changed the title [wip] Expose zend_reflection_property_set_raw_value, zend_reflection_property_set_raw_value_without_lazy_initialization Expose zend_reflection_property_set_raw_value, zend_reflection_property_set_raw_value_without_lazy_initialization Apr 15, 2026
@arnaud-lb arnaud-lb marked this pull request as ready for review April 15, 2026 10:18
nicolas-grekas added a commit to symfony/php-ext-deepclone that referenced this pull request Apr 15, 2026
…lable

PHP 8.6 exposes zend_reflection_property_set_raw_value{,_without_lazy_initialization}
as PHPAPI (php/php-src#21763), moving the lazy-prop
bookkeeping into ext/reflection. Use the PHPAPI direct on 8.6+ and keep the
userland ReflectionProperty round-trip as a fallback for 8.4 / 8.5.

Depends on php/php-src#21763 landing; holding here until the patch is merged
and the target PHP version is known.
nicolas-grekas added a commit to symfony/php-ext-deepclone that referenced this pull request Apr 15, 2026
…lable

PHP 8.6 exposes zend_reflection_property_set_raw_value{,_without_lazy_initialization}
as PHPAPI (php/php-src#21763), moving the lazy-prop
bookkeeping into ext/reflection. Use the PHPAPI direct on 8.6+ and keep the
userland ReflectionProperty round-trip as a fallback for 8.4 / 8.5.

Depends on php/php-src#21763 landing; holding here until the patch is merged
and the target PHP version is known.
@DanielEScherzer
Copy link
Copy Markdown
Member

Not sure the current interface is the best to expose, e.g. the void *cache_slot[3] parameters are not really documented

What is the issue with having other extensions just call the reflection methods via the normal mechanism for calling class methods?

@nicolas-grekas
Copy link
Copy Markdown
Contributor

What is the issue with having other extensions just call the reflection methods via the normal mechanism for calling class methods

CPU overhead!

@arnaud-lb
Copy link
Copy Markdown
Member Author

@DanielEScherzer I've documented the cache_slot parameter in the comment above the declaration of zend_reflection_property_set_raw_value. It is not uncommon to find such cache_slot parameter in the code base, on functions related to property accesses.

If you prefer, I can change the API to something like this:

typedef reflection_object zend_reflection_property;

PHPAPI zend_reflection_property *zend_reflection_property_create(zend_class_entry *ce, zend_string *name);
PHPAPI void zend_reflection_property_set_raw_value(zend_reflection_property *refl_prop, zend_object *object, zval *value);

What is the issue with having other extensions just call the reflection methods via the normal mechanism for calling class methods?

In addition to being faster, this also provides a nicer API. Instantiating objects and calling methods is not straightforward in C.

nicolas-grekas added a commit to symfony/php-ext-deepclone that referenced this pull request Apr 16, 2026
…lable

PHP 8.6 exposes zend_reflection_property_set_raw_value{,_without_lazy_initialization}
as PHPAPI (php/php-src#21763), moving the lazy-prop
bookkeeping into ext/reflection. Use the PHPAPI direct on 8.6+ and keep the
userland ReflectionProperty round-trip as a fallback for 8.4 / 8.5.

Depends on php/php-src#21763 landing; holding here until the patch is merged
and the target PHP version is known.
@Girgias
Copy link
Copy Markdown
Member

Girgias commented Apr 16, 2026

The other thing to mention is calling a "PHP" function/method from C AFAIK requires setting up new VM stacks compared to "just" running in a loop. The other thing is that for global functions those can be disabled by an INI setting. (For classes and class methods that's no longer an issue since 8.5 as the disable_class INI setting got removed)

Comment thread ext/reflection/php_reflection.h Outdated
* cache_slot can be used again with the same 'unmangled_name' and 'scope'.
* Must be zeroed on first use. May be NULL. */
PHPAPI void zend_reflection_property_set_raw_value(
const zend_property_info *prop, zend_string *unmangled_name,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a bit more documentation? I assume

  • zend_object *object is what object we are setting a property on
  • zend_property_info *prop is the property to set
  • zval *value is the value to set

What is the unmangled_name here - if it is the same as the property name, why is a separate parameter needed? The unmangled name could already be retrieved from zend_get_unmangled_property_name(prop-> name)

What does the scope represent - since this is reflection, it doesn't matter what the calling scope is, visibility gets bypassed. Is it the class of the object? Then is it already available as object->ce, so why is a separate parameter needed

Internally reflection might pass the unmangled name and the class entry separately because they are already available and for performance, but that shouldn't be required from external callers

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internally we use intern->ce as the scope, but we don't have intern here. This is why we have to pass it separately. intern->ce can be different than object->ce and prop->ce:

  • intern->ce: The class passed as first argument to new ReflectionProperty(), that we use as scope
  • prop->ce: The class on which the property is declared (may be a super class)

I agree that the unmangled_name parameter could be removed, but at the same time it's useful purely for performance reasons, since a part of the purpose of this API is performance. The same is true about the prop and cache_slot parameters.

The proposed API is low level, but it still abstracts away a lot of complexity.

Comment thread ext/reflection/php_reflection.c Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants