ioc-----依赖注入控制反转

依赖注入控制反转

  • 定义一个写日志的接口 Log.php

写日志的驱动可以有很多种,比如:[文件,数据库],它们根据接口类来具体的实现

class FileLog implements Log
{
    public function write()
    {
        // TODO: Implement write() method.
    }
}

class DateBaseLog implements Log
{
    public function write()
    {
        // TODO: Implement write() method.
    }
}

现在有一个web网站,需要记录每个用户登录时的信息;就有一个User的模型,登录处理的逻辑,成功后用文件写日志

class UserFile
{
    private $log;

    public function __construct()
    {
        $this->log = new FileLog();
    }

    public function login()
    {
        /**
         * 登录成功后写日志,目前是用文件的方式写日志
         */
        $this->log->write();
    }
}

突然有一天,领导通知你,不用文件写日志了,现在要使用数据库。那么此时你又要修改你的User里面的login方法:

class UserDataBase
{
    private $log;

    public function __construct()
    {
        $this->log = new DateBaseLog();
    }

    public function login()
    {
        /**
         * 登录成功后写日志,目前是用文件的方式写日志
         */
        $this->log->write();
    }
}

如果有一天,这个又要改变了呢,你还要再去改吗?这对于我们来说几乎是不能忍的。所以依赖注入就出现了,我们通过构造函数来实现它,就是我们通过外部来影响内部,
也就是:指组件的依赖通过外部参数或其它形式注入

class UserIoc
{
    private $log;

    public function __construct(Log $log)
    {
        $this->log = $log;
    }

    public function login()
    {
        /**
         * 登录成功后写日志,目前是用文件的方式写日志
         */
        $this->log->write();
    }
}

这样的实现的话,我们每次就不用去构造函数里面new它了,是不是很舒服。


分割线

上面我们知道了依赖注入,那么现在我们了解一下,什么是反射?

PHP自5.0版本以后添加了反射机制,它提供了一套强大的反射API,允许你在PHP运行环境中,访问和使用类、方法、属性、参数和注释等,其功能十分强大,经常用于高
扩展的PHP框架,自动加载插件,自动生成文档,甚至可以用来扩展PHP语言。由于它是PHP內建的oop扩展,为语言本身自带的特性,所以不需要额外添加扩展或者配置就
可以使用

在这里,我们通过反射机制来拿到User类里面的各种我们需要的数据:

class User
{
    private $log;

    public function __construct(Log $log)
    {
        $this->log = $log;
    }

    public function login()
    {
        $this->log->write();
    }
}

//获取User对象
$reflector = new ReflectionClass(User::class);

//获取User对象的构造函数
$construct = $reflector->getConstructor();

//获取User对象的构造函数的依赖参数
$constructParams = $construct->getParameters();

//创建User对象,没有参数
$user = $reflector->newInstance();

//创造User对象,需要传递参数
$user = $reflector->newInstanceArgs($constructParams);

$user->login();

在这里,上面的构造函数,需要修改一下:

public function __construct()
    {
        $this->log = new FileLog();
    }

这样就可以正常输出了,动态接口性质的,这里还没有实现,下面是更加纤细的实现

<?php
/**
 * Created by PhpStorm.
 * User: liyi
 * Date: 2019/3/26
 * Time: 16:10
 */

require_once 'Log.php';
require_once 'FileLog.php';

class User
{
    private $log;

    public function __construct(FileLog $log)
    {
        $this->log = $log;
    }

    public function login()
    {
        $this->log->write();
    }
}


function make($concreate)
{
    //user类的反射类
    $reflector = new ReflectionClass($concreate);
    //构造函数
    $construct = $reflector->getConstructor();

    //判断是否有构造函数,没有构造函数,也就没有依赖参数
    if(is_null($construct)) {
        return $reflector->newInstance();
    }

    //有构造函数,得到参数
    $params = $construct->getParameters();

    //根据参数返回实例
    $instance = getDependencies($params);
    //生成User类
    return $reflector->newInstanceArgs($instance);
}

function getDependencies($params)
{
    $dependencies = [];

    foreach ($params as $param) {
        $dependencies[] = make($param->getClass()->name);
    }

    return $dependencies;
}

$user = make('User');

$user->login();


服务容器IOC具体的实现

<?php
/**
 * Created by PhpStorm.
 * User: liyi
 * Date: 2019/3/26
 * Time: 16:58
 */

class Ioc
{
    public $binding = [];

    public function bind($abstract,$concrete)
    {
        $this->binding[$abstract]['concrete'] = function($ioc) use ($concrete) {
            return $ioc->build($concrete);
        };
    }

    public function make($abstract)
    {
        $concrete = $this->binding[$abstract]['concrete'];
        return $concrete($this);
    }

    /**
     * @TODO 创建对象
     * @param $concrete
     * @return object
     * @throws ReflectionException
     */
    public function build($concrete)
    {
        //$concrete 代表的就是完整命名空间的类名
        $reflector = new ReflectionClass($concrete);
        //得到构造函数
        $construct = $reflector->getConstructor();
        //构造函数是否为空
        if(is_null($construct)) {
            //直接返回实例
            return $reflector->newInstance();
        }
        //尝试得到构造函数的依赖参数
        $dependencies = $construct->getParameters();
        //尝试得到构造函数的依赖参数的实例
        $instance = $this->getDependencies($dependencies);
        //根据依赖参数依赖注入,得到当前需要的对象
        return $reflector->newInstanceArgs($instance);
    }

    /**
     * @TODO 获取参数的依赖
     * @param $params
     * @return array
     */
    protected function getDependencies($params):array
    {
        $dependencies = [];

        foreach ($params as $param) {
            //得到依赖参数的名字,再递归得到依赖参数的实例
            $dependencies[] = $this->make($param->getClass()->name);
        }
        return $dependencies;
    }
}

<?php
/**
 * Created by PhpStorm.
 * User: liyi
 * Date: 2019/3/26
 * Time: 16:56
 */

require_once 'Ioc.php';
require_once 'Log.php';
require_once 'FileLog.php';
require_once 'DateBaseLog.php';

class UserIoc
{
    private $log;

    public function __construct(Log $log)
    {
        $this->log = $log;
    }

    public function login()
    {
        $this->log->write();
    }
}

$ioc = new Ioc();

$ioc->bind('Log','FileLog');
$ioc->bind('user','UserIoc');
$user = $ioc->make('user');

$user->login();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值