最近在读《php核心技术与最佳实践》这本书,书中第一章提到用__call()方法可以实现一个简单的字符串链式操作,比如,下面这个过滤字符串然后再求长度的操作,一般要这么写:
strlen(trim($str));
那么能否实现下面这种写法呢?
$str->trim()->strlen();
下面就来试下。
链式操作,说白了其实就是链式的调用对象的方法。既然要实现字符串的链式操作,那么就要实现一个字符串类,然后对这个类的对象进行调用操作。我对字符串类的期望如下:(1)当我创建对象时,我可以将字符串赋值给对象的属性,并且可以访问这个属性读取值;(2)我可以调用trim() 和strlen()方法;(3)我还可以这么调用方法$str->trim()->strlen()。
上面的第(1)条,是一个字符串类的基本要求。先把这个实现了:
1 class String
2 { 3 public $value; 4
5 public function __construct($str=null) 6 { 7 $this->value = $str; 8 } 9 }
可以试下:
1 $str = new String('01389'); 2 echo $str->value;
然后再看第2条,先把$str->trim()实现了,参考书中的思路:触发__call方法然后执行call_user_func。代码如下:
1 class String
2 {
3 public $value;
4
5 public function __construct($str=null)
6 {
7 $this->value = $str;
8 }
9
10 public function __call($name, $args) 11 { 12 $this->value = call\_user\_func($name, $this->value, $args[0]); 13 return $this; 14 } 15 }
测试下:
1 $str = new String('01389'); 2 echo $str->trim('0')->value;
结果如下:
上面需要注意的是第12行: $this->value = call\_user\_func($name, $this->value, $args[0]); $name是回调函数的名字(这里也就是trim),后面两个是回调函数(trim)的参数,参数的顺序不要弄颠倒了。$args是数组,也需要注意下。
第2条中还要实现strlen(),这时上面代码中的第13行就很关键了: return $this; 它的作用就是,在第12行调用trim()处理完字符串后重新value属性赋值,然后返回当前对象的引用,这样对象内的其他方法就可以对属性value进行连续操作了,也就实现了链式操作。$str->strlen()实现如下:
1 class String
2 {
3 public $value;
4
5 public function __construct($str=null)
6 {
7 $this->value = $str;
8 }
9
10 public function __call($name, $args) 11 { 12 $this->value = call\_user\_func($name, $this->value, $args[0]); 13 return $this; 14 } 15
16 public function strlen() 17 { 18 return strlen($this->value); 19 } 20 }
测试下:
1 $str = new String('01389'); 2 echo $str->strlen();
结果:
链式操作:
echo $str->trim('0')->strlen();
结果:
到这里,这篇文章本该就结束了。但是,我想了下,其实不用__call()方法,也是可以实现链式操作的。下面是不用__call()的实现:
1 class String
2 {
3 public $value;
4
5 public function __construct($str=null)
6 {
7 $this->value = $str;
8 }
9
10 public function trim($t) 11 { 12 $this->value = trim($this->value, $t); 13 return $this; 14 } 15
16 public function strlen() 17 { 18 return strlen($this->value); 19 } 20 }
链式操作的关键是在做完操作后要return $this。
另外,本文受到园子里这篇文章的启发,用call_user_func_array()替换了call_user_func()实现,将__call()方法修改如下。
1 public function __call($name, $args) 2 { 3 array_unshift($args, $this->value); 4 $this->value = call\_user\_func_array($name, $args); 5 return $this; 6 }
与上面的__call()方法效果是相同的,这样代码似乎比之前的实现要优雅些。
总结:
__call()在对象调用一个不可访问的方法时会被触发,所以可以实现类的动态方法的创建,实现php的方法重载功能,但它其实是一个语法糖(__construct()方法也是)。
那么如果没有__call()等语法糖,能否实现动态方法的创建和链式操作呢?我想会涉及到以下几个方面的问题:类方法是否存在和可以调用,这个可以用method_exists、is_callable、get_class_methods等方法来实现,另外,就是在创建对象时给属性赋值(初始化),这个语法糖确实方便,不过不是必需的。等有时间再研究下吧。
分类: PHP
标签: PHP, 链式操作, chain operation
好文要顶;) 关注我;) 收藏该文;) ; "分享至新浪微博") ; "分享至微信")
+加关注;)
2
0
« 上一篇:javascript的变量作用域--对比js、php和c的for循环
» 下一篇:wordpress插件bug排查后记(记一次由于开启memecached引起的插件bug)
posted @ 2016-11-25 21:03 yangtoude 阅读(4079) 评论(1) 编辑 收藏
Original url: Access
Created at: 2018-11-29 20:51:56
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论