什么是容器

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

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

常用的容器网上有很多,如 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;}

如你所见,到目前为止我们只实现了从容器中取出实例,从哪里去提供实例定义呢,所以我们还需要提供一个方水法

/*** @param string $id* @param string | array | callable $concrete* @throws ContainerException*/public function injection($id, $concrete){if (is_array($concrete) && !isset($concrete['class'])) {throw new ContainerException('数组必须包含类定义');}$this->definitions[$id] = $concrete;}

只有这样吗?对的,有了这些操作我们已经有一个完整的容器了,插箱即用。

不过为了使用方便,我们可以再提供一些便捷的方法,比如数组式访问。

class Container extends AbstractContainer implements ArrayAccess
{public function offsetExists($offset){return $this->has($offset);}public function offsetGet($offset){return $this->get($offset);}public function offsetSet($offset, $value){return $this->injection($offset, $value);}public function offsetUnset($offset){unset($this->resolvedEntries[$offset]);unset($this->definitions[$offset]);}
}

这样我们就拥有了一个功能丰富,使用方便的轻量级容器了。

以上内容希望帮助到大家,很多PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要请戳这里链接 或 者关注咱们下面的知乎专栏

PHP架构师圈子​zhuanlan.zhihu.com

yii验证在一个数组内_PHP实现一个轻量级容器相关推荐

  1. 在一个数组中删除另一个数组存在的值

    在一个数组中删除另一个数组存在的值 可以在购物车中删除多个商品的时候用此方法 在Vuex实现完整购物车中有涉及,详见 Vuex实现完整购物车 <script type="text/ja ...

  2. PHP实现一个轻量级容器

    什么是容器 在开发过程中,经常会用到的一个概念就是依赖注入.我们借助依懒注入来解耦代码,选择性的按需加载服务,而这些通常都是借助容器来实现. 容器实现对对象的统一管理,并且确保对象实例的唯一性 容器可 ...

  3. JavaScript在一个数组中插入另一个数组

    //原数组 var a = [3,4]; //要插入的数组 var b = [1,2]; //要插入的位置 var i = 1; //插入 a.splice(i,0,...b); //结果 a = [ ...

  4. LeetCode:Find Peak Element - 寻找一个数组内的顶点

    2019独角兽企业重金招聘Python工程师标准>>> 1.题目名称 Find Peak Element(寻找一个数组内的顶点) 2.题目地址 https://leetcode.co ...

  5. MATLAB 在一个数组中随机选择n个数

    MATLAB 中在一个数组内随机选择n个数. 例如:在 A = [10, 50, 80, 100, 130, 260] 中随机选择5个数. 允许重复: n = 5; A = [10, 50, 80, ...

  6. Java 判断一个点是否在一个三角形内

    题目描述:   如何判断一个点是否在一个三角形内. 测试样例: 自定义的POINT类: class POINT{int x;int y;public POINT(int x,int y){this.x ...

  7. 能否构成三角形的条件代码_Java 如何判断一个点是否在一个三角形内

    题目描述: 如何判断一个点是否在一个三角形内. 测试样例: 自定义的POINT类: class POINT{ int x; int y; public POINT(int x,int y){ this ...

  8. python多层数组合成一个数组后循环打印出数组内的每一项元素的方法

    a=[1,2,3,4] b=[5,6,7,8] c=[a,b] def test(c):for i in c:return i print(test(c)) 以上代码执行后打印出来的结果是 预期目标是 ...

  9. php 数组合并字符,PHP将字符串或数组合并到一个数组内方法

    本文主要和大家分享PHP将字符串或数组合并到一个数组内方法,有两种方法,希望希望能帮助到大家. 一般写法:<?php /** * add a string or an array to anot ...

  10. [js] 写一个方法判断数组内元素是否全部相同

    [js] 写一个方法判断数组内元素是否全部相同 const isSameArray = function (array) {if (Array.isArray(array)) {return new ...

最新文章

  1. Ubuntu(Linux) 下 unzip 命令使用详解
  2. mysql中标记某条数据库_一个关系数据库表中的各条记录可以什么
  3. 国内首次 Istio Meetup 来了,主流社区专家邀你来共聊
  4. 【前端框架-Vue-基础】$attr及$listeners实现跨多级组件的通信
  5. python分句_Python循环中的分句,继续和其他子句
  6. 【转】SharePoint 编程指南
  7. 【python】 合并列表的方法
  8. python推导式pythonic必备
  9. Bootstrap 字体与图标
  10. 接管客厅第一步:联想智能音箱体验评测
  11. 替代传统C/S和B/S技术的下一代客户/服务器编程技术
  12. idea 社区教育版需要安装的插件
  13. 爆干3天整理出来,408考研计算机网络复习笔记(更新中)
  14. 《卓有成效的管理者》读书笔记
  15. 【AI视野·今日CV 计算机视觉论文速览 第220期】Wed, 16 Jun 2021
  16. 基于MATLAB的单相电压型逆变电路,基于MatlabSimulink_的电压型单相全桥逆变电路.doc...
  17. SpaceEye :12种地球实时卫星照片壁纸
  18. minus的用法简介
  19. c# 讯飞语音 sdk
  20. 计算机都学什么数学,计算机专业的数学应学到什么水平?应该学习数学的那些分支?...

热门文章

  1. 网页选项卡应用4-12
  2. Confluence 6 数据库 JDBC 驱动
  3. 紫书 习题 8-2 UVa 1610 (暴力出奇迹)
  4. C语言的隐式类型转换
  5. 【CSS系列】获取实时数据做进度
  6. mysql mmm安装管理详解
  7. uni-app多端开发,问题总结
  8. Jenkins配置Android自动打包传蒲公英功能
  9. flutter的四种模式/application/plugin/package/module,flutter调用原生的方法
  10. 2021年河北高考生成绩排名查询,2021年河北省高考报名人数、录取分数线、河北省最好大学排名统计[图]...