class DeferContainer extend BaseContainer { // 已绑定的回调函数 protected $bindings = []; // 绑定服务 public function bind($name, $instance) { if ($instance instanceof Closure) { // 如果$instance是一个回调函数,就绑定到bindings。 $this->bindings[$name] = $instance; } else { // 调用make方法,创建实例 $this->instances[$name] = $this->make($name); } } // 获取服务 public function make($name) { if (isset($this->instances[$name])) { return $this->instances[$name]; } if (isset($this->bindings[$name])) { // 执行回调函数并返回 $instance = call_user_func($this->bindings[$name]); } else { // 还没有绑定到容器中,直接new. $instance = new $name(); } return $instance; } } // ----------- ↓↓↓↓示例代码↓↓↓↓ ----------- // $container = new DeferContainer(); // 绑定服务 $container->bind('StdClass', function () { echo "我被执行了\n"; return new StdClass(); }); // 获取服务 $stdClass = $container->make('StdClass'); var_dump($stdClass);
StdClass这个服务绑定的是一个回调函数,在回调函数中才会真正的实例化类。如果没有用到这个服务,那回调函数就不会被执行,类也不会被实例化。
4. 单例
从上面的代码中可以看出,每次调用make方法时,都会执行一次回调函数,并返回一个新的类实例。但是在某些情况下,我们希望这个实例是一个单例,无论make多少次,只实例化一次。
这时候,我们给bind方法增加第三个参数$shared,用来标记是否是单例,默认不是单例。然后把回调函数和这个标记都存到$bindings数组里。
为了方便绑定单例服务,再增加一个新的方法singleton,它直接调用bind,并且$shared参数强制为true。
对于make方法,我们也要做修改。在执行$bindings里的回调函数以后,做一个判断,如果之前绑定时标记的shared是true,就把回调函数返回的结果存储到$instances里。由于我们是先从$instances里找服务,所以这样下次再make的时候就会直接返回,而不会再次执行回调函数。这样就实现了单例的绑定。
class SingletonContainer extends DeferContainer { // 绑定服务 public function bind($name, $instance, $shared = false) { if ($instance instanceof Closure) { // 如果$instance是一个回调函数,就绑定到bindings。 $this->bindings[$name] = [ 'callback' => $instance, // 标记是否单例 'shared' => $shared ]; } else { // 调用make方法,创建实例 $this->instances[$name] = $this->make($name); } } // 绑定一个单例 public function singleton($name, $instance) { $this->bind($name, $instance, true); } // 获取服务 public function make($name) { if (isset($this->instances[$name])) { return $this->instances[$name]; } if (isset($this->bindings[$name])) { // 执行回调函数并返回 $instance = call_user_func($this->bindings[$name]['callback']); if ($this->bindings[$name]['shared']) { // 标记为单例时,存储到服务中 $this->instances[$name] = $instance; } } else { // 还没有绑定到容器中,直接new. $instance = new $name(); } return $instance; } } // ----------- ↓↓↓↓示例代码↓↓↓↓ ----------- // $container = new SingletonContainer(); // 绑定服务 $container->singleton('anonymous', function () { return new class { public function __construct() { echo "我被实例化了\n"; } }; }); // 无论make多少次,只会实例化一次 $container->make('anonymous'); $container->make('anonymous'); // 获取服务 $anonymous = $container->make('anonymous'); var_dump($anonymous)
内容版权声明:除非注明,否则皆为本站原创文章。