lumen容器模仿
<?php
class Container { private $bindings = [];
private $instances = []; public function getClosure($concrete) {
return function($parameter = []) use($concrete) { # 在这里我们找到了判断初始化函数的契机,利用反射我们可以做很多事,包括我们的问题
# 1.获得一个$concrete类反射
$reflector = new ReflectionClass($concrete);
# 2.判断这个类能否被实例化,例如 private function __construct(){}
if(!$reflector->isInstantiable()) {
throw new Exception("{$concrete} 无法被实例化");
} # 3.获取构造函数反射方法
$constructor = $reflector->getConstructor(); # 4.获取参数列表
$parameters = $constructor->getParameters(); # 5.遍历参数列表
$instancesParams = [];
foreach ($parameters as $_parameter) {
# 如果已经$parameter中已经设置了对应的参数
if(isset($parameter[$_parameter->name])) {
$instancesParams[] = $parameter[$_parameter->name];
continue;
} # 如果没设置判断一下这个参数是否存在默认值
if(!$_parameter->isDefaultValueAvailable()) {
throw new Exception("{$concrete} 无法被实例化,缺少参数{$_parameter->name}");
} $instancesParams[] = $_parameter->getDefaultValue();
} # 这里就需要通过反射来构建对象了
// return new $concrete($parameter);
return $reflector->newInstanceArgs($instancesParams);
};
} public function bind($abstract , $concrete=null, $shared = false)
{
if (is_null($concrete)) {
$concrete = $abstract;
} if (!$concrete instanceof Closure) {
$concrete = $this->getClosure($concrete);
} $this->bindings[$abstract] = [
'concrete' => $concrete,
'shared' => $shared
];
} public function make($abstract ,array $parameters = []) {
if (!isset($this->bindings[$abstract])) {
return false;
} if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
} # 先获取到具体的类型
$concrete = $this->bindings[$abstract]['concrete'];
# 这里需要思考一下
# 到目前为止我们的$this->bindings[$abstract]['concrete']里存储的都是通过getClosure方法生成的闭包。
# 那么直接在这里判断类型肯定行不通,所以我们跳到getClosure里面去看看
$object = $concrete($parameters);
if($this->bindings[$abstract]['shared']) {
$this->instances[$abstract] = $object;
} return $object;
}
} class Person{
private $name;
private $isProgrammer;
public function __construct($name,$isProgrammer = true) {
$this->name = $name;
$this->isProgrammer = $isProgrammer;
} public function me() {
$message = $this->isProgrammer ? ',Ta是一个程序员' :'';
return "姓名: {$this->name} $message";
}
}
$container = new Container();
$container->bind('Person',null,false);
$p1 = $container->make('Person',[
'name' => 'lilei',
'age'=>10
]); $p2 = $container->make('Person',[
'name' => 'zhangsan',
'age'=>10
]); echo $p1->me();
echo $p2->me(); var_dump($p1,$p2);
var_dump($p1 === $p2);
lumen容器模仿的更多相关文章
- lumen-ioc容器测试 (2)
lumen-ioc容器测试 (1) lumen-ioc容器测试 (2) lumen-ioc容器测试 (3) lumen-ioc容器测试 (4) lumen-ioc容器测试 (5) lumen-ioc容 ...
- Lumen开发:如何向 IoC 容器中添加自己定义的类
版权声明:本文为博主原创文章,未经博主允许不得转载. 先在起始文件bootstrap/app.php加上$app->register(App\Providers\User\UserService ...
- [转贴]从零开始学C++之STL(二):实现一个简单容器模板类Vec(模仿VC6.0 中 vector 的实现、vector 的容量capacity 增长问题)
首先,vector 在VC 2008 中的实现比较复杂,虽然vector 的声明跟VC6.0 是一致的,如下: C++ Code 1 2 template < class _Ty, cl ...
- Java入门记(四):容器关系的梳理(上)——Collection
目录 一.Collection及子类/接口容器继承关系 二.List 2.1 ArrayList 2.1.1 序列化的探讨 2.1.2 删除元素 2.1.3 调整大小 2.2 Vector和Stack ...
- 整合Servlet到Spring容器
有时在Spring(3.2.5)项目中,如果使用到Servlet,可能希望Servlet实例作为bean受Spring容器管理,这样也能自动注入其他需要的bean,查了下,发现只针对过滤器提供了代理类 ...
- Java集合容器简介
Java集合容器主要有以下几类: 1,内置容器:数组 2,list容器:Vetor,Stack,ArrayList,LinkedList, CopyOnWriteArrayList(1.5),Attr ...
- Swing 顶层容器
顶层容器值得是容纳其他容器的容器组件,包括JFrame类,JWindows类,JDialog类,JApplet等.Swing中的顶层容器类Swing提供三个顶层容器类:JFrame,JDialog和J ...
- Cocos2d-x中__Dictionary容器以及实例介绍
__Dictionary类在Cocos2d-x 2.x时代它就是CCDictionary类,它是模仿Objective-C中的NSDictionary类而设计的,通过引用计数管理内存.__Dictio ...
- Cocos2d-x中Vector<T>容器以及实例介绍
Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容纳的是Ref及子类所创建的对象指针,其中的T是模板,表示能够放入到容器中的类型,在Cocos2d-x 3.x中T ...
随机推荐
- SpringBoot版不需要配置文件注解获取当前登录用户
本文讯(2019年3月30日 飞快的蜗牛博客) 我是一个懒人,很久不写博客,想起来看到也不一定会写,只有心血来潮的时候写写,"钱塘江上潮信来,今日方知我是我"...... 空杯 ...
- Playbook使用,编写YAML
YAML是什么? YAML是一个可读性高.用来表达数据序列的格式语言 YAML:YAML Ain't a Markup Language YAML以数据为中心,重点描述数据的关系和结构 YAML的格式 ...
- robotframework安装与运行(ride.py1.7.4.2命令报错)(win10+python3.8.1)
首先,robotframework必须在python的环境下运行 所以你的电脑里必须有python3.x的环境先. 上古时期的robotframework只支持python2,不过python2都已经 ...
- python3 while循环
python不支持n++这样格式,因为python中变量不像c那样事先定义好变量类型,在内存中开辟指定的空间,然后赋值. python中以字符串为例,事先在内存划分空间来存放字符串,然后用变量名来指向 ...
- 【Flutter 实战】路由堆栈详解
老孟导读:Flutter中路由是非常重要的部分,任何一个应用程序都离不开路由管理,此文讲解路由相关方法的使用和路由堆栈的变化. Flutter 路由管理中有两个非常重要的概念: Route:路由是应用 ...
- 分别用canvas和css3的transform做出钟表的效果
两种方式实际上在js上的原理都是一样的.都是获取时间对象,再获取时间对象的时分秒,时分秒乘以其旋转一刻度(一秒.一分.一小时)对应的角度.css3中要赋值于transform:rotate(角度),c ...
- spring boot 源码之SpringBootExceptionReporter
SpringBootExceptionReporter 用户自定义异常处理回调接口. public interface SpringBootExceptionReporter { boolean re ...
- java执行器
Executor 执行已提交的 Runnable 任务对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.Executor 接口并没有严格地要求执行是 ...
- tf.split函数的用法(tensorflow1.13.0)
tf.split(input, num_split, dimension): dimension指输入张量的哪一个维度,如果是0就表示对第0维度进行切割:num_split就是切割的数量,如果是2就表 ...
- 性能测试Jmeter安装
一. Jmeter下载地址: http://jmeter.apache.org/download_jmeter.cgi 二. JDK下载地址: https://www.oracle.com/tec ...