php教程,如何利用魔术函数__call()生成梦幻链式调用?
发布于 作者:苏南大叔 来源:程序如此灵动~基于前面多篇文章的铺垫与总结,本文做一个综合的代码应用。实现的总目标是:实现类实例的梦幻链式调用。梦幻的意思是:类本身没有什么方法,就利用外部其它地方定义好的函数或者方法,来实现自身的功能。讲究的是一个资源整合。
苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的代码编程经验。本文测试环境:win10
,nginx@1.15.11
,php@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()
。做到这两点,就可以比较完美的实现链式调用了,参考文章:
内部__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
文章,请参考:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。