您的位置:首页 > 编程语言 > PHP开发

202 Ioc 仿照laravel实现一个最简的ioc容器

2016-10-10 18:26 465 查看
今天感觉对ioc的掌握不是很好,所以决定实现一遍看看。

1.最基本的bind 和 make

容器类最少有两个方法,一个
bind
将类绑定容器中,一个
make
从容器中取得这个类

bind()

$mysql = new mysql();
$Ioc::bind('db',$mysql);


当然上面的new操作也可以用闭包来实现,一个效果,闭包的好处在于这里的new不会立刻执行

$Ioc::bind('db',function($Ioc){
return new mysql();
});


make()

$mysql= Ioc::make('db');


2.最初版本的容器实现

根据上面的描述,那么最初的Ioc类差不多长这样,此处为了更加直白,所以本应该是static的方法被写成了动态

<?php
class Ioc{

function bind($alias,$concrete){
$this->$alias = $concrete;
}

function make($alias){
return $this->$alias;
}
}


有几个问题

所有服务要一个一个bind进去、能否根据配置文件自动bind

每次用make使用一个新服务都会重新new一次

组件无法注入依赖

(继续第三点)组件是否可以自动注入依赖?

是否可以绑定一个闭包而不是实例来实现延迟加载。

3.Ioc初始化时候就把所有服务bind进去

此处可以用配置文件的方法,此处为了简单直接将配置放在构造函数中

class Ioc {
public function __construct(){
//这了只写了一个服务
$services = [
'db' => 'mysql'
];

foreach ($services as $alias => $concrete_name) {
$concrete = new $concrete_name;
$this->bind($alias,$concrete);
}
}

function bind(){
... //跟上面一样
}

function make(){
... //跟上面一样
}
}

class mysql {
function __construct(){
echo "具体实现就不写了,这应该是个pdo的二次封装";
}
}

$Ioc = new Ioc();
$Ioc->make('db');


4.用闭包的方法重写bind方法

$concrete
处理成一个返回实例的闭包,并将ioc容器实例注入到每个闭包中。

function bind($abstract,$concrete,$share){
// $this->$alias = $concrete;
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract,$concrete);
}
$this->bindings[$abstract] = compact('concrete','shared');
}!

function getClosure($abstract,$concrete){
//$c为Ioc容器对象
return function($c) use ($abstract,$concrete){
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};
}


5.让组件内部可以使用容器的其他服务

重写
make
方法,判断是否符合
isBuildable
的条件,要么
$concrete == $abstract
,要么
$concrete
本身已经是闭包,如果不符合那么则调用
build
方法使之符合
isBuildable


//生成实例对象 解决接口和实例化类之间依赖关系
public function make($abstract){
// return $this->$abstract;
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete,$abstract)){
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
return $object;
}

public function isBuildable($concrete,$abstract){
return $concrete == $abstract || $concrete instanceof Closure;
}


build

使用反射获取构造函数的依赖关系,并调用
getPendencies
获取依赖实例。

public function build($concrete){
if ($concrete instanceof Closure){
//Ioc容器实例注入
return $concrete($this);
}
//反射对象
$reflector = new ReflectionClass($concrete);
//检查这个类是否可实例化
if (!$reflector->isInstantiable()){
echo $message = "Target [$concrete] is not instantiable.";
}
$constructor = $reflector->getConstructor();
if (is_null($constructor)){
return new $constructor;
}
$dependencies = $constructor->getParameters();
$instances = $this->getPendencies($dependencies);
return $reflector->newInstanceArgs($instances);
}


getDependencies 实现

public function getDependencies($parameters){
$dependencies = [];
foreach ($dependencies as $parameter) {
$denpendency = $parameter->getClass();
if (is_null($denpendency)){
$denpendencies[] = NULL;
} else {
$dependencies[] = $this->resolveClass($parameter);
}
}
return (array)$dependencies;
}

public function resolveClass(ReflectionParameter $parameter){
return $this->make($parameter->getClass()->name);
}


6.将单例的服务单独bind



使用反射自动bind



使用facade


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  laravel