metrophp / metrodi
This package is not auto-updated.
Last update: 2024-10-02 17:38:24 UTC
README
小巧、智能的依赖注入器
tl;dr
- 不使用类类型
- 不依赖自动加载
- 首先检查参数名称
- 实际上使用类类型,但在检查参数名称之后
- 自动注入以 'Service' 结尾的任何公共类变量
设置
Metro DI 可以通过创建对象或作为全局命名空间函数的单例使用。
$cont = Metrodi_Container::getContainer(); $cont->set('flaga', true); $cont->didef('logService', 'path/to/log.php', 'arg1', 'arg2', 'arg3'); $log = $cont->make('logService');
使用全局函数它看起来是这样的
_set('flaga', true); _didef('logService', 'path/to/log.php', 'arg1', 'arg2', 'arg3'); $log = _make('logService');
事物
在 Metro DI 中,您使用 DI def 函数命名您的依赖项。一个未定义的事物将返回一个原型对象,该对象通过魔法 __call 记录对它的所有方法调用。
$cart = _make('shoppingCartService'); echo( get_class($cart) ); // Metrodi_Proto _didef('shoppingCartService', 'path/to/my/cart.php'); $cart = _make('shoppingCartService'); echo( get_class($cart) ); // Path_To_My_Cart
构造函数注入
当使用 _make 创建对象时,注入器将检查构造函数参数,并找到任何具有相同名称的已定义事物并将它们传递。为什么不使用类类型呢?想象一下尝试切换实际的实现对象。您必须更改包含旧类类型提示的每个文件,或者您必须创建一个充满接口的库,以便为未来可能的切换做好准备。
一些其他语言没有无类型的优势。使用变量的名称而不是类型提示(同时仍然回退到类型提示)允许进行最快的原型设计和最灵活的依赖实现更改。
_didef('request', '\Top\Quality\Request'); _didef('response', '\Top\Quality\Response'); class MyController { public function __construct($request, $response) { echo get_class($request); // 'Top\Quality\Request'; } }
传递参数
您可以在定义对象和创建对象时传递参数。
namespace org\my\cart\service\abstract\concrete\interface; class Cart { public function __construct($idUser, $listItems, $timestamp=NULL) { $this->idUser = $idUser; $this->listItems = $listItems; $this->timestamp = $timestamp; } } _didef('shoppingCartService', '\org\my\cart\service\abstract\concrete\interface\Cart', 'A', 'B'); $cart1 = _make('shoppingCartService'); echo $cart1->idUser; // 'A' echo $cart1->listItems; // 'B' echo $cart1->timestamp; // null $cart2 = _make('shoppingCartService', 'C', 'D', time()); echo $cart2->idUser; // 'C' echo $cart2->listItems; // 'D' echo $cart2->timestamp; // 1234567890 (YMMV)
单例
单例和新的对象都可以通过 _make() 访问,但这取决于您如何使用 _make() 与 _didef()。
_didef('singletonService', '\ns\locator\class', 'arg1', 'arg2'); //later $ss1 = _make('singletonService'); //same reference $ss2 = _make('singletonService');
如果您的对象不是固有的服务,并且每次创建时都需要新的构造函数参数,则可以在每次 _make() 调用中传递构造函数参数。每个唯一的参数组合将被哈希,并缓存生成的对象将在后续对 _make() 的调用中返回。
_didef('user', '\ns\locator\class'); //later $u1 = _make('user', 100); //new object $u2 = _make('user', 200);
您可以通过向 _didef() 提供参数来结合这两种方法,这些参数将被组合并用作后续 _make() 调用的默认值
_didef('log', '\ns\locator\class', '/tmp/out.log'); //later $mainLog = _make('log'); $specialLog = _make('log', '/var/log/special.log');
_makeNew() 函数将始终返回类定义的新实例,无论传递了什么参数。它简单地绕过任何实例缓存,并继续以与第一次调用 _make() 时相同的方式创建新对象。
_didef('user', '\ns\user'); //later $user1 = _make('user'); $user2 = _makeNew('user'); //different instance
闭包
从 3.1.0 版本开始,可以将闭包或任何回调作为任何事物的定义传递。
_didef('connection', function($c) { return new \Ns\Connection($c['username'], $c['password']); }); $c = _make('connection', array('bob', 'secret');
匿名函数的结果将从 _make 返回而不是函数对象。此行为默认为单例行为,重复调用 _make('connection') 将返回相同的对象。
要获取新的引用并再次调用匿名函数,请使用 _makeNew()
_didef('connection', function($c) { return new \Ns\Connection($c['username'], $c['password']); }); $c = _make('connection', array('bob', 'secret'); $c2 = _makeNew('connection', array('alice', 'secret2');
服务提供者
当您从定义公共类变量且其中一个变量名称以 'Service' 结尾的类创建事物时,依赖注入器将自动将该服务的延迟加载对象注入到对象的变量中。
class NullMailer { public function send() { print "Sending...\n"; } } class Controller { public $emailService; } _didef('controller', 'Controller'); _didef('emailService', new NullMailer()); $c = _make('controller'); $c->emailService->send();