有没有办法使用反射类设置私有/受保护的静态属性?

Posted

技术标签:

【中文标题】有没有办法使用反射类设置私有/受保护的静态属性?【英文标题】:Is there any way to set a private/protected static property using reflection classes? 【发布时间】:2011-09-20 20:53:38 【问题描述】:

我正在尝试为类的静态属性执行备份/恢复功能。我可以使用反射对象getStaticProperties() 方法获取所有静态属性及其值的列表。这将获取 privatepublic static 属性及其值。

问题是我在尝试使用反射对象setStaticPropertyValue($key, $value) 方法恢复属性时似乎没有得到相同的结果。 privateprotected 变量对于此方法不可见,因为它们对于 getStaticProperties() 可见。似乎不一致。

有没有办法使用反射类或其他任何方式设置私有/受保护的静态属性?

尝试过

class Foo 
    static public $test1 = 1;
    static protected $test2 = 2;

    public function test () 
        echo self::$test1 . '<br>';
        echo self::$test2 . '<br><br>';
    

    public function change () 
        self::$test1 = 3;
        self::$test2 = 4;
    


$test = new foo();
$test->test();

// Backup
$test2 = new ReflectionObject($test);
$backup = $test2->getStaticProperties();

$test->change();

// Restore
foreach ($backup as $key => $value) 
    $property = $test2->getProperty($key);
    $property->setAccessible(true);
    $test2->setStaticPropertyValue($key, $value);


$test->test();

【问题讨论】:

【参考方案1】:

为了访问类的私有/受保护属性,我们可能需要首先使用反射设置该类的可访问性。试试下面的代码:

$obj         = new ClassName();
$refObject   = new ReflectionObject( $obj );
$refProperty = $refObject->getProperty( 'property' );
$refProperty->setAccessible( true );
$refProperty->setValue(null, 'new value');

【讨论】:

ReflectionProperty::setValue() expects parameter 1 to be object, null given,你的回答建议我应该提供一个 null 但 php 抱怨:( 请注意,-&gt;setValue(null, '...') 仅在设置的属性是 static 属性时才允许使用。如果你试图修改一个对象的属性,你需要提供一个真实的实例,否则 PHP 会报错ReflectionProperty::setValue() expects parameter 1 to be object, null given【参考方案2】:

用于访问类的私有/受保护属性,使用反射,无需ReflectionObject 实例:

对于静态属性:

<?php
$reflection = new \ReflectionProperty('ClassName', 'propertyName');
$reflection->setAccessible(true);
$reflection->setValue(null, 'new property value');

对于非静态属性:

<?php
$instance = new SomeClassName();
$reflection = new \ReflectionProperty(get_class($instance), 'propertyName');
$reflection->setAccessible(true);
$reflection->setValue($instance, 'new property value');

【讨论】:

ReflectionProperty::setValue() expects parameter 1 to be object, null given 你的回答和@Shamee's 有同样的问题 这在 PHP 5.6 中当然可以工作,并且文档表明这始终是它应该工作的方式(参见:php.net/manual/en/reflectionproperty.setvalue.php),所以不确定为什么它不适用于 @ThorSummoner 很好的答案,只是想添加一个可能有一天会帮助其他人的注释,在设置私有属性时,您必须传递该属性所属的类名。如果属性属于父类,你可以做\ReflectionProperty(get_parent_class($instance), 'propertyName') 否则你应该做\ReflectionProperty(\namespace\ParentClass::class,'propertyName') 如果私有属性属于当前类,那么\ReflectionProperty($instance, 'propertyName')【参考方案3】:

您还可以实现类内部方法来更改对象属性访问设置,然后使用$instanve-&gt;properyname = ..... 设置值:

public function makeAllPropertiesPublic(): void

    $refClass = new ReflectionClass(\get_class($this));
    $props = $refClass->getProperties();
    foreach ($props as $property) 
        $property->setAccessible(true);
    

【讨论】:

以上是关于有没有办法使用反射类设置私有/受保护的静态属性?的主要内容,如果未能解决你的问题,请参考以下文章

PHP 从静态方法访问对象的受保护属性

如何访问派生类中的私有集属性[重复]

向某些类公开受保护/私有属性

为啥同一类而不是同一对象可以访问受保护和私有属性?

检查和编辑对象的私有/受保护属性

特征可以具有具有私有和受保护可见性的属性和方法吗?特质可以有构造函数、析构函数和类常量吗?