Skip to content

Implement ReflectionProperty::is{Readable,Writable}()#16209

Draft
iluuu1994 wants to merge 1 commit intophp:masterfrom
iluuu1994:reflection-property-isReadable-isWritable
Draft

Implement ReflectionProperty::is{Readable,Writable}()#16209
iluuu1994 wants to merge 1 commit intophp:masterfrom
iluuu1994:reflection-property-isReadable-isWritable

Conversation

@iluuu1994
Copy link
Member

@iluuu1994 iluuu1994 commented Oct 3, 2024

@iluuu1994 iluuu1994 force-pushed the reflection-property-isReadable-isWritable branch from cab3331 to 325b8fa Compare February 5, 2026 13:55
}
} else if (obj && (!prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET])) {
zval *prop_val = OBJ_PROP(obj, prop->offset);
if (Z_TYPE_P(prop_val) == IS_UNDEF) {
Copy link
Member

Choose a reason for hiding this comment

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

The object may need to be initialized if the prop is undef:

Suggested change
if (Z_TYPE_P(prop_val) == IS_UNDEF) {
if (Z_TYPE_P(prop_val) == IS_UNDEF) {
if (zend_lazy_object_must_init(obj) && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)) {
if (!(obj = zend_lazy_object_init(obj)) {
RETURN_THROW();
}
prop_val = OBJ_PROP(obj, prop->offset);

Test case:

class A {
    public int $prop;
    public function __construct() {
        $this->prop = 1;
    }
}

$rc = new ReflectionClass(A::class);
$obj = $rc->newLazyProxy(fn() => new A());

$rp = new ReflectionProperty(A::class, 'prop');
var_dump($rp->isReadable(null, $obj)); // should be true

}
RETURN_TRUE;
}
RETURN_FALSE;
Copy link
Member

Choose a reason for hiding this comment

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

At this point, if the object is lazy it may need to be initialized, and obj->properties must be checked again:

Suggested change
RETURN_FALSE;
if (zend_lazy_object_must_init(obj)) {
obj = zend_lazy_object_init(obj);
if (!obj) {
RETURN_THROWS();
}
if (obj->properties && zend_hash_find_ptr(obj->properties, ref->unmangled_name)) {
RETURN_TRUE;
}
}
RETURN_FALSE;

The initialized object will have neither __get or __isset since the uninitialized one didn't, so we don't need to check these again.

Test case:

#[AllowDynamicProperties]
class A {
    public function __construct() {
        $this->prop = 1;
    }
}

$rc = new ReflectionClass(A::class);
$obj = $rc->newLazyProxy(fn() => new A());

$rp = new ReflectionProperty(new A, 'prop');
var_dump($rp->isReadable(null, $obj)); // should be true

}
} else if (obj && (prop->flags & ZEND_ACC_READONLY)) {
zval *prop_val = OBJ_PROP(obj, prop->offset);
if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) {
Copy link
Member

Choose a reason for hiding this comment

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

Ditto

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.

Offer reflection methods to test property read-/writability ReflectionClass can't detect readonly properties for mysqli

5 participants