【问题标题】:Zend_Registry: real life examplesZend_Registry:现实生活中的例子
【发布时间】:2010-03-27 22:26:59
【问题描述】:

你觉得Zend_Registry 有用吗?

它应该用于哪些任务?哪个不是?

变量的全局状态不是一个好习惯。 主要对象可能具有通过$front->setParam('paramName', $object) 注入的全局状态, 那么 Zend_Registry 的目的是什么?

【问题讨论】:

  • 您应该将Zend_RegistryZend_Registry::getInstance()-singelton 区分开来。该类本身在 ZF 内部使用而不是全局的,因此 Zend_Registry != global。

标签: php zend-framework global-variables


【解决方案1】:

引用PoEAA on Registry Pattern:

当您想要找到一个对象时,您通常会从另一个与之关联的对象开始,并使用该关联来导航到它。因此,如果您想查找客户的所有订单,您可以从客户对象开始,并在其上使用方法来获取订单。但是,在某些情况下,您将没有合适的对象开始。您可能知道客户的 ID 号,但没有参考。在这种情况下,您需要某种查找方法 - 查找器 - 但问题仍然存在:您如何找到查找器?

我使用注册表的主要原因(当我使用它时)是因为它创建了一个易于访问的应用程序范围。使用注册表,我不必在全局范围内乱扔对象;只有注册表本身是全局的。可以很方便地从任何地方查找我放入注册表的任何内容,包括模型:

  • Zend_Cache、Zend_Translate、重要应用路径等

但是,就像 Singletons 一样,Registry 也经常受到反对。这是article by Brandon Savage with some thought about why not to use the Registry。反对注册表的主要论点是

  • 它使单元测试更加困难
  • 没有经验的编码人员可能会投入太多而不关心正确的设计

那些投票反对注册表的人通常主张使用Dependency Injection,尽管应该注意的是,一旦你获得了它的实例,你也可以注入注册表。但是,您没有Inversion of Control,因为使用对象将从注册表中提取所需的内容。不过,使用注册表作为服务定位器是一种有效的方法。

看到这个article by Martin Fowler about ServiceLocator vs. Dependency Injection

就像 cmets 在您的问题中指出的那样,Zend_Registry 不是严格的单身人士。除了使用通过Zend_Registry::getInstance() 获得的全局实例之外,您还可以在需要时实例化多个实例。所以对象可以有自己的注册表。但是这样使用 Registry 时,它基本上只是一个美化的 ArrayObject。

最后说明:就像所有设计模式一样,如果适用于您的问题,请使用它。

【讨论】:

    【解决方案2】:

    当您使用$front->setParam 时,您是在前端控制器中定义一个参数。

    但该参数在(或不应从)应用程序的其他层(例如模型)中不可用。

    Zend_Registry 与任何其他全局变量一样,可从应用程序的任何位置(包括模型内部)使用。

    但是使用注册表而不是一堆全局变量可以确保您不会在任何地方都有很多全局变量:即使使用注册表意味着一些全局状态(应该说不是那么好) em>,最好把所有东西都放在一个地方。


    几个现实生活中的例子可能是:

    • 存储与数据库的连接,该连接在 bootsreap 中建立,但在模型中使用
    • 全局存储一个适配器(或任何机制),该适配器将用于在应用程序的所有层中进行翻译/本地化——Zend 框架本身就是这样做的。


    最后,我觉得Zend_Registry有用吗?

    好吧,当涉及到一些全局状态时,是的,它很有用。

    但是如果可以避免使用它,它可能会更好:从概念上讲,不让你的类依赖于任何全局状态会更好:更容易重用,更容易测试,...
    关于这一点,您可能想看看 Dependency Injection 是什么。

    【讨论】:

    • $front->setParam 不是依赖注入吗? Zend 应用程序资源呢?
    【解决方案3】:

    我同意Pascal MARTIN。我刚开始习惯于依赖注入。但是我还没有找到在控制器中注入对象的方法,所以我最近做的是使用 de registry 来访问控制器中的服务。在当前项目中,我正在执行以下操作:

    引导程序:

    // simple DI without an IoC container, and what have you
    $dbAdapter    = Zend_Db::factory( /* bla bla */ );
    $mediaService = new Service_Media( new Repository_Media_Db( $dbAdapter ) );
    $registry     = Zend_Registry::getInstance();
    $registry->mediaService = $mediaService;
    

    ...然后在控制器中:

    public function init()
    {
        $this->_mediaService = Zend_Registry::get( 'mediaService' );
    }
    
    public function listAction()
    {
        // simplified
        $this->view->media = $this->_mediaService->listAllUploadedVideos();
    }
    

    希望这是对您有用的示例。

    【讨论】:

    • 这里真的需要注册表吗?动作助手还不够吗?
    • 我通常做的:_initMediaService(){return $service;};,然后在action controller中:$front->getParam('mediaService');
    • 我猜动作助手也是一个不错的选择。那就是......只要它只在控制器中需要。但是您可能会遇到其他服务或业务层也需要此服务的情况。虽然我猜这可以通过构造函数注入来解决。嗯.. 如您所见,我还没有真正深入地考虑过它。到目前为止,这个例子适合我的目的。我想有很多方法可以完成一项任务。我猜这完全取决于你想采取多少纯粹主义者的方法。一旦我更深入地研究 DI,我可能会放弃这种方法。
    • 至于您的第二条评论;我还没有使用新的 OOP 引导方法(仍在使用过程引导)。但是我假设,从您的示例中,_init 方法会自动将返回值分配给前端控制器中的参数?这可能是一种选择。但是就像 Pascal 提到的,并且根据我之前的评论,除了控制器(也许还有查看助手)之外,您不应该在其他层中使用它。您不想将业务层绑定到前端控制器。他们没有任何业务知道前端控制器。
    猜你喜欢
    • 2011-12-13
    • 2012-01-27
    • 1970-01-01
    • 2010-11-23
    • 2016-10-26
    • 2011-07-16
    • 1970-01-01
    • 2016-12-26
    • 2012-03-05
    相关资源
    最近更新 更多