mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
`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
170 lines
4.4 KiB
PHP
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
|