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)
内容版权声明:除非注明,否则皆为本站原创文章。
