php容器
可以理解为一个盒子,事先将项目中可能用到的类扔进去,在项目中直接从容器中拿,也就是避免了直接在项目中到处new,造成大量耦合。取而代之的是在项目类里面增设setDi、getDi方法,通过Di(依赖注入)统一管理类。
1.定义了一个存储接口,以及两个类实现
1.定义了一个存储接口,以及两个类实现
<?php interface Storage{ public function open(); } class DatabaseStorage implements Storage { public function open() { echo 'open db Storage'; } } class FileStorage implements Storage { public function open() { echo 'open file Storage'; } }
2.创建一个容器
// 容器 class Container { protected $binds; // 绑定闭包 protected $instances; // 绑定实例 /** * 向容器中注册服务 * * @param $abstract 服务名称 * @param $conctete 服务体 */ public function bind($abstract, $concrete) { // 如果是个闭包则绑定到binds中 if ($concrete instanceof Closure) { $this->binds[$abstract] = $concrete; } else { // 否则绑定到实例数组中 $this->instances[$abstract] = $concrete; } } /** * 从容器中获取服务 * * @param $abstract 服务名称 * @param $params 实例化服务所需要传递的参数 */ public function make($abstract, $params = []) { // 如果是个实例就返回这个实例 if (isset($this->instances[$abstract])) { return $this->instances[$abstract]; } array_unshift($params, $this); // 返回闭包执行结果 return call_user_func_array($this->binds[$abstract], $params); } }
3.使用容器,注册服务到容器中,并拿出来使用
$Container = new Container; // 把名称为FileStorage,内容为闭包的服务,注册到容器 $Container->bind('FileStorage', function($Container) { return new FileStorage; }); // 把名称为DatabaseStorage,内容为DatabaseStorage实例的服务注册到容器 $Container->bind('DatabaseStorage', new DatabaseStorage); // 从容器获取服务并使用 $FileStorage = $Container->make('FileStorage'); $FileStorage->open(); // open file Storage $DatabaseStorage = $Container->make('DatabaseStorage'); $DatabaseStorage->open(); // open db Storage
4.容器的另外两种实现方式
通过魔术方法实现
class MagicContainer{ private $ele; function __construct() { $this->ele = []; } function __set($name, $value) { $this->ele[$name] = $value; } function __get($name) { return $this->ele[$name]; } function __isset($name) { return isset($this->ele[$name]); } function __unset($name) { if(isset($this->ele[$name])){ unset($this->ele[$name]); } } } $container = new MagicContainer(); $container->logger = function ($msg){ file_put_contents('info.log',$msg.PHP_EOL,FILE_APPEND); }; $logger = $container->logger; $logger('magic container works');
通过ArrayAccess接口实现
class ArrayContainer implements ArrayAccess { private $elements; public function __construct() { $this->elements = []; } public function offsetExists($offset){ return isset($this->elements[$offset]); } public function offsetGet($offset){ if($this->offsetExists($offset)){ return $this->elements[$offset]; }else{ return false; } } public function offsetSet($offset, $value){ $this->elements[$offset] = $value; } public function offsetUnset($offset){ if($this->offsetExists($offset)){ unset($this->elements[$offset]); } } } $container = new ArrayContainer(); $container['logger'] = function ($msg){ file_put_contents('info.log',$msg.PHP_EOL,FILE_APPEND); }; $logger = $container['logger']; $logger('array container works');