如何在PHP中获取对象的受保护属性

Awa*_*rni 53 php protected object php-5.2

我有一个对象有一些我想要获取和设置的受保护属性.对象看起来像

Fields_Form_Element_Location Object
(
[helper] => formText
[_allowEmpty:protected] => 1
[_autoInsertNotEmptyValidator:protected] => 1
[_belongsTo:protected] => 


[_description:protected] => 
[_disableLoadDefaultDecorators:protected] => 
[_errorMessages:protected] => Array
    (
    )

[_errors:protected] => Array
    (
    )
[_isErrorForced:protected] => 
[_label:protected] => Current City


[_value:protected] => 93399
[class] => field_container field_19 option_1 parent_1
)
Run Code Online (Sandbox Code Playgroud)

我想获得value该对象的属性.当我尝试$obj->_value$obj->value它产生错误.我搜索并找到了使用的解决方案PHP Reflection Class.它在我的本地工作但在服务器PHP版本是5.2.17因此我不能在那里使用此功能.那么任何解决方案如何获得这样的属性?

dre*_*ish 94

以下是如何使用的非常简单的示例(没有错误检查)ReflectionClass:

function accessProtected($obj, $prop) {
  $reflection = new ReflectionClass($obj);
  $property = $reflection->getProperty($prop);
  $property->setAccessible(true);
  return $property->getValue($obj);
}
Run Code Online (Sandbox Code Playgroud)

我知道你说你被限制在5.2,但那是2年前,5.5是最老的支​​持版本,我希望能帮助现代版本的人.

  • 这是一个明确的黑客,但在我的情况下,我正在使用的框架限制了我的动作.只要您知道自己在做什么以及为什么这样做,这个有用并且很好用 - 谢谢!:) (6认同)
  • 反思是其中之一,如果你发现自己使用它,你应该认真考虑,以确保你需要.也就是说,一切都有时间和地点.我认为这在单元测试中派上用场,以确保对象可以访问它应该拥有的数据.就我而言,我正在使用Laravel的Queue模拟来验证给定的Job已经触发,但是它被赋予了适当的数据,存储在受保护的属性中.如果没有这个,那么异步会让断言变得有点棘手.谢谢@drewish. (2认同)

Jan*_*roň 47

对象可以被类型强制转换成(关联)阵列和保护成员有前缀键chr(0).'*'.chr(0)(见@ fardelian的评论在这里).使用这个未填充的功能,您可以编写"曝光器":

function getProtectedValue($obj,$name) {
  $array = (array)$obj;
  $prefix = chr(0).'*'.chr(0);
  return $array[$prefix.$name];
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以解析序列化字符串中的值,其中(似乎)受保护的成员具有相同的前缀(我希望php 5.2没有更改它).


Álv*_*lez 22

这就是"受保护"的含义,正如可见性章节所解释的那样:

声明受保护的成员只能在类本身以及继承和父类中访问.

如果您需要从外面进入酒店,请选择一个:

  • 不要将其声明为受保护,而是将其公之于众
  • 编写一些函数来获取和设置值(getter和setter)

如果您不想修改原始类(因为它是第三方库,您不想弄乱)创建一个扩展原始类的自定义类:

class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}
Run Code Online (Sandbox Code Playgroud)

...并在那里添加你的getter/setter.

  • 但是如果你使用一些外部库并且你必须调试它并想要打印一些受保护字段的值呢? (5认同)
  • @KamilKiełczewski抱歉,我根本无法得到它.如果你的意思是标准的OOP原则以某种方式干扰调试我强烈不同意,但当然你总能找到一个场景,意大利面条更容易处理;-) (4认同)

use*_*001 11

如果你想修改一个类而不添加getter和setter ....

PHP 7在闭包上添加了一个调用($ obj)方法(比旧的bindTo更快),允许你调用一个函数,这样$this变量就像在一个类中一样 - 具有完全权限.

 //test class with restricted properties
 class test{
    protected $bar="protected bar";
    private $foo="private foo";
    public function printProperties(){
        echo $this->bar."::".$this->foo;   
     }
 }

$testInstance=new test();
//we can change or read the restricted properties by doing this...
$change=function(){
    $this->bar="I changed bar";
    $this->foo="I changed foo";
};
$change->call($testInstance);
$testInstance->printProperties();
//outputs I changed bar::I changed foo in php 7.0 
Run Code Online (Sandbox Code Playgroud)


Chr*_*ras 8

对于PHP 7.4+,我们可以使用箭头函数和 ,Closure::call只需一小行即可访问私有和受保护的成员:

PHP 7.4+

检索受保护/私有成员:

class Test {
  protected $data = 'Protected variable!';
}

// Will output "Protected variable!"
echo (fn() => $this->data)->call(new Test);
Run Code Online (Sandbox Code Playgroud)

更改受保护/私有成员:

class Test {
  protected $data = 'Testing';
}

$test = new Test;

(fn() => $this->data = "New Data!")->call($test);

// Will output "New Data!"
echo (fn() => $this->data)->call($test);
Run Code Online (Sandbox Code Playgroud)

当然,Closure如果我们想更改/使用多个成员,我们可以使用普通函数:

class Test {
  protected $data = 'Data!';
}

$test = new Test;

(function() {
  $this->new_data = "New {$this->data}";
})->call($test);

// Will output "New Data!"
echo (fn() => $this->new_data)->call($test);
Run Code Online (Sandbox Code Playgroud)