首页 > 开发 > PHP > 正文

PHP实现一个轻量级容器的方法

2024-05-04 22:41:22
字体:
来源:转载
供稿:网友

什么是容器

在开发过程中,经常会用到的一个概率就是依赖注入。我们借助依懒注入来解耦代码,选择性的按需加载服务,而这些通常都是借助容器来实现。

容器实现对类的统一管理,并且确保对象实例的唯一性

常用的容器网上有很多,如PHP-DI 、 YII-DI 等各种实现,通常他们要么大而全,要么高度适配特定业务,与实际需要存在冲突。

出于需要,我们自己造一个轻量级的轮子,为了保持规范,我们基于PSR-11 来实现。

PSR-11

PSR 是 php-fig 提供的标准建议,虽然不是官方组织,但是得到广泛认可。PSR-11 提供了容器接口。他包含 ContainerInterface 和 两个异常接口,提供使用建议。

/** * Describes the interface of a container that exposes methods to read its entries. */interface ContainerInterface{  /**   * Finds an entry of the container by its identifier and returns it.   *   * @param string $id Identifier of the entry to look for.   *   * @throws NotFoundExceptionInterface No entry was found for **this** identifier.   * @throws ContainerExceptionInterface Error while retrieving the entry.   *   * @return mixed Entry.   */  public function get($id);  /**   * Returns true if the container can return an entry for the given identifier.   * Returns false otherwise.   *   * `has($id)` returning true does not mean that `get($id)` will not throw an exception.   * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.   *   * @param string $id Identifier of the entry to look for.   *   * @return bool   */  public function has($id);}

实现示例

我们先来实现接口中要求的两个方法

abstract class AbstractContainer implements ContainerInterface{  protected $resolvedEntries = [];  /**   * @var array   */  protected $definitions = [];  public function __construct($definitions = [])  {    foreach ($definitions as $id => $definition) {      $this->injection($id, $definition);    }  }  public function get($id)  {    if (!$this->has($id)) {      throw new NotFoundException("No entry or class found for {$id}");    }    $instance = $this->make($id);    return $instance;  }  public function has($id)  {    return isset($this->definitions[$id]);  }

实际我们容器中注入的对象是多种多样的,所以我们单独抽出实例化方法。

public function make($name)  {    if (!is_string($name)) {      throw new /InvalidArgumentException(sprintf(        'The name parameter must be of type string, %s given',        is_object($name) ? get_class($name) : gettype($name)      ));    }    if (isset($this->resolvedEntries[$name])) {      return $this->resolvedEntries[$name];    }    if (!$this->has($name)) {      throw new NotFoundException("No entry or class found for {$name}");    }    $definition = $this->definitions[$name];    $params = [];    if (is_array($definition) && isset($definition['class'])) {      $params = $definition;      $definition = $definition['class'];      unset($params['class']);    }    $object = $this->reflector($definition, $params);    return $this->resolvedEntries[$name] = $object;  }  public function reflector($concrete, array $params = [])  {    if ($concrete instanceof /Closure) {      return $concrete($params);    } elseif (is_string($concrete)) {      $reflection = new /ReflectionClass($concrete);      $dependencies = $this->getDependencies($reflection);      foreach ($params as $index => $value) {        $dependencies[$index] = $value;      }      return $reflection->newInstanceArgs($dependencies);    } elseif (is_object($concrete)) {      return $concrete;    }  }  /**   * @param /ReflectionClass $reflection   * @return array   */  private function getDependencies($reflection)  {    $dependencies = [];    $constructor = $reflection->getConstructor();    if ($constructor !== null) {      $parameters = $constructor->getParameters();      $dependencies = $this->getParametersByDependencies($parameters);    }    return $dependencies;  }  /**   *   * 获取构造类相关参数的依赖   * @param array $dependencies   * @return array $parameters   * */  private function getParametersByDependencies(array $dependencies)  {    $parameters = [];    foreach ($dependencies as $param) {      if ($param->getClass()) {        $paramName = $param->getClass()->name;        $paramObject = $this->reflector($paramName);        $parameters[] = $paramObject;      } elseif ($param->isArray()) {        if ($param->isDefaultValueAvailable()) {          $parameters[] = $param->getDefaultValue();        } else {          $parameters[] = [];        }      } elseif ($param->isCallable()) {        if ($param->isDefaultValueAvailable()) {          $parameters[] = $param->getDefaultValue();        } else {          $parameters[] = function ($arg) {          };        }      } else {        if ($param->isDefaultValueAvailable()) {          $parameters[] = $param->getDefaultValue();        } else {          if ($param->allowsNull()) {            $parameters[] = null;          } else {            $parameters[] = false;          }        }      }    }    return $parameters;  }            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表