简述 container —— 反射机制实现

前言

使用依赖注入实现控制反转来降低代码的耦合性。

依赖注入 DI,控制反转 IOC,解耦等等等 大家探索前进,终走到了这一步,终于让代码灵活、可扩展、低耦合、高内聚,终于可以开心的coding了!!

好,现在我要去数据库中查询用户id为1的用户名。


new User(
    new \Database\MysqlDrive(new \Database\Connection),
    new Builder(),
    new Relations(),
    new Event(new Listener()),
    new Auth(),
    ...
)

stop?我好像有点写不完,我只想获取一个用户名而已!!!

当我使用依赖注入后,所有的依赖都由调用者来处理, 调用者可以控制User的行为,但却要做更多的事情。

但我不想多做一丝事情,我希望更加简单,简单到连依赖也能自动处理,解析,自动注入该有多好呀!

题外话:我所理解的最为灵活的php开发架构是,php作为一个中转,将前端和mysql连接起来。这样我们就可以灵活到一套代码解决所有所有的问题了。
例如http://web.dev/users/1?fields=id,username&include=posts:limit(1|5):order(created_at|desc)

示例代码

我现在有一个Foo类,Foo类中一个allBarName()方法.并且依赖于BarA~BarD这4个类的name()方法. 如下

<?php

namespace Container\Foo;

use Container\Bar\BarA;
use Container\Bar\BarB;
use Container\Bar\BarC;
use Container\Bar\BarD;

class Foo
{
    private $barA;
    private $barB;
    private $barC;
    private $barD;

    public function __construct(BarA $barA, BarB $barB, BarC $barC, BarD $barD)
    {

        $this->barA = $barA;
        $this->barB = $barB;
        $this->barC = $barC;
        $this->barD = $barD;
    }

    public function allBarName()
    {
        return $this->barA->name().'/'.$this->barB->name().'/'.$this->barC->name().'/'.$this->barD->name();
    }
}

BarA示例, BarB,BarC,BarD相同

<?php

namespace Container\Bar;

class BarA
{
    public function name()
    {
        return '彼得·帕克';
    }
}

现在用依赖注入的方式来,调用allBarName()方法。

$foo = new \Container\Foo\Foo(
    new \Container\Bar\BarA(),
    new \Container\Bar\BarB(),
    new \Container\Bar\BarC(),
    new \Container\Bar\BarD()
);

echo $foo->allBarName(); // 彼得·帕克/托尼·屎大颗/巴里·艾伦/布鲁斯·韦恩

上面的code已经是低耦合的了。
但懒惰的我并不想去手动注入Foo的所有依赖,我希望能有一个Container来帮我解析Foo的所有依赖,然后再把实例返回给我。

那就来吧,实现一个简单的Container

<?php

namespace Container;

class Container
{
    public static function make($class)
    {
        $reflection = new \ReflectionClass($class);

        $constructor = $reflection->getConstructor();
        $parameters = $constructor->getParameters();

        $instances = [];

        foreach ($parameters as $parameter) {
            $className =  $parameter->getClass()->getName();
            $instances[] = new $className;
        }

        //... 将数组拆封成参数传递给方法, 类似于 call_user_func_array()
        return new $class(...$instances);
    }
}

这是一个简单到不能再简单的依赖解析容器了,但我想它能满足我的需求。

再次调用allBarName()方法

$foo = \Container\Container::make(\Container\Foo\Foo::class);
echo $foo->allBarName(); // 彼得·帕克/托尼·屎大颗/巴里·艾伦/布鲁斯·韦恩

oh yeah!成功了

结语

我想我已经表达了我的想法,我还没有能力也不是很想去实现一个强大灵活的container,能够知道为什么需要container我已经很满足了。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 2

这个就是流行的设计模式,java也采用DI, IOC。所有不能说TP5抄袭了laravel

7年前 评论

@xuanjiang1985 迷之鄙视链而已, 思想本身又部分语言.

7年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!