<?php
// 定下了一个接口 (超能力模组的规范、契约),所有被创造的模组必须遵守该规范,才能被生产。
interface SuperModuleInterface
{
/**
* 超能力激活方法
*
* 任何一个超能力都得有该方法,并拥有一个参数
*@param array $target 针对目标,可以是一个或多个,自己或他人
*/
public function activate(array $target);
}
/**
* 发射X-超能量(对超能力的具体实现)
*/
class XPower implements SuperModuleInterface
{
public function activate(array $target = [])
{
return '发射X-超能量';
}
}
/**
* 发射终极炸弹 (对超能力的具体实现)
*/
class UltraBomb implements SuperModuleInterface
{
public function activate(array $target = [])
{
return '发射终极炸弹';
}
}
//生产超人,使其携带能力
class Superman
{
protected $module;
// 初始化 “超人” 类的时候,提供的模组实例必须是一个 SuperModuleInterface 接口的实现。否则就会提示错误。
public function __construct(SuperModuleInterface $module)
{
$this->module = $module;
echo $this->module->activate();
}
}
// 工厂模式的升华 —— IoC 容器:通过指令自动化生产
class Container
{
protected $binds;
protected $instances;
/**
* 向 超级工厂 注册了一些生产脚本
* @param $abstract简称
* @param $concrete可以被执行的回调(可以是匿名函数、非匿名函数、类的方法)作为生产一个类的实例的 脚本
*/
public function bind($abstract, $concrete)
{
// instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例:
// Closure类,也就是闭包类,php中,闭包都是Closure类的实例
// instanceof Closure 判断是否属于闭包类
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
// 开始生产bind()注册的脚步
public function make($abstract, $parameters = [])
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
// array_unshift() 函数用于向数组插入新元素。新数组的值将被插入到数组的开头。
// $this 值本类,此时的$parameters数组下标为0的参数是本类。下标为1的参数是传入的参数
array_unshift($parameters, $this);
// call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数,
// 回调函数的第一个参数为$parameters[0],也就是本类,第二个参数是传入的参数
return call_user_func_array($this->binds[$abstract], $parameters);
}
}
// 创建一个容器(后面称作超级工厂)
$container = new Container;
// 向该 超级工厂 添加 超人 的生产脚本
$container->bind('superman', function($container, $moduleName) {
return new Superman($container->make($moduleName));
});
// 向该 超级工厂 添加 超能力模组 的生产脚本
$container->bind('xpower', function($container) {
return new XPower;
});
// 同上
$container->bind('ultrabomb', function($container) {
return new UltraBomb;
});
// ****************** 华丽丽的分割线 **********************
// 开始启动生产
$superman_1 = $container->make('superman', ['xpower']);
$superman_2 = $container->make('superman', ['ultrabomb']);
// 我们通过注册、绑定的方式向容器中添加一段可以被执行的回调(可以是匿名函数、非匿名函数、类的方法)作为生产一个类的实例的 脚本 ,只有在真正的 生产(make) 操作被调用执行时,才会触发。
// 实际上,真正的 IoC 容器更为高级。我们现在的例子中,还是需要手动提供超人所需要的模组参数,但真正的 IoC 容器会根据类的依赖需求,自动在注册、绑定的一堆实例中搜寻符合的依赖需求,并自动注入到构造函数参数中去。Laravel 框架的服务容器正是这么做的。这种自动搜寻依赖需求的功能,是通过 反射(Reflection) 实现的,php 完美的支持反射机制!