我们正在考虑将依赖注入容器集成到我们的项目中。我看过的每个DIC都使用关联数组和/或魔术方法。例如,下面是来自Pimple页面的示例:
$container['session_storage'] = function ($c) {
return new $c['session_storage_class']($c['cookie_name']);
};
$container['session'] = function ($c) {
return new Session($c['session_storage']);
};这是有原因的吗?我讨厌在我的代码中使用字符串,而不是要显示在某个地方的文字字符串。您失去了太多IDE的功能(这使得代码更难维护,这是我们试图避免的!)。
我的偏好应该是这样的:
class Container {
function getSessionStorage()
{
return new $this->getSessionStorageClass($this->getCookieName);
}
function getSession()
{
return new Session($this->getSessionStorage());
}
}有什么理由不这么做吗?如果我们走这条路,我是不是错过了一些不起作用的粉刺魔法?
发布于 2013-02-13 08:05:46
Pimple中ArrayAccess扩展的“魔力”在于它是完全可重用和可互操作的。Pimple作为DIC的一大特点是定义的服务可以利用先前定义的服务和/或参数。假设(无论出于什么原因)您有一个需要Filter实例的Session对象。没有DIC,你可以这样写:
$session = new Session(new Filter);对于粉刺,你可以这样写:
$pimple['filter'] = function($c) {
return new Filter;
};
$pimple['session'] = function($c) {
return new Session($c['filter']);
}Pimple在Session对象的实例化中使用以前注册的'Filter‘服务。这一优点是不是实现ArrayAccess的DIC的唯一,但其可重用性对于代码重用和共享非常有用。当然,您可以为某些服务或所有服务硬编码getter/setter,但可重用性的好处几乎没有了。
另一种选择是使用魔术方法作为getters/setter。这将为DIC提供更像您在代码中所需的应用程序接口,您甚至可以将它们用作Pimple代码的包装器(尽管此时编写一个专门构建的ArrayAccess可能会更好)。包装Pimple的现有方法可能如下所示:
public function __call($method, $args) {
if("set" === substr($method, 0, 3)) {
return $this[substr($method, 3)];
}
if("get" === substr($method, 0, 3) && isset($args[0])) {
return $this[substr($method, 3)] = $args[0];
}
return null;
}您还可以使用__set和__get为DIC中的服务和参数提供类似对象的访问,如下所示:(仍然包装在Pimple的ArrayAccess方法之上)
public function __set($key, $value) {
return $this[$key] = $value;
}
public function __get($key) {
return $this[$key];
}除此之外,您可以完全重写DIC以独占地使用魔术方法,并使用类似对象的API语法而不是实现ArrayAccess,但这应该很容易弄清楚:]
发布于 2014-05-19 15:42:58
您之所以关心集成开发环境自动完成,是因为您将使用容器作为服务定位器,即您将调用您的容器。
理想情况下,您不应该这样做。服务定位器模式是一种反模式:您可以从容器获取依赖项,而不是注入所需的依赖项(依赖项注入)。这意味着将您的代码耦合到容器。
Pimple (和它的数组访问)并没有真正解决这个问题,所以我不会直接回答您的问题,但我希望它能让问题变得更清楚。
附注:什么是“理想”的方式?依赖注入。
切勿使用或调用容器,除非是在应用程序的根目录下(例如创建控制器)。总是注入你需要的对象(依赖项),而不是注入整个容器。
发布于 2013-02-13 07:46:30
Pimple被设计成像数组一样被访问(它实现了ArrayAccess接口)。如果您想要一个类似方法的接口,只需扩展Pimple并使用__call()魔术方法:
class Zit extends Pimple
{
public function __call($method, array $args)
{
$prefix = substr($method, 0, 3);
$suffix = isset($method[3])
? substr($method, 3)
: NULL;
if ($prefix === 'get') {
return $this[$suffix];
} elseif ($prefix === 'set') {
$this[$suffix] = isset($args[0])
? $args[0]
: NULL;
}
}
}用法:
$zit = new Zit();
// equivalent to $zit['Foo'] = ...
$zit->setFoo(function() {
return new Foo();
});
// equivalent to ... = $zit['Foo']
$foo = $zit->getFoo();至于为什么Pimple没有提供这种开箱即用的功能,我不知道。可能只是为了让它尽可能简单。
编辑:
关于IDE自动补全,它们也不能用于像这样的神奇方法。我相信,一些编辑器允许您使用@property和@method给出文档块提示来弥补这一点。
https://stackoverflow.com/questions/14813504
复制相似问题