正常情况下我们只能访问对象的 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