用DI容器替换全局$ registry对象是否是一种好习惯? [英] Is it good practice to have DI container replace a global $registry object?

查看:39
本文介绍了用DI容器替换全局$ registry对象是否是一种好习惯?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经开始重构一个小型应用程序以使用小型DI容器,而不是使用
$ registry :: getstuff();

I have started refactoring a small application to use a small DI container instead of having $registry::getstuff(); calls in my classes I inject them in a container.

这引发了两个问题,

Q1->我扩展 Pimple DI类,并创建一个容器,该容器具有特定于每个需要DI的对象的依赖项。然后,我将对象整个shebang 送入并进行清理它在构造函数中将DI的对象分配给我正在构建的对象的类属性。

Q1 -> I extend Pimple DI class and create a container with dependencies specific to each object that will need DI. I then feed the object the whole shebang, and decrontruct it it in the constructor assigning the DI's objects to the class properties of the object I'm building.

我应该在 new object()调用中分离对象吗?我只是觉得这样比较容易,但是看到我现在是一个单一的团队,我只是想确认自己有正确的方法。

Should I be separating the object in the new object() call? I just found it easier like this but seeing I'm a one man team right now I just want to confirm I have proper methodology.

Q2->我找到了$如果我在几个主要类上执行此操作,那么我遍历的注册表对象将不可用,这是使用DI的正常结果,不再使用注册表了吗?我可能在容器中注入了一个或两个单例对象,但看起来这就是我所需要的,而且即使这些对象也可以轻松消除,因为DI具有可返回对象同一实例的share()属性,从而有效地消除了需要单身人士。这样就摆脱了需要注册表/单子的应用程序的方法,因为如果这样的话,这很容易。

Q2 -> I find the $registry object I was passing around all over will be uneeded if I do this on a few of the main classes, is this a normal result of using DI, no more registry? I may have a singleton or two injected in the container but it looks as that is all I will need and even those could easily be eliminitated since the DI has a share() property that returns the same instance of the object, effectively removing the need for singletons. Is this the way to rid an app of needing registry/singletons, because if it is it's darn easy like this.

推荐答案

Q2 :
如果您要遍历 $ registry 对象....那么您的 Registry 实际上不是所谓的注册表(如Fowler所述)。

Q2 : If you were passing around all over your $registry object.... then your Registry was not really what is called a Registry (as Fowler described it).

注册表或多或少是一个全局对象( -已知)。
在PHP中,用于实现 Registry 的两个常见原型将是

A Registry is more or less a global object (a "well-known") with get/set methods. In PHP, two common prototypes for the implementations of a Registry would be

作为一个单例

class RegistryAsSingleton
{
    public static function getInstance (){
       //the singleton part
    }

    public function getStuff ()
    {
       //some stuff accessed thanks to the registry
    }
}

到处都是静态方法

class RegistryAsStatic
{
    public static function getStuff()
    {
    }
}

遍历您的 Registry 使其成为一个对象:一个容器,其用途不比提供对其他对象的引用更大。

Passing your Registry all over the place makes it, well, just an object: a container with no greater purpose than providing references to other objects.

您的DI容器(使用您在OP中建议的Pimple)本身就是 Registry :它众所周知,使您能够从中获取组件

Your DI container (using Pimple as you suggested in your OP) is kind of a Registry itself: It IS well known and enables you to get components from anywhere.

所以是的,我们可以说您的DI容器将通过执行相同的功能来消除注册表的要求和必要性。

So yes, we can say that your DI container will remove the requirement and necessity of a registry by performing the same functionality.

但是(总是但是)



被证明是无辜的
(马丁·福勒)之前,注册表始终是有罪的。

Registry are always guilty until proven innocent (Martin Fowler)

如果您使用自己的 DI容器替换您的注册表,这可能是错误的。

If you're using your DI Container to replace your Registry, this is probably wrong.

例如:

//probably a Wrong usage of Registry
class NeedsRegistry
{
    public function asAParameter(Registry $pRegistry)
    {
       //Wrong dependency on registry where dependency is on Connection
       $ct = $pRegistry->getConnection();
    }

    public function asDirectAccess ()
    {
       //same mistake, more obvious as we can't use another component
       $ct = Registry::getInstance()->getConnection();
    }
}

//probably a wrong replacement for Registry using DI Container
class NeedsContainer
{
    public function asAParameter(Container $pRegistry)
    {
       //We are dependent to the container with no needs, 
       //this code should be dependent on Connection
       $ct = $pContainer->getConnection();
    }

    public function asDirectAccess ()
    {
       //should not be dependent on container
       $ct = Container::getInstance()->getConnection();
    }
}

为什么这样不好?因为您的代码与以前的依赖程度一样,所以它仍然依赖于一个没有提供明确目标的组件(注册表或容器)(我们可能会在此处想到接口)

Why is this bad? Because your code is not less dependent than before, it still depends on a component (either a registry or a container) which does not provides a clear goal (we may think of interface here)

在某些情况下,注册表模式很有用,因为它是定义组件或数据(例如,全局配置)的简单且相当便宜的方法。

The Registry-pattern be useful in some cases because it's a simple and fairly inexpensive way to define components or data (e.g. global configuration).

在不依赖DI的情况下通过消除依赖关系重构上述示例的方法是:

A way to refactor the above example without relying on DI by removing the dependency would be:

class WasNeedingARegistry
{
    public function asAParameter (Connection $pConnection)
    {
       $pConnection->doStuff();//The real dependency here, we don't care for 
       //a global registry
    }
}

//the client code would be like
$wasNeedingARegistry = new WasNeedingARegistry();
$wasNeedingARegistry->setConnection($connection);

当然,如果客户端代码不知道连接,则这可能是不可能的。

Of course, this may not be possible if the client code isn't aware of the connection, which is probably the reason why you probably ended using a Registry in the first place.

现在DI开始发挥作用了。

Now DI comes into play

使用DI使我们的生活更加美好,因为它可以处理依赖关系,并使我们能够以随时可用的状态访问依赖关系。

Using DI makes our life better because it will handle the dependency and enables us to access the dependency in a ready-to-use state.

在代码中的某些地方,您'将配置您的组件:

Somewhere in your code, you'll configure your components:

$container['connection'] = function ($container) {
    return new Connection('configuration');
};
$container['neededARegistry'] = function ($container) {
    $neededARegistry = new NeededARegistry();
    $neededARegistry->setConnection($container['connection']);
    return $neededARegistry;
};

现在您拥有重构代码所需的一切:

Now you have everything you need to refactor your code:

// probably a better design pattern for using a Registry 
class NeededARegistry
{
    public function setConnection(Connection $pConnection)
    {
       $this->connection = $pConnection;
       return $this;
    }

    public function previouslyAsDirectAccess ()
    {
       $this->connection->doStuff();
    }
}

//and the client code just needs to know about the DI container
$container['neededARegistry']->previouslyAsDirectAccess();

客户端代码应尽可能隔离。客户端应该负责并注入自己的依赖项(通过 set-方法)。客户不应负责处理其依赖项的依赖项。

The "client" code should be as isolated as possible. The client should be responsible for and inject its own dependencies (via set- methods). The client should not be responsible for handling its dependencies's dependencies.

class WrongClientCode
{
    private $connection;
    public function setConnection(Connection $pConnection)
    {
       $this->connection = $pConnection;
    }

    public function callService ()
    {
       //for the demo we use a factory here
       ServiceFactory::create('SomeId')
                       ->setConnection($this->connection)
                       ->call();
       //here, connection was propagated on the solely 
       // purpose of being passed to the Service
    }
}

class GoodClientCode
{
    private $service;
    public function setService(Service $pService)
    {
       //the only dependency is on Service, no more connection
       $this->service = $pService;
    }

    public function callService ()
    {
       $this->service->setConnection($this->connection)
                     ->call();
    }
}

DI容器将使用具有以下功能的服务配置GoodClientCode已经对其连接进行了正确配置

The DI container will configure GoodClientCode with the Service that has already been properly configured with its Connection

对于Singleton方面,是的,它将使您摆脱它们。
希望这会有所帮助

As for the Singleton aspect, yes, it will enable you to get rid of them. Hope this helps

这篇关于用DI容器替换全局$ registry对象是否是一种好习惯?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆