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

时间:2013-12-02 17:33:45

标签: php object protected 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
)

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

9 个答案:

答案 0 :(得分:81)

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

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

我知道你说你被限制在5.2,但那是两年前的5.5 is the oldest supported version,我希望能帮助现代版本的人。

答案 1 :(得分:43)

对象可以被类型转换为(关联)数组,受保护的成员具有前缀为chr(0).'*'.chr(0)的键(请参阅@ fardelian' s comment here)。使用这个未填充的功能,您可以编写"曝光器":

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

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

答案 2 :(得分:21)

这就是“受保护”的意思,正如Visibility章节所解释的那样:

  

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

如果您需要从外面访问该物业,请选择一个:

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

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

class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}

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

答案 3 :(得分:10)

如果你想修改课程而不添加getter和setter ....

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

 //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 

答案 4 :(得分:3)

如果您无法修改原始类并且不能扩展它,则可以使用ReflectionProperty接口。

phptoolcase库有一个方便的方法:

$value = PtcHandyMan::getProperty( $your_object , ‘propertyName’);

单例类的静态属性:

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

您可以在此处找到该工具:http://phptoolcase.com/guides/ptc-hm-guide.html

答案 5 :(得分:1)

对于 PHP 7.4+,我们可以使用 Arrow FunctionClosure::call 来访问私有成员和受保护成员,只需一行:

PHP 7.4+

检索受保护/私有成员:

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

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

更改受保护/私有成员:

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);

当然,如果我们想改变/使用多个成员,我们可以使用普通的 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);

答案 6 :(得分:0)

我喜欢做的是将所有可从外部写入的属性声明为public。您希望对外界可见但不可写的属性应该声明为 protected 并编写 __get()< /em> 魔术方法,以便您可以阅读它们。示例:

/**
 * 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

但尚不存在这样的语法(或者...至少我不知道)。 PS 你应该声明在 Class DockBlock 中可读的 protected/private 属性,如图所示,这样你就可以自动完成它们,否则你会能够访问它们,但是当您编写代码时,您的 IDE 在自动完成时将无法识别它们。

答案 7 :(得分:-1)

  $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']));

答案 8 :(得分:-2)

Laravel解决方案:

collect($obj)->get('property')