最近在读《php核心技术与最佳实践》这本书,书中第一章提到用__call()方法可以实现一个简单的字符串链式操作,比如,下面这个过滤字符串然后再求长度的操作,一般要这么写:

strlen(trim($str));

那么能否实现下面这种写法呢?

$str->trim()->strlen();

下面就来试下。

链式操作,说白了其实就是链式的调用对象的方法。既然要实现字符串的链式操作,那么就要实现一个字符串类,然后对这个类的对象进行调用操作。我对字符串类的期望如下:(1)当我创建对象时,我可以将字符串赋值给对象的属性,并且可以访问这个属性读取值;(2)我可以调用trim() 和strlen()方法;(3)我还可以这么调用方法$str->trim()->strlen()。

上面的第(1)条,是一个字符串类的基本要求。先把这个实现了:

 class String
{
public $value; public function __construct($str=null)
{
$this->value = $str;
}
}

可以试下:

 $str = new String('01389');
echo $str->value;

然后再看第2条,先把$str->trim()实现了,参考书中的思路:触发__call方法然后执行call_user_func。代码如下:

 class String
{
public $value; public function __construct($str=null)
{
$this->value = $str;
} public function __call($name, $args)
{
$this->value = call_user_func($name, $this->value, $args[0]);
return $this;
}
}

测试下:

 $str = new String('01389');
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()实现如下:

 class String
{
public $value; public function __construct($str=null)
{
$this->value = $str;
} public function __call($name, $args)
{
$this->value = call_user_func($name, $this->value, $args[0]);
return $this;
} public function strlen()
{
return strlen($this->value);
}
}

测试下:

 $str = new String('01389');
echo $str->strlen();

结果:

链式操作:

echo $str->trim('0')->strlen();

结果:


到这里,这篇文章本该就结束了。但是,我想了下,其实不用__call()方法,也是可以实现链式操作的。下面是不用__call()的实现:

 class String
{
public $value; public function __construct($str=null)
{
$this->value = $str;
} public function trim($t)
{
$this->value = trim($this->value, $t);
return $this;
} public function strlen()
{
return strlen($this->value);
}
}

链式操作的关键是在做完操作后要return $this。

另外,本文受到园子里这篇文章的启发,用call_user_func_array()替换了call_user_func()实现,将__call()方法修改如下。

     public function __call($name, $args)
{
array_unshift($args, $this->value);
$this->value = call_user_func_array($name, $args);
return $this;
}

与上面的__call()方法效果是相同的,这样代码似乎比之前的实现要优雅些。


总结:

__call()在对象调用一个不可访问的方法时会被触发,所以可以实现类的动态方法的创建,实现php的方法重载功能,但它其实是一个语法糖(__construct()方法也是)。

那么如果没有__call()等语法糖,能否实现动态方法的创建和链式操作呢?我想会涉及到以下几个方面的问题:类方法是否存在和可以调用,这个可以用method_exists、is_callable、get_class_methods等方法来实现,另外,就是在创建对象时给属性赋值(初始化),这个语法糖确实方便,不过不是必需的。等有时间再研究下吧。

用php实现一个简单的链式操作的更多相关文章

  1. js实现一个简单的链式操作

    如何实现一个链式操作 function person() {} person.prototype = { setname: function(name) { this.name = name retu ...

  2. 超简单jQuary链式操作代码实现手风琴效果

    超简单jQuery代码实现手风琴效果 HTML代码 <div id="cont"> <div> <p>人生若只如初见</p> < ...

  3. php链式调用(链式操作)

    2017年6月28日 10:41:19 星期三 情景: 在多次处理数组的时候, 要自定义好多个临时变量, 起名字特别麻烦 于是, 就想到利用PHP的 1.魔法方法__call 2.不定参数, 参数自动 ...

  4. js简单实现链式调用

    链式调用实现原理:对象中的方法执行后返回对象自身即可以实现链式操作.说白了就是每一次调用方法返回的是同一个对象才可以链式调用. js简单实现链式调用demo Object.prototype.show ...

  5. PHP中的__toString方法(实现JS里的链式操作)

    _toString方法是在打印对象时自动调用的魔术方法,如果不声明会报以下错 Catchable fatal error: Object of class String could not be co ...

  6. jQuery链式操作[转]

    用过jQuery的朋友都知道他强大的链式操作,方便,简洁,易于理解,如下 $("has_children").click(function(){ $(this).addClass( ...

  7. PHP链式操作输出excel(csv)

    工作中经常会遇到产品运营让导出一些简单的比较规范的数据,这时候要是有一个简单的方法可以用就简单多了.下面是我的一个输出简单的excel(csv)的方法类,用到了链式操作.说到链式操作,在jquery中 ...

  8. PHP 链式操作

    所谓链式操作最简单的理解就是 操作完毕之后再返回对象$this 想必大家工作中基本都快用烂了得东西. 下面就是一个链式操作MYSQL数据库类. 最常见的链式操作 每一个方法操作之后,返回一个对象,直到 ...

  9. jQery的链式操作和商城简易导航栏

    今天要记录的是jq的一些简单操作.项目的需求是做一个导航栏,单机不同的商品名称链接,显示相应的内容.用js来写的话相对代码量要多一些,选择jqrey一行则可以搞定,下面呢是我的代码和效果图 这个是初始 ...

随机推荐

  1. opencv源码:cascadedetect

    级联分类器检测类CascadeClassifier,提供了两个重要的方法: CascadeClassifier cascade_classifier; cascade_classifier.load( ...

  2. 跟我一起云计算(5)——Shards

    什么是sharding Sharding的基本思想就要把一个数据库切分成多个部分放到不同的数据库 (server)上,从而缓解单一数据库的性能问题.不太严格的讲,对于海量数据的数据库,如果是因为表多而 ...

  3. 深究标准IO的缓存

    前言 在最近看了APUE的标准IO部分之后感觉对标准IO的缓存太模糊,没有搞明白,APUE中关于缓存的部分一笔带过,没有深究缓存的实现原理,这样一本被吹上天的书为什么不讲透彻呢?今天早上爬起来赶紧找了 ...

  4. 神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观

    前言 哦,不搞SQL了么,当然会继续,周末会继续更新,估计写完还得几十篇,但是我会坚持把SQL更新完毕,绝不会烂尾,后续很长一段时间没更新的话,不要想我,那说明我是学习新的技能去了,那就是学习英语,本 ...

  5. SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

    Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少.但我 ...

  6. JQuery 复制粘贴上传图片插件(textarea 和 tinyMCE)

    开源地址:https://github.com/yuezhongxin/paste-upload-image.js 支持 Ctrl+C/Ctrl+V 上传,支持拖拽上传,也支持 QQ/微信截图上传. ...

  7. PHP的学习--RSA加密解密

    PHP服务端与客户端交互或者提供开放API时,通常需要对敏感的数据进行加密,这时候rsa非对称加密就能派上用处了. 举个通俗易懂的例子,假设我们再登录一个网站,发送账号和密码,请求被拦截了. 密码没加 ...

  8. 敏捷软件开发VS传统软件工程

    敏捷软件开发:又称敏捷开发,是一种从1990年代开始逐渐引起广泛关注的一些新兴软件开发方法,是一种应对快速变化的需求的一种软件开发能力. 与传统软件工程相比,它们的具体名称.理念.过程.术语都不尽相同 ...

  9. [DeviceOne开发]-do_LinearLayout组件使用技巧

    一.摘要 今天跟大家主要来介绍一下DeviceOne中的do_linearlayout这个布局,在DeviceOne开发中,do_linearlayout这个布局是相当重要. 现在给大家来总结一下. ...

  10. 2000条你应知的WPF小姿势 基础篇<28-33 WPF启动故事>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...