mirror of
https://github.com/php/php-src.git
synced 2026-10-28 09:46:46 +08:00
ext/reflection: Make properties readonly (#24282)
This commit is contained in:
1 parent
461eb0e8b8
commit
eef0f71aa7
7 files changed
+142
-39
No files matched your search
@@ -29,6 +29,13 @@ PHP 8.7 UPGRADE NOTES
|
||||
not present in the result set. It previously reported the condition
|
||||
through PDO::ATTR_ERRMODE and returned false.
|
||||
|
||||
- Reflection:
|
||||
. The public $name and $class properties of ReflectionClass,
|
||||
ReflectionClassConstant, ReflectionProperty, ReflectionMethod,
|
||||
ReflectionFunctionAbstract, ReflectionParameter, ReflectionExtension,
|
||||
ReflectionZendExtension, ReflectionAttribute and ReflectionConstant are
|
||||
now readonly.
|
||||
|
||||
- Session:
|
||||
. Setting session.cookie_path to a value containing one of ";\r\n", or
|
||||
session.cookie_domain to a value containing one of ",; \t\r\n\013\014",
|
||||
|
||||
@@ -22,7 +22,7 @@ interface Reflector extends Stringable
|
||||
/** @not-serializable */
|
||||
abstract class ReflectionFunctionAbstract implements Reflector
|
||||
{
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
/** @implementation-alias ReflectionClass::__clone */
|
||||
private function __clone(): void {}
|
||||
@@ -179,7 +179,7 @@ class ReflectionMethod extends ReflectionFunctionAbstract
|
||||
/** @cvalue ZEND_ACC_FINAL */
|
||||
public const int IS_FINAL = UNKNOWN;
|
||||
|
||||
public string $class;
|
||||
public readonly string $class;
|
||||
|
||||
public function __construct(object|string $objectOrMethod, ?string $method = null) {}
|
||||
|
||||
@@ -254,7 +254,7 @@ class ReflectionClass implements Reflector
|
||||
/** @cvalue ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR */
|
||||
public const int SKIP_DESTRUCTOR = UNKNOWN;
|
||||
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
private function __clone(): void {}
|
||||
|
||||
@@ -473,8 +473,8 @@ class ReflectionProperty implements Reflector
|
||||
/** @cvalue ZEND_ACC_FINAL */
|
||||
public const int IS_FINAL = UNKNOWN;
|
||||
|
||||
public string $name;
|
||||
public string $class;
|
||||
public readonly string $name;
|
||||
public readonly string $class;
|
||||
|
||||
/** @implementation-alias ReflectionClass::__clone */
|
||||
private function __clone(): void {}
|
||||
@@ -592,8 +592,8 @@ class ReflectionClassConstant implements Reflector
|
||||
/** @cvalue ZEND_ACC_FINAL */
|
||||
public const int IS_FINAL = UNKNOWN;
|
||||
|
||||
public string $name;
|
||||
public string $class;
|
||||
public readonly string $name;
|
||||
public readonly string $class;
|
||||
|
||||
/** @implementation-alias ReflectionClass::__clone */
|
||||
private function __clone(): void {}
|
||||
@@ -642,7 +642,7 @@ class ReflectionClassConstant implements Reflector
|
||||
/** @not-serializable */
|
||||
class ReflectionParameter implements Reflector
|
||||
{
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
/** @implementation-alias ReflectionClass::__clone */
|
||||
private function __clone(): void {}
|
||||
@@ -756,7 +756,7 @@ class ReflectionIntersectionType extends ReflectionType
|
||||
/** @not-serializable */
|
||||
class ReflectionExtension implements Reflector
|
||||
{
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
/** @implementation-alias ReflectionClass::__clone */
|
||||
private function __clone(): void {}
|
||||
@@ -802,7 +802,7 @@ class ReflectionExtension implements Reflector
|
||||
/** @not-serializable */
|
||||
class ReflectionZendExtension implements Reflector
|
||||
{
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
/** @implementation-alias ReflectionClass::__clone */
|
||||
private function __clone(): void {}
|
||||
@@ -846,7 +846,7 @@ class ReflectionAttribute implements Reflector
|
||||
/** @cvalue REFLECTION_ATTRIBUTE_IS_INSTANCEOF */
|
||||
public const int IS_INSTANCEOF = UNKNOWN;
|
||||
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
public function getName(): string {}
|
||||
public function inNamespace(): bool {}
|
||||
@@ -918,7 +918,7 @@ final class ReflectionFiber
|
||||
*/
|
||||
class ReflectionConstant implements Reflector
|
||||
{
|
||||
public string $name;
|
||||
public readonly string $name;
|
||||
|
||||
public function __construct(string $name) {}
|
||||
|
||||
|
||||
Generated
+13
-13
@@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit php_reflection.stub.php instead.
|
||||
* Stub hash: c4dcc2653f826c2c437065faec4bf77772ef88b1
|
||||
* Stub hash: 6191049a28b4c5fe134fc37cd8969a33d00c51de
|
||||
* Has decl header: yes */
|
||||
|
||||
#include "zend_attributes.h"
|
||||
@@ -1442,7 +1442,7 @@ static zend_class_entry *register_class_ReflectionFunctionAbstract(zend_class_en
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
@@ -1526,7 +1526,7 @@ static zend_class_entry *register_class_ReflectionMethod(zend_class_entry *class
|
||||
|
||||
zval property_class_default_value;
|
||||
ZVAL_UNDEF(&property_class_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CLASS), &property_class_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CLASS), &property_class_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
|
||||
zend_attribute *attribute_Deprecated_func_setaccessible_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setaccessible", sizeof("setaccessible") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
|
||||
@@ -1585,7 +1585,7 @@ static zend_class_entry *register_class_ReflectionClass(zend_class_entry *class_
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
@@ -1687,11 +1687,11 @@ static zend_class_entry *register_class_ReflectionProperty(zend_class_entry *cla
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
zval property_class_default_value;
|
||||
ZVAL_UNDEF(&property_class_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CLASS), &property_class_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CLASS), &property_class_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
|
||||
zend_attribute *attribute_Deprecated_func_setaccessible_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "setaccessible", sizeof("setaccessible") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
|
||||
@@ -1738,11 +1738,11 @@ static zend_class_entry *register_class_ReflectionClassConstant(zend_class_entry
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
zval property_class_default_value;
|
||||
ZVAL_UNDEF(&property_class_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CLASS), &property_class_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_CLASS), &property_class_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
@@ -1757,7 +1757,7 @@ static zend_class_entry *register_class_ReflectionParameter(zend_class_entry *cl
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
|
||||
zend_attribute *attribute_Deprecated_func_getclass_0 = zend_add_function_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "getclass", sizeof("getclass") - 1), ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
|
||||
@@ -1833,7 +1833,7 @@ static zend_class_entry *register_class_ReflectionExtension(zend_class_entry *cl
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
@@ -1848,7 +1848,7 @@ static zend_class_entry *register_class_ReflectionZendExtension(zend_class_entry
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
@@ -1879,7 +1879,7 @@ static zend_class_entry *register_class_ReflectionAttribute(zend_class_entry *cl
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
@@ -1934,7 +1934,7 @@ static zend_class_entry *register_class_ReflectionConstant(zend_class_entry *cla
|
||||
|
||||
zval property_name_default_value;
|
||||
ZVAL_UNDEF(&property_name_default_value);
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_NAME), &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
Generated
+4
-4
@@ -1,12 +1,12 @@
|
||||
/* This is a generated file, edit php_reflection.stub.php instead.
|
||||
* Stub hash: c4dcc2653f826c2c437065faec4bf77772ef88b1 */
|
||||
* Stub hash: 6191049a28b4c5fe134fc37cd8969a33d00c51de */
|
||||
|
||||
#ifndef ZEND_PHP_REFLECTION_DECL_c4dcc2653f826c2c437065faec4bf77772ef88b1_H
|
||||
#define ZEND_PHP_REFLECTION_DECL_c4dcc2653f826c2c437065faec4bf77772ef88b1_H
|
||||
#ifndef ZEND_PHP_REFLECTION_DECL_6191049a28b4c5fe134fc37cd8969a33d00c51de_H
|
||||
#define ZEND_PHP_REFLECTION_DECL_6191049a28b4c5fe134fc37cd8969a33d00c51de_H
|
||||
|
||||
typedef enum zend_enum_PropertyHookType {
|
||||
ZEND_ENUM_PropertyHookType_Get = 1,
|
||||
ZEND_ENUM_PropertyHookType_Set = 2,
|
||||
} zend_enum_PropertyHookType;
|
||||
|
||||
#endif /* ZEND_PHP_REFLECTION_DECL_c4dcc2653f826c2c437065faec4bf77772ef88b1_H */
|
||||
#endif /* ZEND_PHP_REFLECTION_DECL_6191049a28b4c5fe134fc37cd8969a33d00c51de_H */
|
||||
@@ -10,19 +10,18 @@ class Test {
|
||||
// This is unsupported and the actual behavior doesn't matter.
|
||||
// Just make sure it doesn't crash.
|
||||
$rc = new ReflectionClassConstant(Test::class, 'C');
|
||||
unset($rc->name);
|
||||
try {
|
||||
var_dump($rc->getName());
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
echo $rc, "\n";
|
||||
unset($rc->name);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
var_dump($rc->getName());
|
||||
|
||||
echo $rc, "\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property ReflectionClassConstant::$name must not be accessed before initialization
|
||||
Typed property ReflectionClassConstant::$name must not be accessed before initialization
|
||||
Cannot unset readonly property ReflectionClassConstant::$name
|
||||
string(1) "C"
|
||||
Constant [ public int C ] { 1 }
|
||||
@@ -27,7 +27,7 @@ Class [ <internal:Reflection> class ReflectionClass implements Stringable, Refle
|
||||
}
|
||||
|
||||
- Properties [1] {
|
||||
Property [ public string $name ]
|
||||
Property [ public protected(set) readonly string $name ]
|
||||
}
|
||||
|
||||
- Methods [64] {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
--TEST--
|
||||
GH-24147: Reflection $name and $class properties cannot be modified
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class B {
|
||||
public string $x;
|
||||
}
|
||||
|
||||
function byRef(&$x) { $x = 'Z'; }
|
||||
|
||||
$tests = [
|
||||
'compound assignment' => function ($r) { $r->class .= 'Z'; },
|
||||
'reference' => function ($r) { $ref = &$r->name; $ref = 'Z'; },
|
||||
'string offset' => function ($r) { $r->name[0] = 'Z'; },
|
||||
'by-ref argument' => function ($r) { byRef($r->class); },
|
||||
'dynamic by-ref argument' => function ($r) { $fn = 'byRef'; $fn($r->class); },
|
||||
'foreach by reference' => function ($r) { foreach ($r as &$v) { $v = 'Z'; } },
|
||||
'unset' => function ($r) { unset($r->name); },
|
||||
'setValue' => function ($r) { (new ReflectionProperty($r, 'name'))->setValue($r, 'Z'); },
|
||||
'setRawValue' => function ($r) { (new ReflectionProperty($r, 'name'))->setRawValue($r, 'Z'); },
|
||||
];
|
||||
|
||||
foreach ($tests as $label => $test) {
|
||||
$r = new ReflectionProperty('B', 'x');
|
||||
try {
|
||||
$test($r);
|
||||
echo "$label: no error\n";
|
||||
} catch (Throwable $e) {
|
||||
echo "$label: ", $e::class, ": ", $e->getMessage(), "\n";
|
||||
}
|
||||
if (!isset($r->name, $r->class) || $r->name !== $r->getName() || $r->class !== $r->getDeclaringClass()->name) {
|
||||
echo "$label: properties diverged from getters\n";
|
||||
}
|
||||
}
|
||||
|
||||
class WriteBeforeConstruct extends ReflectionClass {
|
||||
public function __construct() {
|
||||
$this->name = 'Z';
|
||||
}
|
||||
}
|
||||
|
||||
class UnsetAfterConstruct extends ReflectionClass {
|
||||
public function __construct() {
|
||||
parent::__construct('B');
|
||||
unset($this->name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['WriteBeforeConstruct', 'UnsetAfterConstruct'] as $class) {
|
||||
try {
|
||||
new $class();
|
||||
echo "$class: no error\n";
|
||||
} catch (Throwable $e) {
|
||||
echo "$class: ", $e::class, ": ", $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Unsetting the uninitialized property in a subclass to route reads through __get() stays possible
|
||||
class UnsetBeforeConstruct extends ReflectionClass {
|
||||
public function __construct() {
|
||||
unset($this->name);
|
||||
}
|
||||
|
||||
public function __get($name) {
|
||||
return "magic $name";
|
||||
}
|
||||
}
|
||||
|
||||
var_dump((new UnsetBeforeConstruct())->name);
|
||||
|
||||
foreach (['setValue', 'setRawValue'] as $method) {
|
||||
$r = (new ReflectionClass('ReflectionClass'))->newInstanceWithoutConstructor();
|
||||
try {
|
||||
(new ReflectionProperty($r, 'name'))->$method($r, 'Z');
|
||||
echo "uninitialized $method: no error\n";
|
||||
} catch (Throwable $e) {
|
||||
echo "uninitialized $method: ", $e::class, ": ", $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
compound assignment: ReflectionException: Cannot set read-only property ReflectionProperty::$class
|
||||
reference: Error: Cannot indirectly modify readonly property ReflectionProperty::$name
|
||||
string offset: Error: Cannot indirectly modify readonly property ReflectionProperty::$name
|
||||
by-ref argument: Error: Cannot indirectly modify readonly property ReflectionProperty::$class
|
||||
dynamic by-ref argument: Error: Cannot indirectly modify readonly property ReflectionProperty::$class
|
||||
foreach by reference: Error: Cannot acquire reference to readonly property ReflectionProperty::$name
|
||||
unset: Error: Cannot unset readonly property ReflectionProperty::$name
|
||||
setValue: ReflectionException: Cannot set read-only property ReflectionProperty::$name
|
||||
setRawValue: ReflectionException: Cannot set read-only property ReflectionProperty::$name
|
||||
WriteBeforeConstruct: ReflectionException: Cannot set read-only property WriteBeforeConstruct::$name
|
||||
UnsetAfterConstruct: Error: Cannot unset readonly property ReflectionClass::$name
|
||||
string(10) "magic name"
|
||||
uninitialized setValue: ReflectionException: Cannot set read-only property ReflectionClass::$name
|
||||
uninitialized setRawValue: ReflectionException: Cannot set read-only property ReflectionClass::$name
|
||||
Reference in new issue
Block a user