PHP获取类私有属性的3种方法


Posted in PHP onSeptember 10, 2020

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

PHP获取类私有属性的3种方法

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

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的拼接方式比较诡异,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引入的bindTocallbindTo的用法示例如下:

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

总结

性能: 数组 > 反射 > 闭包

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

推荐: 闭包 > 反射 > 数组

以上就是PHP获取类私有属性的3种方法的详细内容,更多关于PHP获取类私有属性的资料请关注三水点靠木其它相关文章!

PHP 相关文章推荐
php数据入库前清理 注意php intval与mysql的int取值范围不同
Dec 12 PHP
php XPath对XML文件查找及修改实现代码
Jul 27 PHP
php curl基本操作详解
Jul 23 PHP
PHP中使用sleep造成mysql读取失败的案例和解决方法
Aug 21 PHP
php操作(删除,提取,增加)zip文件方法详解
Mar 12 PHP
PHP5.2下preg_replace函数的问题
May 08 PHP
PHP+MySQL统计该库中每个表的记录数并按递减顺序排列的方法
Feb 15 PHP
ZendFramework2连接数据库操作实例
Apr 18 PHP
简单实现php上传文件功能
Sep 21 PHP
Laravel中encrypt和decrypt的实现方法
Sep 24 PHP
PHP二维数组实现去除重复项的方法【保留各个键值】
Dec 21 PHP
解决Laravel无法使用COOKIE和SESSION的问题
Oct 16 PHP
php实现图片压缩处理
Sep 09 #PHP
如何在PHP中读写文件
Sep 07 #PHP
PHP延迟静态绑定使用方法实例解析
Sep 05 #PHP
PHP autoload使用方法及步骤详解
Sep 05 #PHP
PHP数组访问常用方法解析
Sep 05 #PHP
XAMPP升级PHP版本实现步骤解析
Sep 04 #PHP
php使用Swoole实现毫秒级定时任务的方法
Sep 04 #PHP
You might like
一篇入门的php Class 文章
2007/04/04 PHP
让PHP开发者事半功倍的十大技巧小结
2010/04/20 PHP
PHP输出数组中重名的元素的几种处理方法
2012/09/05 PHP
PHP使用标准库spl实现的观察者模式示例
2018/08/04 PHP
php中钩子(hook)的原理与简单应用demo示例
2019/09/03 PHP
php5与php7的区别点总结
2019/10/11 PHP
javascript笔试题目附答案@20081025_jb51.net
2008/10/26 Javascript
利用了jquery的ajax实现二级联互动菜单
2013/12/02 Javascript
javascript中typeof的使用示例
2013/12/19 Javascript
自己封装的javascript事件队列函数版
2014/06/12 Javascript
D3.js实现直方图的方法详解
2016/09/25 Javascript
vue-router跳转页面的方法
2017/02/09 Javascript
Vue.js使用$.ajax和vue-resource实现OAuth的注册、登录、注销和API调用
2017/05/10 Javascript
BootStrap 页签切换失效的解决方法
2017/08/17 Javascript
详解webpack3编译兼容IE8的正确姿势
2017/12/21 Javascript
vue双向数据绑定知识点总结
2018/04/18 Javascript
echarts饼图各个板块之间的空隙如何实现
2020/12/01 Javascript
javascript实现简单页面倒计时
2021/03/02 Javascript
Python的Django框架中从url中捕捉文本的方法
2015/07/20 Python
python中is与双等于号“==”的区别示例详解
2017/11/21 Python
python实现两个文件合并功能
2018/04/01 Python
基于Python中numpy数组的合并实例讲解
2018/04/04 Python
python 列表递归求和、计数、求最大元素的实例
2018/11/28 Python
Python3.7+tkinter实现查询界面功能
2019/12/24 Python
实例讲解CSS3中的border-radius属性
2015/08/18 HTML / CSS
Ryderwear美国官网:澳大利亚高端健身训练装备品牌
2018/04/24 全球购物
可口可乐唇膏:Lip Smackers
2019/08/27 全球购物
华为C++笔试题
2014/08/05 面试题
刘胡兰的英雄事迹材料
2014/02/11 职场文书
自荐信模板大全
2015/03/27 职场文书
2015年中学校长工作总结
2015/05/19 职场文书
爱的教育读书笔记
2015/06/26 职场文书
使用react-virtualized实现图片动态高度长列表的问题
2021/05/28 Javascript
PHP实现两种排课方式
2021/06/26 PHP
Netty客户端接入流程NioSocketChannel创建解析
2022/03/25 Java/Android
Python面试不修改数组找出重复的数字
2022/05/20 Python