在php的面向对象里,用得最多的魔术方法一定是
__construct
方法。而在很多很多地方,__call
方法和__callStatic
方法用得地方一样很多,而且特别好用呢。下面举个应用的例子。
这里就拿yansongda pay
来举例子。这个是集成了微信和支付宝的支付相关的插件。
class Pay {
/**
* 定义Config配置.
*
* @var Config
*/
protected $config;
/**
* 构造.
*
* @param array $config
*/
public function __construct(array $config)
{
$this->config = new Config($config)
}
/**
* Magic static call.
*
* @param string $method
* @param array $params
*
* @return GatewayApplicationInterface
*/
public function __callStatic($method, $params)
{
$app = new self(...$params);
return $app->create($method);
}
/**
* Create a instance. 创建一个实例
*
* @param string $method
*
* @return GatewayApplicationInterface
*/
protected function create()
{
// 这里简化一下 注册日志就不写了
$gateway = __NAMESPACE__.'\\Gateways\\'.Str::studly($method);
if (class_exists($gateway)) {
return self::make($gateway);
}
throw new InvalidGatewayException("Gateway [{$method}] Not Exists");
}
/**
* Make a gateway. 实现一个支付入口
*
* @param string $gateway
*
* @return GatewayApplicationInterface
*/
protected function make($gateway)
{
$app = new $gateway($this->config);
if ($app instanceof GatewayApplicationInterface) {
return $app;
}
throw new InvalidGatewayException("Gateway [$gateway] Must Be An Instance Of GatewayApplicationInterface")
}
}
复制代码
上面就是一个比较完整的过程了。
这个名为class Pay
的很好起到了一个将不同的支付需求分发出去。
// 假设这里已经写好了Pay类的命名空间
// 如果是微信支付,那么可以这么写
$config = [
...
];
$wechat = Pay::Wechat($config) // 创建Wechat类的实例
// 如果是支付宝,那么..
$config = [
...
];
$alipay = Pay::Alipay($config) // 创建Alipay类的实例
复制代码
为什么可以达到这个效果呢,整个流程:
- 首先调用了Pay类的静态方法,比如是
Wechat
- 结果,没有找到,就会自动调用
class Pay
的__callStatic
魔术方法。 - 然后
new self(...$params)
这样就是为了调用后面的create($method)
,并且将传过来的$config
进行储存。 - 后面接着
create
方法里 找到对应的Wechat
类,并进行instanceof
判断。 - 最后在
make
方法里 实例化Wechat类
。
小总结:这样是为了对于有不同情况,想对它们进行清晰的分类,而实现的一个统一入口类Pay
。后面比如,alipay,肯定会涉及到移动端支付,PC网页支付,app支付各种情况。那么同样又可以使用这个方法,找到对应的类,进行实例化,调用方法。以后如果是自己封装方法,大家可以尝试效仿。
最后__call
方法其实和__callStatic
类似 只是用->
调用而已。