<?php class Container { private $bindings = []; private $instances = []; public function getClosure($concrete) { return function($parameter = []) use($concrete) { # 在这里我们找到了判断初始化函数的契机,利用反射我们可以做很多事,包括我们的问题 # 1.获得一个$concrete类反射 $reflector = new ReflectionClass($concrete); # 2.判断这个类能否被实例化,例如 private function __construct(){} if(!$reflector->isInstantiable()) { throw new Exception("{$concrete} 无法被实例化"); } # 3.获取构造函数反射方法 $constructor = $reflector->getConstructor(); # 4.获取参数列表 $parameters = $constructor->getParameters(); # 5.遍历参数列表 $instancesParams = []; foreach ($parameters as $_parameter) { # 如果已经$parameter中已经设置了对应的参数 if(isset($parameter[$_parameter->name])) { $instancesParams[] = $parameter[$_parameter->name]; continue; } # 如果没设置判断一下这个参数是否存在默认值 if(!$_parameter->isDefaultValueAvailable()) { throw new Exception("{$concrete} 无法被实例化,缺少参数{$_parameter->name}"); } $instancesParams[] = $_parameter->getDefaultValue(); } # 这里就需要通过反射来构建对象了 // return new $concrete($parameter); return $reflector->newInstanceArgs($instancesParams); }; } public function bind($abstract , $concrete=null, $shared = false) { if (is_null($concrete)) { $concrete = $abstract; } if (!$concrete instanceof Closure) { $concrete = $this->getClosure($concrete); } $this->bindings[$abstract] = [ 'concrete' => $concrete, 'shared' => $shared ]; } public function make($abstract ,array $parameters = []) { if (!isset($this->bindings[$abstract])) { return false; } if (isset($this->instances[$abstract])) { return $this->instances[$abstract]; } # 先获取到具体的类型 $concrete = $this->bindings[$abstract]['concrete']; # 这里需要思考一下 # 到目前为止我们的$this->bindings[$abstract]['concrete']里存储的都是通过getClosure方法生成的闭包。 # 那么直接在这里判断类型肯定行不通,所以我们跳到getClosure里面去看看 $object = $concrete($parameters); if($this->bindings[$abstract]['shared']) { $this->instances[$abstract] = $object; } return $object; } } class Person{ private $name; private $isProgrammer; public function __construct($name,$isProgrammer = true) { $this->name = $name; $this->isProgrammer = $isProgrammer; } public function me() { $message = $this->isProgrammer ? ',Ta是一个程序员' :''; return "姓名: {$this->name} $message"; } } $container = new Container(); $container->bind('Person',null,false); $p1 = $container->make('Person',[ 'name' => 'lilei', 'age'=>10 ]); $p2 = $container->make('Person',[ 'name' => 'zhangsan', 'age'=>10 ]); echo $p1->me(); echo $p2->me(); var_dump($p1,$p2); var_dump($p1 === $p2);