<?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 完美的支持反射机制!