正常情况下我们只能访问对象的 public 属性

虽然 private 和 protected 设计的目的就是为了实现封装,不让外界直接访问,但是有时候使用一些 API 进行数据获取的时候,返回的数据可能就存在于 protected或 private 中,这时就必须找到一个方法可以直接访问这些数据。

以下方法可以实现强制访问对象数据

反射覆盖(PHP> = 5.3)

使用Reflection类,可以反映现有对象,并使用 ReflectionProperty :: setAccessible方法更改所需的每个属性的可访问性。示例如下:

//example of a class with hidden properties
class MyExampleClass         
{
    public $myPublicVar = "I'm public!";
    protected $myProtectedVar = "I'm protected!";
    private $myPrivateVar = "I'm private!";
}

$obj = new MyExampleClass();
$refObj  = new ReflectionObject($obj);
$refProp1 = $refObj->getProperty('myProtectedVar');
$refProp1->setAccessible(TRUE);
$refProp2 = $refObj->getProperty('myPrivateVar');
$refProp2->setAccessible(TRUE);

echo $refProp1->getValue($obj);               //echoes: I'm protected!
echo $refProp2->getValue($obj);               //echoes: I'm private!

使用Reflection据说非常慢,但好处是你不仅可以读取属性的值,还可以使用ReflectionProperty :: setValue方法更改它。

数组强制转换

这是我发现的概念上最简单的方法,也是我所知道的唯一一个适用于5.3之前的PHP版本的方法。它涉及将Object转换为数组,并查看Array元素以获取所需的属性。执行此操作时,根据特殊规则命名与每个属性对应的Array元素的索引,具体取决于其在Object内的可见性。下一个伪代码片段显示了以下规则:

switch ($visibility) {
    case 'public':
        $array_index = $property_name;
        break;
    case 'protected':
        $array_index = "\0*\0" . $property_name;
        break;
    case 'private':
        $array_index = "\0" . $class_name . "\0" . $property_name;
        break;
}

这意味着您访问该属性的方式取决于其可见性。正如您所看到的,在两个NULL字节之间,PHP三明治是星号或类名(取决于可见性是受保护的还是私有的),并将其预先添加到属性名称以形成Array索引。因此,您可以按如下方式访问对象的隐藏属性:

//example of a class with hidden properties
class MyExampleClass                 
{
    public $myPublicVar = "I'm public!";
    protected $myProtectedVar = "I'm protected!";
    private $myPrivateVar = "I'm private!";
}

$obj = new MyExampleClass();
$obj_array = (Array)$obj;         //cast the object as an Array

echo $obj_array['myPublicVar'];                                        //echoes: I'm public!
echo $obj_array["\0*\0" . 'myProtectedVar'];                           //echoes: I'm protected!
echo $obj_array["\0" . 'MyExampleClass' . "\0" . 'myPrivateVar'];      //echoes: I'm private!

闭包绑定覆盖(PHP> = 5.4)

class MyExampleClass   //example of a class with hidden properties
{
    public $myPublicVar = "I'm public!";
    protected $myProtectedVar = "I'm protected!";
    private $myPrivateVar = "I'm private!";
}

$obj = new MyExampleClass();
$propGetter = Closure::bind(  function($prop){return $this->$prop;}, $obj, $obj );

echo $propGetter('myProtectedVar');    //echoes: I'm protected!
echo $propGetter('myPrivateVar');            //echoes: I'm private!

参考资料:

https://www.sitepoint.com/community/t/how-to-access-protected-property-in-a-class/216904