简述 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 我已经很满足了。
- code demo https://github.com/weiwenhao/container
- blog 地址 简述 container —— 反射机制实现
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: