服务容器是一个用于管理类依赖和执行依赖注入的强大工具。

一个类要被容器所能够提取,必须要先注册至这个容器。既然称这个容器叫做服务容器,那么我们需要某个服务,就得先注册、绑定这个服务到容器,那么提供服务并绑定服务至容器的东西就是服务提供器(ServiceProvider)。

依赖注入和控制反转是对同一件事情的不同描述,它们描述的角度不同。依赖注入是从应用程序的角度在描述,应用程序依赖容器创建并注入它所需要的外部资源。而控制反转是从容器的角度在描述,容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

<?php

/**
* Interface Log
* 面向接口编程
*/
interface Log
{
public function write();
} class FileLog implements Log
{
public function write()
{
echo 'filelog write...' . PHP_EOL;
}
} class DataBaseLog implements Log
{
public function write()
{
echo 'dblog write...' . PHP_EOL;
}
} /**
* Class Request
* 模拟请求类
*/
class Request
{
public function toArray()
{
return ['name' => 'value'];
}
} /**
* User类依赖Log接口的实现
*/
class User
{
private $log;
private $extra; public function __construct(Log $log, $a, $b, $c = '默认参数')
{
$this->log = $log;
$this->extra = compact('a', 'b', 'c');
} /**
* 模拟用户登录写入登录日志
*/
public function login(Request $request)
{
echo '接收登录请求的参数json:' . json_encode($request->toArray()) . PHP_EOL;
echo 'user log success...' . PHP_EOL;
$this->log->write();
} public function getExtra()
{
var_dump($this->extra);
}
} /**
* Class Ioc
* 模拟IoC容器
* 类从注册到实例化,最终被我们所使用,都是服务容器负责
*/
class Ioc
{
protected $bindings = [];
protected $instances = [];
protected static $ioc; protected function __construct()
{
} public static function getInstance()
{
if (is_null(self::$ioc)) {
self::$ioc = new self();
}
return self::$ioc;
} /**
* 注册绑定 (绑定自身、闭包、接口)
* 也就是服务
* @param $abstract
* @param null $concrete
* @param bool $share
*/
public function bind($abstract, $concrete = null, $share = true)
{
if (is_null($concrete)) {
$concrete = $abstract;
}
$this->bindings[$abstract]['share'] = $share;
if ($concrete instanceof Closure) {
$this->bindings[$abstract]['concrete'] = $concrete;
} else {
$this->bindings[$abstract]['concrete'] = function (Ioc $ioc, $vars = []) use ($concrete) {
return $ioc->build($concrete, $vars);
};
}
} /**
* 返回对象
* @param $abstract
* @param array $vars
* @return mixed
* @throws ReflectionException
*/
public function make($abstract, $vars = [])
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
} if (isset($this->bindings[$abstract]['concrete'])) {
$concrete = $this->bindings[$abstract]['concrete'];
$instance = $concrete($this, $vars);
if ($this->bindings[$abstract]['share']) {
$this->instances[$abstract] = $instance;
}
return $instance;
} throw new RuntimeException($abstract . ' is not bound yet');
} /**
* 创建对象
* @param $concrete
* @return object
* @throws ReflectionException
*/
public function build($concrete, $vars = [])
{
$reflectionClass = new ReflectionClass($concrete);
$constructor = $reflectionClass->getConstructor();
if (is_null($constructor)) {
return $reflectionClass->newInstance();
}
$isInstantiable = $reflectionClass->isInstantiable();
if (!$isInstantiable) {
throw new ReflectionException("{$concrete} cant construct");
}
$parameters = $constructor->getParameters();
$dependencies = $this->getDependencies($parameters, $vars);
return $reflectionClass->newInstanceArgs($dependencies);
} /**
* 获取参数的依赖
* @param array $parameters
* @return array
* @throws ReflectionException
*/
public function getDependencies(array $parameters, $vars = [])
{
$dependencies = [];
reset($vars);
$type = key($vars) === 0 ? 'figure' : 'letter';
/**
* @var ReflectionParameter $parameter
*/
foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
$name = $parameter->getName();
if ($dependency) {
$dependencies[] = $this->getObjectParam($dependency->getName(), $vars);
} elseif ('figure' == $type && !empty($vars)) {
$dependencies[] = array_shift($vars);
} elseif ('letter' == $type && isset($vars[$name])) {
$dependencies[] = $vars[$name];
} elseif ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
} else {
throw new ReflectionException('The constructor of the ' . $parameter->getDeclaringClass()->getName() . ' class has no default value of $' . $name);
}
} return $dependencies;
} /**
* 获取对象类型的参数值
* @access protected
* @param string $className 类名
* @param array $vars 参数
* @return mixed
*/
protected function getObjectParam($className, &$vars)
{
$array = $vars;
$value = array_shift($array);
if ($value instanceof $className) {
$result = $value;
array_shift($vars);
} else {
$result = $this->make($className);
} return $result;
} /**
* @param null $key
* @return array|mixed|null
*/
public function getInstances($key = null)
{
if (is_null($key)) {
return $this->instances;
} elseif (isset($this->instances[$key])) {
return $this->instances[$key];
} else {
return null;
}
}
} // run
/*
| 模拟容器绑定
*/
$ioc = Ioc::getInstance();
$ioc->bind(Request::class);//绑定类
$ioc->bind(Log::class, FileLog::class);//绑定接口
//$ioc->bind(Log::class, DataBaseLog::class);
$ioc->bind('test', function () {//绑定闭包
return 'test' . PHP_EOL;
}); /*
| 模拟路由访问 User 控制器下的 login 方法
*/
$ioc->bind(User::class, null, true);
$method = 'login';
$reflectionMethod = new ReflectionMethod(User::class, $method);
$parameters = $reflectionMethod->getParameters();
$dependencies = $ioc->getDependencies($parameters);
$user = $ioc->make(User::class, ['参数1', '参数2']);
call_user_func_array([$user, $method], $dependencies);
// 查看参数
$user->getExtra();
var_dump($ioc->getInstances());

模拟服务容器Ioc的更多相关文章

  1. 依赖注入(DI)与服务容器(IoC)

    参考文章:http://www.yuansir-web.com/2014/03/20/%E7%90%86%E8%A7%A3php-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A ...

  2. laravel服务容器(IOC控制反转,DI依赖注入),服务提供者,门脸模式

    laravel的核心思想: 服务容器: 容器:就是装东西的,laravel就是一个个的对象 放入:叫绑定 拿出:解析 使用容器的目的:这里面讲到的是IOC控制反转,主要是靠第三方来处理具体依赖关系的解 ...

  3. laravel服务容器-----深入理解控制反转(IoC)和依赖注入(DI)

    首先大家想一想什么是容器,字面意思就是盛放东西的东西,常见的变量,对象属性都是容器,一个容器能够装什么东西,完全在于你对这个容器的定义.有的容器不仅仅只是存文本,变量,而是对象,属性,那么我们通过这种 ...

  4. Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)

    容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于你对该容器的定义.当然,有这样一种容器,它存放的不是文本.数值,而是对象.对象的描述(类.接口)或 ...

  5. IOC Container(服务容器)的工作机制

    IOC Container 是laravel的一个核心内容,有了IOC Container在Laravel的强大表现,我们可以在Laravel中实现很大程度的代码维护性.(文档我是看的懵逼懵逼的(*^ ...

  6. [原]容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在其实际中的运用,是非常有必要的,可以让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能,明白原理后,可以更好的使用它,进而为进行面向对象提供一 ...

  7. Laravel 服务容器,IoC,DI

    DI DI 就是常说的依赖注入,那么究竟什么是依赖注入呢? 打个比方,电脑(非笔记本哈)需要键盘和鼠标我们才能进行操作,这个‘需要’换句话说就是‘依赖’键盘和鼠标. 那么,相应的,一个类需要另一个类才 ...

  8. laravel 服务容器实例——深入理解IoC模式

    刚刚接触laravel,对于laravel的服务容器不是很理解.看了<Laravel框架关键技术解析>和网上的一些资料后对于服务容器有了一些自己的理解,在这里分享给大家 1.依赖 IoC模 ...

  9. 容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在事实上际中的运用,是很有必要的,能够让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能.明确原理后,能够更好的使用它,进而为进行面向对象提供一 ...

随机推荐

  1. 转载:Linux 时钟基础学习

    1.HZ Linux核心每隔固定周期会发出timer interrupt (IRQ 0),HZ是用来定义每一秒有几次timer interrupts.举例来说,HZ为1000,代表每秒有1000次ti ...

  2. 题解 P4568 【[JLOI2011]飞行路线】

    P4568 [JLOI2011]飞行路线 分层图模板题,相似的题还有P4822 [BJWC2012]冻结,P2939 [USACO09FEB]改造路Revamping Trails,其实做惯了也就不难 ...

  3. buuctf Easysql 小记

    堆叠注入 利用原理: 补充系统变量@@sql_modesql_mode:是一组mysql支持的基本语法及校验规则PIPES_AS_CONCAT:将“||”视为字符串的连接操作符而非或运算符,这和Ora ...

  4. Ubuntu 国内安装 kubernetes

    由于墙的原因,国内要安装 kubernetes 非常的麻烦,因此只要解决这个问题,就可以顺利安装 kubernetes 的 三个官法工具 kubelet.kubeadm.kubectl. 安装环境: ...

  5. 去除移动端苹果手机(ios)的input默认样式与input禁止键盘出现的方式

    样式: input{-webkit-appearance: none;} 在iPhone plus点击input框出生日期时会出现如下图: 为了去掉下面那条苹果自带的,可以这样处理:在HTML中的in ...

  6. swift中的可选类型

    可选类型也是Swift语言新添加的对象.主要是为了解决对象变量或常量为空的情况.在前面定义的变量和常量都不能为空.里面必须要有值. Swift中的可选类型则允许变量(常量)中没有值(被设为nil).要 ...

  7. 【PAT甲级】1084 Broken Keyboard (20 分)

    题意: 输入两行字符串,输出第一行有而第二行没有的字符(对大小写不敏感且全部以大写输出). AAAAAccepted code: #define HAVE_STRUCT_TIMESPEC #inclu ...

  8. rf 环境

    googlechrome webdriver驱动下载 addrhttps://sites.google.com/a/chromium.org/chromedriver/downloads谷歌浏览器ap ...

  9. Vue.nextTick DOM 更新循环结束之后执行延迟回调

    在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统 ...

  10. 《JavaScript高级程序设计》读书笔记(三)基本概念第四小节 操作符

    内容---语法 上一小节---数据类型 本小节 操作符---流程控制语句---理解函数 操作符--操作数据值的操作符--算术(如加减).位操作符.关系.相等--ECMAScript操作符可以适用于很多 ...