PHP获取类私有属性的几种方式

时间: 2019-07-10阅读: 33标签: 属性

今天在推上看到一条获取PHP类私有属性的推文,感觉很有意思:

顺着推文联想,还有其他方式吗?经过自己的测试及网上答案,总结出三种方法:


1. 反射

反射可以获取类的详细信息,要获取私有属性的值,只需将对应属性的 ReflectionProperty 实例设置为可访问再取值即可。示例代码如下:

namespace tlanyan;

class Foo {
  private $bar = "Foo bar!";
}

// 获取反射类及反射属性
$class = new \ReflectionClass(Foo::class);
$property = $class->getProperty("bar");
// 设置属性可访问
$property->setAccessible(true);

$foo = new Foo;
// 获取对象属性值
// 注意:只能通过 ReflectionProperty 实例的 getValue 方法访问
// 不能这样直接访问: $foo->bar;
echo $property->getValue($foo), PHP_EOL:
// 输出: Foo bar!

本人之前写过“PHP回顾之反射”一文,比较详细的介绍了反射及用法,有兴趣的阅读参考。


2. 转换成数组

这种方法用将对象强制转换成数组,再通过键获取其值。示例代码如下:

class Foo {
  private $bar = "Foo bar!";
}

$foo = new Foo;
// 强制转型
$attrs = (array)$foo;
// 拼接key,注意 "\0" 不能改成单引号!
$key = "\0" . Foo::class . "\0" . "bar";
echo $attrs[$key], PHP_EOL;
// 输出: Foo bar!

上述代码中key的拼接方式比较诡异,根据鸟哥“ 深入理解PHP原理之对象(一) ”文中的信息,key规则如下:

  1. public 属性, key是 属性名 ;
  2. protected 属性,key是 \0*\0属性名 ;
  3. private 属性, key是 \0类名\0属性名 。

注意 \0 是一个字符(不是两个),对应的ASCII码是数字0。编程时要用 双引号 将其引起来。不能使用单引号,否则转义失效,那就是两个字符。如果你有C语言基础,应该知道 \0 就是字符串的结束符。这个符号直接输出不会显示,但可以通过 strlen 或者 ord 让其现形:

foreach ($attrs as $key => $value) {
  echo "key:$key", ", key length:", strlen($key), ", ascii: ";
  for ($i = 0; $i < strlen($key); ++ $i) {
    echo ord($key[$i]), " "; 
  }
  echo PHP_EOL;
}
// 输出
// key:Foobar, key length:8, ascii: 0 70 111 111 0 98 97 114
// Foobar 有6个字符,加上两个不显示字符,所以长度是8

还需要注意拼接 private 属性时类名应该是 “完全限定类名” ,建议通过 Foo::class 的方式获取。

与强制转换成数组类似的另一种方法是 serialize ,但是 serialize 比较慢,并且序列化后的字符串更难辨认结构和处理,不建议使用。


3. 闭包

文章开头的推特截图已经展示了闭包的用法,其中 call 方法在PHP7中引入,另一个是PHP5.4引入的 bindTo 。 call 和 bindTo 的用法示例如下:

namespace tlanyan;

class Foo {
  private $bar = "Foo bar!";
}

$foo = new Foo;
// 闭包(匿名函数)是PHP5.3引入的功能
$closure = function() { return $this->bar; };
// PHP5.4起支持bindTo方法
$method = $closure->bindTo($foo, Foo::class);
echo $method(), PHP_EOL;

// PHP7引入call方法,可绑定this直接执行
echo $closure->call($foo), PHP_EOL;

bindTo 方法的第二个参数注意传入对象的 “完全限定类名” ,指示函数应该放置在该类的作用域下,从而可以访问私有属性。


总结

性能:数组 > 反射 > 闭包

易用性:闭包 > 数组 > 反射

推荐:闭包 > 反射 > 数组

原文来自:https://www.tlanyan.me/ways-to-access-php-class-private-members/


链接: http://www.fly63.com/article/detial/4616

Css边框阴影:box-shadow属性

box-shadow是css3新增的一个属性。在W3School里,定义box-shadow是向框添加一个或者多个阴影的属性。 语法:box-shadow: h-shadow v-shadow blur spread color inset. h-shadow: 阴影的水平位置 v-shadow:阴影的垂直位置 blur

CSS3中box-shadow属性

box-shadow属性是一个CSS3属性,允许我们在几乎任何元素上来创建阴影效果,类似于在设计软件中的”drop shadow”。这些阴影效果允许我们在原本平面的、二维的页面上面创建出深度(第三维)的错觉。

Js枚举属性与for-in和for-of

首先要分清什么是可枚举属性,什么是不可枚举属性,在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。

vue里的$refs属性

vuejs的极大程度的帮助减少了对dom的操作,他主要通过添加ref属性,但是当获取this.$refs属性时,稍有不注意就会输出undefined导致我们对dom节点的操作报错。this.$refs.xxx为undefined的几种情况记录:

Vue之计算属性

模板内的表达式通常用于简单的运算,当其过长或逻辑复复杂时,会变得难以维护,在Vue应用中,在模板中双向绑定一些数据或者表达式,但是表达式如果过长,或者逻辑更为复杂时

JS中轻松遍历对象属性的几种方式

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组

css3的calc属性不生效问题

css3的 calc:计算属性。由于自己做的项目中这个属性不常用到,偶尔用一次还没效果。后来研究了下是因为运算符两边没加空格。

Js对象的三个属性

每个对象都拥有三个特性(属性)(object attribute):对象的原型(prototype)。指向另外一个对象,本对象的属性继承自它的原型对象。对象的类(class)。是一个表示对象类型的字符串。对象的扩展标记(extensible flag)

css3新增的属性有哪些?

CSS 用于控制网页的样式和布局。CSS3 是最新的 CSS 标准。CSS3新增了很多的属性,下面一起来分析一下新增的一些属性:

CSS filter 属性

filter将模糊或者颜色偏移等图像效果用于元素,通常用于调整图像,背景和边框的渲染,css 标准中已内置一些预定义效果的函数,也可通过url使用SVG滤镜

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

广告赞助文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全