小编给大家分享一下服务容器Ioc的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
服务容器是一个用于管理类依赖和执行依赖注入的强大工具。
一个类要被容器所能够提取,必须要先注册至这个容器。既然称这个容器叫做服务容器,那么我们需要某个服务,就得先注册、绑定这个服务到容器,那么提供服务并绑定服务至容器的东西就是服务提供器(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的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4625815/blog/4617154