我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

基于前面多篇文章的铺垫与总结,本文做一个综合的代码应用。实现的总目标是:实现类实例的梦幻链式调用。梦幻的意思是:类本身没有什么方法,就利用外部其它地方定义好的函数或者方法,来实现自身的功能。讲究的是一个资源整合。

苏南大叔:php教程,如何利用魔术函数__call()生成梦幻链式调用? - 梦幻链式调用
php教程,如何利用魔术函数__call()生成梦幻链式调用?(图2-1)

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的代码编程经验。本文测试环境:win10nginx@1.15.11php@8.2.10-nts

前文回顾

在前面的文章里面,苏南大叔描述了:类访问“不能访问的方法”的魔术方法:__call()__callStatic()。这就是本文的核心技术点之一,可以说是万能被调用者。参考文章:
https://newsn.net/say/php-class-call.html

接收到目标函数名和参数后,需要正确的处理它。这里就使用了call_user_func()或者call_user_func_array(),将需求处理的过程转向真正有能力处理它们的函数或方法。参考文章:

新的问题来了,传递的函数(或者说带命名方法的类方法)是可以明确的,但是,传递的参数(个数)可能就不明确了。这里就需要一些万能的参数接收函数了,比如:func_get_args()。参考文章:

万能的接收函数接收到的是个数组,而普通函数接收参数的时候,是一个一个接收的,而不是这种打包的方式。所以,这里需要一个解包的操作,也就是...操作。参考文章:

对于做链式调用这个需求来说,主要需要一个return $this和一个function getResult()。做到这两点,就可以比较完美的实现链式调用了,参考文章:

苏南大叔:php教程,如何利用魔术函数__call()生成梦幻链式调用? - 梦幻链式调用代码
php教程,如何利用魔术函数__call()生成梦幻链式调用?(图2-2)

内部__callStatic

__callStaic()这部分,并不是做链式调用所必须的部分。因为静态方法里面没有$this,所以无法返回$this,因此__callStaic()并不能构成链式调用的一部分。
一个__call()就足够做链式调用了。但是,本文为了演示需要,这里生生的造出了这个__callStaic()的需求。

class SN
{
    // ...
    private $who = "sunan";
    private static $who_ = "sunan";
    public function __construct($who)
    {
        $this->who = $who;
    }
    public static function __callStatic($func, $args)
    {
        array_unshift($args, self::$who_);
        self::$who_ = call_user_func_array($func, $args);
    }
    // ...
}

值得特别说明的是:调用外部函数的方法,这里使用了call_user_func_array()。下面的__call()里面,使用的是call_user_func(),两者的效果是一致的。

内部__call实现链式调用

__call()这个魔术方法是非常重要的,就是在这里实现了各种不存在方法的调用,并且实现了链式调用最关键的一步return $this的。

class SN
{
    private $result;
    // ...
    public function __call($func, $args)
    {
        $this->result .= call_user_func($func, $this->who, ...$args);
        return $this;
    }
    public function getResult()
    {
        $this->result = str_replace($this->who, self::$who_ , $this->result);
        return $this->result;
    }
}

外部函数

这里写了两个外部函数,其实函数叫什么,有多少参数,实现什么样的逻辑,这些都是并不重要的。其实就是配置__call()里面的call_user_func()函数的。

被调用了不存在的方法?那就调用一个外部函数试试?
function buildWho($name, $plus, $plus2)
{
    var_dump(func_get_args());
    return "{$name}{$plus}{$plus2}";
}
function atSchool($who, $atSchool, $plus)
{
    return "{$who},在{$atSchool}学习{$plus}。";
}
function atUniversity()
{
    return atSchool(...func_get_args());
}

最终调用代码

需要明确的是:链式调用的关键点是$this。那么,静态方法因为并不存在上下文,所以并不会参与到链式调用中来。

$me = new SN("苏南");
$me::who("大", "叔");
echo $me->school('北京小学', "绘画")->school('北京中学', "英语")->university('北京大学', "计算机")->getResult();

输出:

array(3) {
  [0]=>
  string(5) "sunan"
  [1]=>
  string(3) "大"
  [2]=>
  string(3) "叔"
}
sunan大叔,在北京小学学习绘画。sunan大叔,在北京中学学习英语。sunan大叔,在北京大学学习计算机。

结束语

本文纯粹是为了使用这些代码技巧拼凑的代码,合适不合适的还请大家分析着使用。更多苏南大叔的php文章,请参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   php