源码-反转控制的理解

来源:互联网 发布:c 语言中的删除文件 编辑:程序博客网 时间:2024/06/16 16:22

源码-反转控制的理解

反转控制是什么,有什么用:反转控制为Ioc Container,简称ICO,解决各个类之间的依赖问题。主流框架(laravel、yii等)源码均有出现,若不能理解反转控制,对源码的理解就很难深入。

  • 功能是什么
    1、存储定义的类
    2、实例化类

案例说明-简易案例

//容器类,封装的很简单,set方法用于存储类,get用于实例化类Class Container{    private $_definitions;//定义类    public function set($class, $definition)    {        $this->_definitions[$class] = $definition;    }//实例化类  call_user_func:第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。    public function get($class, $params = [])    {        $definition = $this->_definitions[$class];        return call_user_func($definition, $params);    }}//构造赋值属性class EmailSenderBy163{    private $_name;    public function __construct($name = '')    {        $this->_name = $name;    }    public function send()    {    }}$container = new Container;$container->set('EmailSenderBy163', function ($name = '') {//函数追加new自己函数    return new EmailSenderBy163($name);});//启动new函数new自己$emailSenderBy163 = $container->get('EmailSenderBy163', '163');echo "<pre>";print_r($emailSenderBy163);
//打印出来的结果EmailSenderBy163 Object(    [_name:EmailSenderBy163:private] => 163)

上述不太好理解,我还用思维导图做了图让你理解,绝对贴心
这里写图片描述

案例说明-复杂案例

//没什么好说,一个类构造赋值属性class EmailSenderBy163{    private $_name;    public function __construct($name = '')    {        $this->_name = $name;    }    public function send()    {    }}class User{    private $_emailSenderObject;    //构造赋值并限制$emailSenderObject为EmailSenderBy163 类和子类为    public function __construct(EmailSenderBy163 $emailSenderObject)    {        $this->_emailSenderObject = $emailSenderObject;    }    public function register()    {        $this->_emailSenderObject->send();    }}//容器Class Container{    private $_definitions;    public function set($class, $definition)    {        $this->_definitions[$class] = $definition;    }    public function get($class, $params = [])    {    //get方法在判断回调函数上更加严谨        if (isset($this->_definitions[$class]) && is_callable($this->_definitions[$class], true)) {            $definition = $this->_definitions[$class];            //$this是指这个容器            return call_user_func($definition, $this, $params);        } else {            throw new Exception("error");        }    }}$container = new Container;$container->set('EmailSenderBy163', function ($container, $name = '') {    return new EmailSenderBy163($name);});$container->set('User', function ($container, $params = []) {//$container对应上述的$this,这样拿到相对应参数,这里有点绕想想会明白的    return new User($container->get($params[0], $params[1]));});echo '<pre>';print_r($container->get('EmailSenderBy163', ['163']));print_r($container->get('User', ['EmailSenderBy163', '163']));

这就是反转控制,需要先把所有的类全部set进去,然后get的时候指定其所依赖的类,依然很麻烦。可以考虑使用反射,并做自动实例化处理。
反射类地址:http://php.net/manual/zh/book.reflection.php

利用反射增加容器类

Class Container{    public function get($class, $params = [])    {        return $this->build($class, $params);    }    public function build($class, $params)    {        $dependencies = [];    //实例化反射类        $reflection = new ReflectionClass($class);        //获取类的构造函数        $constructor = $reflection->getConstructor();        if ($constructor !== null) {        //获取参数            foreach ($constructor->getParameters() as $param) {            //获得类的提示类型                $c = $param->getClass();                if ($c !== null) {                //获取类名                    $dependencies[] = $this->get($c->getName(), $params);                }            }        }        foreach ($params as $index => $param) {            $dependencies[$index] = $param;        }//从给出的参数创建一个新的类实例        return $reflection->newInstanceArgs($dependencies);    }}$container = new Container;$user = $container->get('User');echo '<pre>';print_r($user);

输出结果

User Object(    [_emailSenderObject:User:private] => EmailSenderBy163 Object        (            [_name:EmailSenderBy163:private] =>         ))