1. <?php
    2. // 定下了一个接口 (超能力模组的规范、契约),所有被创造的模组必须遵守该规范,才能被生产。
    3. interface SuperModuleInterface
    4. {
    5. /**
    6. * 超能力激活方法
    7. *
    8. * 任何一个超能力都得有该方法,并拥有一个参数
    9. *@param array $target 针对目标,可以是一个或多个,自己或他人
    10. */
    11. public function activate(array $target);
    12. }
    13. /**
    14. * 发射X-超能量(对超能力的具体实现)
    15. */
    16. class XPower implements SuperModuleInterface
    17. {
    18. public function activate(array $target = [])
    19. {
    20. return '发射X-超能量';
    21. }
    22. }
    23. /**
    24. * 发射终极炸弹 (对超能力的具体实现)
    25. */
    26. class UltraBomb implements SuperModuleInterface
    27. {
    28. public function activate(array $target = [])
    29. {
    30. return '发射终极炸弹';
    31. }
    32. }
    33. //生产超人,使其携带能力
    34. class Superman
    35. {
    36. protected $module;
    37. // 初始化 “超人” 类的时候,提供的模组实例必须是一个 SuperModuleInterface 接口的实现。否则就会提示错误。
    38. public function __construct(SuperModuleInterface $module)
    39. {
    40. $this->module = $module;
    41. echo $this->module->activate();
    42. }
    43. }
    44. // 工厂模式的升华 —— IoC 容器:通过指令自动化生产
    45. class Container
    46. {
    47. protected $binds;
    48. protected $instances;
    49. /**
    50. * 向 超级工厂 注册了一些生产脚本
    51. * @param $abstract简称
    52. * @param $concrete可以被执行的回调(可以是匿名函数、非匿名函数、类的方法)作为生产一个类的实例的 脚本
    53. */
    54. public function bind($abstract, $concrete)
    55. {
    56. // instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例:
    57. // Closure类,也就是闭包类,php中,闭包都是Closure类的实例
    58. // instanceof Closure 判断是否属于闭包类
    59. if ($concrete instanceof Closure) {
    60. $this->binds[$abstract] = $concrete;
    61. } else {
    62. $this->instances[$abstract] = $concrete;
    63. }
    64. }
    65. // 开始生产bind()注册的脚步
    66. public function make($abstract, $parameters = [])
    67. {
    68. if (isset($this->instances[$abstract])) {
    69. return $this->instances[$abstract];
    70. }
    71. // array_unshift() 函数用于向数组插入新元素。新数组的值将被插入到数组的开头。
    72. // $this 值本类,此时的$parameters数组下标为0的参数是本类。下标为1的参数是传入的参数
    73. array_unshift($parameters, $this);
    74. // call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数,
    75. // 回调函数的第一个参数为$parameters[0],也就是本类,第二个参数是传入的参数
    76. return call_user_func_array($this->binds[$abstract], $parameters);
    77. }
    78. }
    79. // 创建一个容器(后面称作超级工厂)
    80. $container = new Container;
    81. // 向该 超级工厂 添加 超人 的生产脚本
    82. $container->bind('superman', function($container, $moduleName) {
    83. return new Superman($container->make($moduleName));
    84. });
    85. // 向该 超级工厂 添加 超能力模组 的生产脚本
    86. $container->bind('xpower', function($container) {
    87. return new XPower;
    88. });
    89. // 同上
    90. $container->bind('ultrabomb', function($container) {
    91. return new UltraBomb;
    92. });
    93. // ****************** 华丽丽的分割线 **********************
    94. // 开始启动生产
    95. $superman_1 = $container->make('superman', ['xpower']);
    96. $superman_2 = $container->make('superman', ['ultrabomb']);
    97. // 我们通过注册、绑定的方式向容器中添加一段可以被执行的回调(可以是匿名函数、非匿名函数、类的方法)作为生产一个类的实例的 脚本 ,只有在真正的 生产(make) 操作被调用执行时,才会触发。
    98. // 实际上,真正的 IoC 容器更为高级。我们现在的例子中,还是需要手动提供超人所需要的模组参数,但真正的 IoC 容器会根据类的依赖需求,自动在注册、绑定的一堆实例中搜寻符合的依赖需求,并自动注入到构造函数参数中去。Laravel 框架的服务容器正是这么做的。这种自动搜寻依赖需求的功能,是通过 反射(Reflection) 实现的,php 完美的支持反射机制!