模拟服务容器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, $extra)
    {
        $this->log = $log;
        $this->extra = $extra;
    }

    /**
     * 模拟用户登录写入登录日志
     */
    public function login(Request $request)
    {
        echo ‘接收登录请求的参数json:‘ . json_encode($request->toArray()) . PHP_EOL;
        echo ‘user log success...‘ . PHP_EOL;
        $this->log->write();
    }
}

/**
 * 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
     */
    public function bind($abstract, $concrete = null, $params = [])
    {
        if (is_null($concrete)) {
            $concrete = $abstract;
        }

        if (!$concrete instanceof Closure) {
            $this->bindings[$abstract][‘concrete‘] = function (Ioc $ioc) use ($concrete, $params) {
                return $ioc->build($concrete, $params);
            };
        } else {
            $this->bindings[$abstract][‘concrete‘] = $concrete;
        }
    }

    /**
     * 返回对象
     * @param $abstract
     * @return mixed
     */
    public function make($abstract)
    {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        if (isset($this->bindings[$abstract][‘concrete‘])) {
            $concrete = $this->bindings[$abstract][‘concrete‘];
            $instance = $concrete($this);
            $this->instances[$abstract] = $instance;
            return $instance;
        }

        throw new RuntimeException($abstract . ‘ is not bound yet‘);
    }

    /**
     * 创建对象
     * @param $concrete
     * @return object
     * @throws ReflectionException
     */
    public function build($concrete, $params)
    {
        $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, $params);
        return $reflectionClass->newInstanceArgs($dependencies);
    }

    /**
     * 获取参数的依赖
     * @param array $parameters
     * @return array
     * @throws ReflectionException
     */
    public function getDependencies(array $parameters, $params = [])
    {
        $dependencies = [];
        /**
         * @var ReflectionParameter $parameter
         */
        foreach ($parameters as $parameter) {
            $dependency = $parameter->getClass();
            if (is_null($dependency)) {
                if ($parameter->isDefaultValueAvailable()) {
                    $dependency[] = $parameter->getDefaultValue();
                } else {
                    if (!isset($params[‘$‘ . $parameter->getName()])) {
                        throw new ReflectionException(‘The constructor of the ‘ . $parameter->getDeclaringClass()->getName() . ‘ class has no default value of $‘ . $parameter->getName());
                    }
                    $dependencies[] = $params[‘$‘ . $parameter->getName()];
                }
            } else {
                $dependencies[] = $this->make($dependency->name);
            }
        }
        return $dependencies;
    }
}

/**
 * Class Facade
 * 模拟门面
 */
class Facade
{
    protected static function getFacadeClass()
    {
        return ‘‘;
    }

    public static function __callStatic($name, $arguments)
    {
        $instance = Ioc::getInstance()->make(static::getFacadeClass());
        return call_user_func_array([$instance, $name], $arguments);
    }
}

class UserFacade extends Facade
{
    protected static function getFacadeClass()
    {
        return ‘User‘;
    }
}

// run
/*
 | 模拟容器绑定
 */
$ioc = Ioc::getInstance();
$ioc->bind(Request::class);//绑定类
$ioc->bind(Log::class, FileLog::class);//绑定接口
//$ioc->bind(Log::class, DataBaseLog::class);
$ioc->bind(User::class, null, [‘$extra‘ => ‘额外参数‘]);//绑定类 且支持额外参数绑定
$ioc->bind(‘test‘, function () {//绑定闭包
    return ‘test‘ . PHP_EOL;
});

/*
 | 模拟路由访问 User 控制器下的 login 方法
 */
$reflectionMethod = new ReflectionMethod(User::class, ‘login‘);
$parameters = $reflectionMethod->getParameters();
$dependencies = $ioc->getDependencies($parameters);
$user = $ioc->make(‘test‘);
$user = $ioc->make(User::class);
// 普通调用
echo ‘普通调用:‘ . PHP_EOL;
call_user_func_array([$user, ‘login‘], $dependencies);
// facade门面调用
echo ‘门面调用:‘ . PHP_EOL;
call_user_func_array([UserFacade::class, ‘login‘], $dependencies);

原文地址:https://www.cnblogs.com/cshaptx4869/p/11671003.html

时间: 2024-08-30 14:31:00

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

Laravel 服务容器 IoC(控制反转) 和 DI(依赖注入)

Laravel 服务容器 IoC(控制反转) 和 DI(依赖注入) IoC 容器, laravel 的核心 Laravel 的核心就是一个 IoC 容器,根据文档,称其为“服务容器”,顾名思义,该容器提供了整个框架中需要的一系列服务.作为初学者,很多人会在这一个概念上犯难,因此,我打算从一些基础的内容开始讲解,通过理解面向对象开发中依赖的产生和解决方法,来逐渐揭开“依赖注入”的面纱,逐渐理解这一神奇的设计理念. 本文一大半内容都是通过举例来让读者去理解什么是 IoC(控制反转) 和 DI(依赖注

依赖注入(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%A5laravel-ioc%E5%AE%B9%E5%99%A8/?preview 我们在建一个类时,在类的内部有可能会用到另外一个对象实例举个栗子: class User{ public function getUser(){ $db = new DB(); // 这里产生了对数据库连接类的依赖 $d

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

介绍 学习经典框架的实现原理以及设计模式在事实上际中的运用,是很有必要的,能够让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能.明确原理后,能够更好的使用它,进而为进行面向对象提供一种思路. 点击下载源代码:下载 动手模拟IoC实现 首先我们把我们用的dao.service.entity定义出来: Student.java : package com.bzu.entity; public class Student { private int id; private Strin

laravel 学习笔记 —— 神奇的服务容器

转载自:https://www.insp.top/learn-laravel-container 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于你对该容器的定义.当然,有这样一种容器,它存放的不是文本.数值,而是对象.对象的描述(类.接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” .“依赖注入(DI)”.本文就从这里开始. IoC 容器, laravel 的核心 Laravel 的核心就

laravel框架总结(四) -- 服务容器

1.依赖 我们定义两个类:class Supperman 和 class Power,现在我们要使用Supperman ,而Supperman 依赖了Power class Supperman { private $power; public function __construct(){ $this->power = new Power; } } 一旦Power发生了变化,Supperman 不得不修改,这种就叫耦合程度太高,所以面临的问题是解耦,就需要用到控制反转. 2.依赖注入 只要不是由

模拟实现Spring IOC

通过在类上标注@Registration 注册进容器,@Injection从容器注入对象 容器类: public class SpringContainer { public SpringContainer(String packageToScan){ Set<Class<?>> classes = getClasses(packageToScan); for(Class c : classes){ if(!c.isAnnotationPresent(Registration.cl

Minor【 PHP框架】4.服务容器与服务提供者

4.1 服务提供者 关于服务容器可以参考我的另外一篇文章:http://www.cnblogs.com/orlion/p/4797422.html Minor使用IoC(Inversion of Control,控制倒转,这是一个设计模式,可以先查看下百科)容器这个强有力的工具管理类依赖.依赖注入(也是一种设计模式,一般用于实现IoC)是 一个不用编写固定代码来处理类之间依赖的方法,相反的,这些依赖是在运行时注入的,这样允许处理依赖时具有更大的灵活性. 服务提供者是服务容器中的单元,是一个普通的

服务容器

1.依赖 我们定义两个类:class Supperman 和 class Power,现在我们要使用Supperman ,而Supperman 依赖了Power class Supperman { private $power; public function __construct(){ $this->power = new Power; } } 一旦Power发生了变化,Supperman 不得不修改,这种就叫耦合程度太高,所以面临的问题是解耦,就需要用到控制反转. 2.依赖注入 只要不是由

laravel 服务容器实现原理

前言 通过实现laravel 框架功能,以便深入理解laravel框架的先进思想. 什么是服务容器 服务容器是用来管理类依赖与运行依赖注入的工具.Laravel框架中就是使用服务容器来实现 ** 控制反转 ** 和 ** 依赖注入 **. 什么是控制反转(IoC)和依赖注入(DI) 控制反转(IoC) 就是说把创建对象的** 控制权 进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,也就是 Laravel ** 中的容器. 依赖注入(DI)则是帮助容器实现在运行