1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00
Files
archived-php-src/ext/reflection/tests/property_hooks/gh17713.phpt
Arnaud Le Blanc 24b191a4de Fix ReflectionProperty::getRawValue() and related methods for properties overridden with hooks
`new Reflectionproperty($scope, $propName)` keeps a reference to the
zend_property_info of $propName declared in $scope. In getRawValue() and
related methods, we use this reference to check whether the property is hooked.

Calling `new ReflectionProperty($scope, $propName)->getRawValue($object)` is
equivalent to the expression $object->$propName from scope $scope (except that
it bypasses hooks), and thus may access an overridden property (unless the
original is private). This property may have hooks and different flags.

Here I fetch the effective property info before checking for hooks and
property flags.

Fixes GH-17713
Closes GH-17714
2025-02-07 10:49:02 +01:00

170 lines
4.4 KiB
PHP

--TEST--
GH-17713: getRawValue(), setRawValue(), setRawValueWithoutLazyInitialization() may call hooks
--FILE--
<?php
#[AllowDynamicProperties]
class Base {
public $publicProp = 'Base::$publicProp';
private $privateProp = 'Base::$privateProp';
public $hookedProp {
get {
echo __METHOD__, "\n";
return $this->hookedProp;
}
set {
echo __METHOD__, "\n";
$this->hookedProp = $value;
}
}
public $virtualProp {
get {
echo __METHOD__, "\n";
return __METHOD__;
}
set {
echo __METHOD__, "\n";
}
}
}
class Test extends Base {
public $publicProp {
get {
echo __FUNCTION__, "\n";
return $this->publicProp;
}
set {
echo __FUNCTION__, "\n";
$this->publicProp = $value;
}
}
private $privateProp = 'Test::$privateProp' {
get {
echo __FUNCTION__, "\n";
return $this->privateProp;
}
set {
echo __FUNCTION__, "\n";
$this->privateProp = $value;
}
}
public $dynamicProp {
get {
echo __FUNCTION__, "\n";
return $this->dynamicProp;
}
set {
echo __FUNCTION__, "\n";
$this->dynamicProp = $value;
}
}
public $hookedProp {
get {
echo __METHOD__, "\n";
return $this->hookedProp;
}
set {
echo __METHOD__, "\n";
$this->hookedProp = $value;
}
}
public $virtualProp {
get {
echo __METHOD__, "\n";
return $this->virtualProp;
}
set {
echo __METHOD__, "\n";
$this->virtualProp = $value;
}
}
public static $changedProp = 'Test::$changedProp';
}
function test($scope, $class, $prop) {
printf(
"# Accessing %s->%s from scope %s\n",
$class,
$prop,
is_object($scope) ? get_class($scope) : $scope,
);
$propertyReflection = new ReflectionProperty($scope, $prop);
$object = new $class();
try {
$propertyReflection->setRawValue($object, 42);
} catch (Throwable $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump($propertyReflection->getRawValue($object));
} catch (Throwable $e) {
echo $e->getMessage(), "\n";
}
try {
$propertyReflection->setRawValueWithoutLazyInitialization($object, 43);
} catch (Throwable $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump($propertyReflection->getRawValue($object));
} catch (Throwable $e) {
echo $e->getMessage(), "\n";
}
if ($prop === 'privateProp') {
printf(
"# Accessing %s->%s again from scope %s\n",
$class,
$prop,
$class,
);
$propertyReflection = new ReflectionProperty($class, $prop);
var_dump($propertyReflection->getRawValue($object));
}
}
test(Base::class, Test::class, 'publicProp');
test(Base::class, Test::class, 'privateProp');
test(Base::class, Test::class, 'hookedProp');
test(Base::class, Test::class, 'virtualProp');
test(Base::class, Base::class, 'virtualProp');
$scope = new Base();
$scope->dynamicProp = 'Base::$dynamicProp';
$scope->changedProp = 'Base::$dynamicProp';
test($scope, Test::class, 'dynamicProp');
test($scope, Test::class, 'changedProp');
?>
--EXPECT--
# Accessing Test->publicProp from scope Base
int(42)
int(43)
# Accessing Test->privateProp from scope Base
int(42)
int(43)
# Accessing Test->privateProp again from scope Test
string(18) "Test::$privateProp"
# Accessing Test->hookedProp from scope Base
int(42)
int(43)
# Accessing Test->virtualProp from scope Base
int(42)
int(43)
# Accessing Base->virtualProp from scope Base
Must not write to virtual property Base::$virtualProp
Must not read from virtual property Base::$virtualProp
Can not use setRawValueWithoutLazyInitialization on virtual property Base::$virtualProp
Must not read from virtual property Base::$virtualProp
# Accessing Test->dynamicProp from scope Base
int(42)
int(43)
# Accessing Test->changedProp from scope Base
May not use setRawValue on static properties
May not use getRawValue on static properties
Can not use setRawValueWithoutLazyInitialization on static property Test::$changedProp
May not use getRawValue on static properties