php的依赖注入容器

这里接着上一篇 php依赖注入,直接贴出完整代码如下:

<?php

class C
{
    public function doSomething()
    {
        echo __METHOD__, ‘我是C类|‘;
    }
}

class B
{
    private $c;

    public function __construct(C $c)
    {
        $this->c = $c;
    }

    public function doSomething()
    {
        $this->c->doSomething();
        echo __METHOD__, ‘我是B类|‘;
    }
}
class A
{
    private $b;

    public function __construct(B $b)
    {
        $this->b = $b;
    }

    public function doSomething()
    {
        $this->b->doSomething();
        echo __METHOD__, ‘我是A类|‘;;
    }
}
//这段代码使用了魔术方法,在给不可访问属性赋值时,__set() 会被调用。读取不可访问属性的值时,__get() 会被调用。
class Container
{
    private $s = array();

    function __set($k, $c)
    {
        $this->s[$k] = $c;
    }

    function __get($k)
    {
        return $this->s[$k]($this);
    }
}
$class = new Container();

$class->c = function () {
    return new C();
};
$class->b = function ($class) {
    return new B($class->c);
};
$class->a = function ($class) {
    return new A($class->b);
};

// 从容器中取得A
$model = $class->a;
$model->doSomething(); // C::doSomething我是C类|B::doSomething我是B类|A::doSomething我是A类|

再来一段简单的代码演示一下,容器代码来自simple di container,完整如下:

<?php

class C
{
    public function doSomething()
    {
        echo __METHOD__, ‘我是C类|‘;
    }
}

class B
{
    private $c;

    public function __construct(C $c)
    {
        $this->c = $c;
    }

    public function doSomething()
    {
        $this->c->doSomething();
        echo __METHOD__, ‘我是B类|‘;
    }
}
class A
{
    private $b;

    public function __construct(B $b)
    {
        $this->b = $b;
    }

    public function doSomething()
    {
        $this->b->doSomething();
        echo __METHOD__, ‘我是A类|‘;;
    }
}
class IoC
{
    protected static $registry = [];

    public static function bind($name, Callable $resolver)
    {
        static::$registry[$name] = $resolver;
    }

    public static function make($name)
    {
        if (isset(static::$registry[$name])) {
            $resolver = static::$registry[$name];
            return $resolver();
        }
        throw new Exception(‘Alias does not exist in the IoC registry.‘);
    }
}

IoC::bind(‘c‘, function () {
    return new C();
});
IoC::bind(‘b‘, function () {
    return new B(IoC::make(‘c‘));
});
IoC::bind(‘a‘, function () {
    return new A(IoC::make(‘b‘));
});

// 从容器中取得A
$foo = IoC::make(‘a‘);
$foo->doSomething(); // C::doSomething我是C类|B::doSomething我是B类|A::doSomething我是A类|

这段代码使用了后期静态绑定

依赖注入容器的高级功能

真实的dependency injection container会提供更多的特性,如

  • 自动绑定(Autowiring)或 自动解析(Automatic Resolution)
  • 注释解析器(Annotations)
  • 延迟注入(Lazy injection)

下面的代码在Twittee的基础上,实现了Autowiring。

<?php
class C
{
    public function doSomething()
    {
        echo __METHOD__, ‘我是周伯通C|‘;
    }
}

class B
{
    private $c;

    public function __construct(C $c)
    {
        $this->c = $c;
    }

    public function doSomething()
    {
        $this->c->doSomething();
        echo __METHOD__, ‘我是周伯通B|‘;
    }
}

class A
{
    private $b;

    public function __construct(B $b)
    {
        $this->b = $b;
    }

    public function doSomething()
    {
        $this->b->doSomething();
        echo __METHOD__, ‘我是周伯通A|‘;;
    }
}

class Container
{
    private $s = array();

    public function __set($k, $c)
    {
        $this->s[$k] = $c;
    }

    public function __get($k)
    {
        // return $this->s[$k]($this);
        return $this->build($this->s[$k]);
    }

    /**
     * 自动绑定(Autowiring)自动解析(Automatic Resolution)
     *
     * @param string $className
     * @return object
     * @throws Exception
     */
    public function build($className)
    {
        // 如果是匿名函数(Anonymous functions),也叫闭包函数(closures)
        if ($className instanceof Closure) {
            // 执行闭包函数,并将结果
            return $className($this);
        }

        /** @var ReflectionClass $reflector */
        $reflector = new ReflectionClass($className);

        // 检查类是否可实例化, 排除抽象类abstract和对象接口interface
        if (!$reflector->isInstantiable()) {
            throw new Exception("Can‘t instantiate this.");
        }

        /** @var ReflectionMethod $constructor 获取类的构造函数 */
        $constructor = $reflector->getConstructor();

        // 若无构造函数,直接实例化并返回
        if (is_null($constructor)) {
            return new $className;
        }

        // 取构造函数参数,通过 ReflectionParameter 数组返回参数列表
        $parameters = $constructor->getParameters();

        // 递归解析构造函数的参数
        $dependencies = $this->getDependencies($parameters);

        // 创建一个类的新实例,给出的参数将传递到类的构造函数。
        return $reflector->newInstanceArgs($dependencies);
    }

    /**
     * @param array $parameters
     * @return array
     * @throws Exception
     */
    public function getDependencies($parameters)
    {
        $dependencies = [];

        /** @var ReflectionParameter $parameter */
        foreach ($parameters as $parameter) {
            /** @var ReflectionClass $dependency */
            $dependency = $parameter->getClass();

            if (is_null($dependency)) {
                // 是变量,有默认值则设置默认值
                $dependencies[] = $this->resolveNonClass($parameter);
            } else {
                // 是一个类,递归解析
                $dependencies[] = $this->build($dependency->name);
            }
        }

        return $dependencies;
    }

    /**
     * @param ReflectionParameter $parameter
     * @return mixed
     * @throws Exception
     */
    public function resolveNonClass($parameter)
    {
        // 有默认值则返回默认值
        if ($parameter->isDefaultValueAvailable()) {
            return $parameter->getDefaultValue();
        }

        throw new Exception(‘I have no idea what to do here.‘);
    }
}

// ----
$class = new Container();
$class->b = ‘B‘;
$class->a = function ($class) {
    return new A($class->b);
};
// 从容器中取得A
$model = $class->a;
$model->doSomething(); 

$di = new Container();
$di->php7 = ‘A‘;
/** @var A $php7 */
$foo = $di->php7;
var_dump($foo);

$foo->doSomething(); //C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|object(A)#10 (1) { ["b":"A":private]=> object(B)#14 (1) { ["c":"B":private]=> object(C)#16 (0) { } } } C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|

?>

以上代码的原理参考PHP官方文档:反射,PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。

若想进一步提供一个数组访问接口,如$di->php7可以写成$di‘php7‘],则需用到[ArrayAccess(数组式访问)接口

一些复杂的容器会有许多特性,欢迎博友们补充。

时间: 2024-08-09 23:18:59

php的依赖注入容器的相关文章

YII框架的依赖注入容器

依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象. 所谓的依赖就是,一个对象,要使用另外一个对象才能完成某些功能.那么这个对象就依赖于被使用的对象. 例如: /** * 厨师 */ class cook { /** * 制作食物 */ public function cooking() { $food = new food(); echo $food->get(),"汤<br/>"; } } /*

Unity轻量级依赖注入容器

一.前言 Unity是一个轻量级的可扩展的依赖注入容器,支持构造函数,属性和方法调用注入.在Nuget里安装unity 二.Unity的API方法 UnityContainer.RegisterType<ITFrom,TTO>();  //注册映射 UnityContainer.RegisterType< ITFrom, TTO >("keyName");//注册映射指定key值 IEnumerable<T> databases = UnityCon

依赖注入容器Autofac的详解[转]

依赖注入容器Autofac的详解 发表于 2011 年 09 月 22 日 由 renfengbin 分享到:GMAIL邮箱         Hotmail邮箱 delicious digg Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成,并且开源,Autofac的主要特性如下: 1,灵活的组件实例化:Autofac支持自动装配,给定的组件类型Autofac自动选择使用构造函数注入或者属性注入,Autofac还可以

WPF PRISM开发入门二(Unity依赖注入容器使用)

这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点击这里下载. 运行效果如下: 下面将引入Unity类库,使用Unity来生成需要的对象实例. 先查看一下CalculateRelpLoop类, public class CalculateRelpLoop : ICalculateRelpLoop { ICalculateService _calcu

依赖注入容器Autofac的详解

Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成,并且开源,Autofac的主要特性如下: 1,灵活的组件实例化:Autofac支持自动装配,给定的组件类型Autofac自动选择使用构造函数注入或者属性注入,Autofac还可以基于lambda表达式创建实例,这使得容器非常灵活,很容易和其他的组件集成.2,资源管理的可视性:基于依赖注入容器构建的应用程序的动态性,意味着什么时候应该处理那些资源有点困难.Autofac

依赖注入容器-Autofac

介绍一款依赖注入的容器AutoFac,一直非常迷惑依赖注入到底有独特的优势或者好处,感觉如果用策略模式和反射等也是可以实现这个解耦的,不管怎么样还是先来大概了解依赖注入到底是怎么一回事.              首先来看个例子,如果你想要一把锤子你会怎么做?(这个例子是我百度上看到的,觉得挺形象的) 1.自己造,打铁,锻造等. 2.或者你找制造锤子的工厂订购 3.打开淘宝,下单,支付 上面的例子在程序开发中分别有什么不同:第一种方式显而易见非常麻烦,从开发角度看就是高度耦合,导致使用和制造混在

IoC 依赖注入容器 Unity

原文:IoC 依赖注入容器 Unity IoC 是什么? 在软件工程领域,“控制反转(Inversion of Control,缩写为IoC)”是一种编程技术,表述在面向对象编程中,可描述为在编译时静态分析器并不知道具体被耦合的对象,而该对象是在运行时被对象装配器绑定的. 在传统编程中,决定业务流程的对象是被静态分配的.而在 IoC 中,业务流程取决于对象装配器实例化提供的对象,这使利用抽象来定义对象间的交互成为可能.对象装配器为了能绑定一个对象,要求该对象必须具备兼容的抽象定义.例如类 Cla

如何编写一个简单的依赖注入容器

随着大规模的项目越来越多,许多项目都引入了依赖注入框架,其中最流行的有Castle Windsor, Autofac和Unity Container. 微软在最新版的Asp.Net Core中自带了依赖注入的功能,有兴趣可以查看这里. 关于什么是依赖注入容器网上已经有很多的文章介绍,这里我将重点讲述如何实现一个自己的容器,可以帮助你理解依赖注入的原理. 容器的构想 在编写容器之前,应该先想好这个容器如何使用. 容器允许注册服务和实现类型,允许从服务类型得出服务的实例,它的使用代码应该像 var

依赖注入和依赖注入容器

http://www.digpage.com/di.html#di 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Service Locator)两种模式. 关于依赖注入与服务定位器, Inversion of Control Containers and the Dependency Injection pattern 给出了很详细的讲解,这里结合Web应用和Yii具体实现