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实现维护文件代码
Jun 14 PHP
坏狼的PHP学习教程之第2天
Jun 15 PHP
php下检测字符串是否是utf8编码的代码
Jun 28 PHP
PHP教程 基本语法
Oct 23 PHP
Discuz7.2版的faq.php SQL注入漏洞分析
Aug 06 PHP
PHP中字符安全过滤函数使用小结
Feb 25 PHP
Laravel5中contracts详解
Mar 02 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
Jan 08 PHP
PHP通过微信跳转的Code参数获取用户的openid(关键代码)
Jul 06 PHP
php文件上传、下载和删除示例
Aug 28 PHP
php数组指针操作详解
Feb 14 PHP
laravel-admin表单提交隐藏一些数据,回调时获取数据的方法
Oct 08 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 Memcache 中实现消息队列
2009/11/24 PHP
PHP技术开发技巧分享
2010/03/23 PHP
php下封装较好的数字分页方法
2010/11/23 PHP
PHP中的函数声明与使用详解
2017/05/27 PHP
Jquery下EasyUI组件中的DataGrid结果集清空方法
2014/01/06 Javascript
JavaScript实现鼠标点击后层展开效果的方法
2015/05/13 Javascript
微信小程序 less文件编译成wxss文件实现办法
2016/12/05 Javascript
前端主流框架vue学习笔记第一篇
2017/07/26 Javascript
用node开发并发布一个cli工具的方法步骤
2019/01/03 Javascript
详解vue中使用protobuf踩坑记
2019/05/07 Javascript
Vue+Vant 图片上传加显示的案例
2020/11/03 Javascript
[01:17:55]VGJ.T vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/20 DOTA
python学生信息管理系统
2018/03/13 Python
dataframe 按条件替换某一列中的值方法
2019/01/29 Python
pyhanlp安装介绍和简单应用
2019/02/22 Python
python写一个随机点名软件的实例
2019/11/28 Python
Scrapy框架实现的登录网站操作示例
2020/02/06 Python
Python创建空列表的字典2种方法详解
2020/02/13 Python
Python模拟登录requests.Session应用详解
2020/11/17 Python
日本钓鱼渔具和户外用品网上商店:naturum
2016/08/07 全球购物
Spartoo英国:欧洲最大的网上鞋店
2016/09/13 全球购物
澳大利亚最超值的自行车之家:Reid Cycles
2019/03/24 全球购物
阿姆斯特丹城市卡:Amsterdam Pass
2019/12/01 全球购物
澳大利亚有机化妆品网上商店:The Well Store
2020/02/20 全球购物
学生生病请假条范文
2014/02/16 职场文书
老龙头导游词
2015/02/11 职场文书
寒假致家长的一封信
2015/10/10 职场文书
2016八一建军节慰问信
2015/11/30 职场文书
篮球拉拉队口号
2015/12/25 职场文书
2016年万圣节活动个人总结
2016/04/05 职场文书
2019年鼓励无偿献血倡议书
2019/09/17 职场文书
导游词之西安骊山
2019/12/03 职场文书
Redis缓存-序列化对象存储乱码问题的解决
2021/06/21 Redis
javascript的setTimeout()使用方法总结
2021/11/20 Javascript
Appium中scroll和drag_and_drop根据元素位置滑动
2022/02/15 Python
基于Python实现对比Exce的工具
2022/04/07 Python