Php Zend 2最佳实践-控制器外侧的服务定位器

Php Zend 2最佳实践-控制器外侧的服务定位器,php,zend-framework,zend-framework2,Php,Zend Framework,Zend Framework2,我刚接触Zend 2,有这种情况。我想知道处理这种情况的最好方法是什么 在应用程序模块中,我有这些类 namespace Application\Foo; class Base { protected $this->services; //service locator public function myFunc() { //needs service locator here $this->services; } }

我刚接触Zend 2,有这种情况。我想知道处理这种情况的最好方法是什么

在应用程序模块中,我有这些类

namespace Application\Foo;

class Base {
    protected $this->services; //service locator
    public function myFunc() {
        //needs service locator here
        $this->services;
    }
}



如您所见,我需要基类中的服务定位器。然后我想用A,B。。。我的控制器中的扩展类

谢谢你的建议


更新

根据jmleroux的建议,我更新了代码,使其看起来像这样

namespace Application\Foo;

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class Base implements ServiceLocatorAwareInterface {
    protected $this->services; //service locator

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
        $this->services = $serviceLocator;
    }

    public function getServiceLocator() {
        return $this->services;
    }


    public function myFunc() {
        //needs service locator here
        $this->services;
    }
}
module.conf.php

service_manager => array(
    'invokables' => array(
        'my_ser' => 'Application\Foo\Base'
    )
)
在我的控制器中

$this->serviceLocator->get('my_ser'); 
返回已加载服务定位器的基类

现在我的问题是如何在加载服务定位器的情况下获得扩展类(A,B…)。自

$x = new \Application\Foo\A(); 
未加载服务定位器。我是否必须将所有扩展类作为可调用项添加到模块配置中?还是有更好的选择

再次感谢


更新2

特别感谢大家(@jmleroux)的支持。找到了这些解决方案,我将它们添加到这里,认为这会帮助其他人

注意:只是一个大概的想法。名称空间和类名不准确

解决方案1(推荐)-带有ServiceLocatorAwareInterface/ServiceLocatorAwareTrit for php 5.4+

每个类实现ServiceLocatorAwareInterface并将其添加到服务管理器

namespace Application\Foor;

class A implements ServiceLocatorAwareInterface {
protected $services;

public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
    $this->services = $serviceLocator;
}

public function getServiceLocator() {
        return $this->services;
    }
}

class B implements ServiceLocatorAwareInterface {
    use ServiceLocatorAwareTrait;
}
module.conf.php(或在模块getServiceConfig()函数内)

在控制器内按名称调用服务


解决方案2-使用AbstractFactoryInterface

创建一个工厂类

class MyFac implements AbstractFactoryInterface {
    public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
        if (class_exists($requestedName)){ \\eg. check Application\Foo\A exists
            return true;
        }

        return false;
    }

    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
        $class = new $requestedName;   \\eg. creates an instance of Application\Foo\A
        $class->setServiceLocator($locator); \\make sure your class has this method 
        return new $class;
    }
}
module.conf.php(或在模块getServiceConfig()函数内)

在控制器中调用

$this->getServiceLocator()->get('Application\Foo\A');

谢谢。

为了访问服务定位器,需要将基类声明为可调用的服务


如果您使用的是PHP5.4+,则可以使用

谢谢。我已经更新了代码。如果
Base
的目的只是提供一个服务定位器,那么不要使用它。特别是在PHP5.4下,只需实现接口并使用
ServiceLocatorAwareTrit
并将类A和B声明为可调用的。如果您真的想集中实例化,还可以使用
AbstractFactory
来回答您的新问题如果您想注入服务定位器,那么您必须将所有子类作为可调用的并通过服务管理器加载。如果您只是用new实例化它们,那么即使父对象是可调用的,它也不会起作用。谢谢大家,对于我目前的情况,使用ServiceLocatorAwareInterface似乎是最好的选择@jmleroux仅供将来参考,我想知道如何实现AbstractFactory,你能给我举个好例子吗?这篇文章很清楚:谢谢。这篇文章帮助了我。
'service_manager' => array(
    'invokables' => array(
        'my_ser_a' => 'Application\Foo\A',
        'my_ser_b' => 'Application\Foo\B',
        ......
    )
)
class MyFac implements AbstractFactoryInterface {
    public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
        if (class_exists($requestedName)){ \\eg. check Application\Foo\A exists
            return true;
        }

        return false;
    }

    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
        $class = new $requestedName;   \\eg. creates an instance of Application\Foo\A
        $class->setServiceLocator($locator); \\make sure your class has this method 
        return new $class;
    }
}
'service_manager' => array(
    'abstract_factories' => array(
        'Application\Foo\MyFac'
    )
)
$this->getServiceLocator()->get('Application\Foo\A');