如何在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