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

如何在PHP中获取对象的受保护属性,php,object,protected,php-5.2,Php,Object,Protected,Php 5.2,我有一个对象,它有一些我想要获取和设置的受保护属性。这个物体看起来像 Fields_Form_Element_Location Object ( [helper] => formText [_allowEmpty:protected] => 1 [_autoInsertNotEmptyValidator:protected] => 1 [_belongsTo:protected] => [_description:protected] => [_disabl

我有一个对象,它有一些我想要获取和设置的受保护属性。这个物体看起来像

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
)
我想获取对象的
属性。当我尝试
$obj->\u value
$obj->value
时,它会生成错误。我搜索并找到了使用
PHP反射类的解决方案
。它在我的本地服务器上工作,但在服务器上PHP版本是
5.2.17
,因此我无法在那里使用此函数。那么,有什么解决方案可以获得这样的属性吗?

这就是“受保护”的含义,正如本章所解释的:

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

如果需要从外部访问属性,请选择一个:

  • 不要将其声明为受保护,而是将其公开
  • 编写两个函数来获取和设置值(getter和setter)
如果您不想修改原始类(因为它是第三方库,您不想弄乱),请创建扩展原始类的自定义类:

class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}

。。。并在那里添加getter/setter。

如果不能修改原始类,并且扩展它也不是一个选项,那么可以使用ReflectionProperty接口

phptoolcase库提供了一种简便的方法:

$value = PtcHandyMan::getProperty($your_object , 'propertyName');
singleton类的静态属性:

$value = PtcHandyMan::getProperty('myCLassName', 'propertyName');

您可以在这里找到该工具:

对象可以类型化为(关联)数组,受保护的成员的键前缀为
chr(0)。“*”.chr(0)
(请参阅@fardelian的注释)。使用此未记录的功能,您可以编写“exposer”:

或者,您可以解析字符串中的值,其中(似乎)受保护的成员具有相同的前缀


这在PHP5.2中工作,没有ReflectionClass的开销。但是,有些属性受到保护并对客户端代码隐藏是有原因的。读或写可能会使数据不一致,或者作者提供了一些其他方式来公开数据,以尽可能精简接口。当有理由直接读取受保护的属性时,正确的方法是实现magic方法,因此请始终检查是否存在任何方法。

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

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

我知道你说过你被限制在5.2版本,但那是两年前的事了,我希望能帮助人们使用现代版本。

如果你想在不添加getter和setter的情况下修补类

  $propGetter = Closure::bind(  function($prop){return $this->$prop;}, $element['field_text']['#object'], $element['field_text']['#object'] );
  drupal_set_message('count='.count($propGetter('hostEntity')->field_captioned_carousel['und']));
PHP7在闭包上添加了一个call($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 
对于PHP 7.4+,我们可以使用和来访问私有和受保护的成员,只需使用一小行:

PHP7.4+ 检索受保护/私有成员:

类测试{
受保护的$data='受保护的变量!';
}
//将输出“受保护变量!”
echo(fn()=>$this->data)->调用(新测试);
更改受保护/私人成员:

类测试{
受保护的$数据='测试';
}
$test=新测试;
(fn()=>$this->data=“newdata!”)->调用($test);
//将输出“新数据!”
echo(fn()=>$this->data)->调用($test);
当然,如果要更改/使用多个成员,我们可以使用普通函数:

类测试{
受保护的$data='data!';
}
$test=新测试;
(功能(){
$this->new_data=“new{$this->data}”;
})->电话($测试);
//将输出“新数据!”
echo(fn()=>$this->new_data)->调用($test);

我喜欢做的是将所有可从外部写入的属性声明为public。您希望外部世界可见但不可写的属性应声明为受保护的并写入\u get()magic方法,以便读取它们。例如:

/**
 * Class Test
 *
 * @property int $protected
 *
 */
class Test
{
    
    private const READABLE = ['protected'];
    
    protected $protected = 1;
    
    public $public = 2;
    
    public function __get($property)
    {
        //if you want to read every protected or private
        return $this->$property ?? null;
    
        //if you want only some protected and private values to be readable
        if (in_array($property, self::READABLE)) {
            return $this->$property;
        }
    }
}

$test = new Test();
echo $test->protected; //outputs 1
echo $test->public; //outputs 2

$test->protected = 3; //outputs error - protected property
最好有财产声明,如:

public readonly $protected = 1; //only readable from the outside
public  $public = 2; //readable and writable from the outside

但目前还不存在这样的语法(或者……至少我不知道)P.S.您应该声明受保护/私有属性,这些属性将在类DockBlock中可读,如图所示,以便您可以自动完成它们,否则您将能够访问它们,但是当您编写代码时,IDE在自动完成时无法识别它们。

使用getter和setter是否省略了一些上下文?您只需要编写适当的setter/getter方法对。如果你不能修改这个类,你可以简单地扩展它。@Arnaud我想他已经理解了OOP的基本原理。我认为这里真正的问题是他不能修改Fields\u Form\u Element\u Location类。请查看类代码或文档,看它是否提供了访问这些数据的getter。如果没有,你就不应该访问它。找出原因。如果你仍然需要访问它,你需要修改类和/或与它的作者交谈。没有文档的“付费工具”?那你付什么钱?D-;这是一个明确的黑客,但在我的情况下,我工作的框架限制了我的行动。只要你知道自己在做什么和为什么,这本书就很有用,也很好用——谢谢!)是的,我发现它在单元测试中非常有用,在单元测试中,您希望检查对私有属性的分配,但不一定要将其公开。ReflectionClass在5.x的所有版本中都可用,并且不需要库、要求或配置(在PHP的所有版本中都可用)@PhilM但是
ReflectionProperty::setAccessible
是PHP5>=5.3.0反射是其中之一,如果您发现自己正在使用它,您应该仔细查看以确保您需要。也就是说,每件事都有时间和地点。我支持这样的观点,即这在单元测试中非常有用,可以确保对象能够访问它应该访问的数据。在我的例子中,我使用Laravel的队列模拟来验证一个给定的作业是否已被触发,以及它是否已被触发
public readonly $protected = 1; //only readable from the outside
public  $public = 2; //readable and writable from the outside