“Service locator”是一种设计模式,主体思想是把系统运行过程中用到的各种资源统一由一个中央注册表登记管理,当系统需要某个资源时,直接从”Service locator”获取。
zf2中加入了Zend\ServiceManager模块,这个模块可以将数组,对象等资源进行统一管理,系统需要使用某个数组或者对象时就可以直接通过ServiceManager来获取,这里提到的资源在Serviece locator模式里就是’服务’。
1. 使用ServiceManager
1.1 ServiceManager::setService通过类的实例注册一个服务
$serviceManager = new Zend\ServiceManager\ServiceManager(); $serviceManager->setService('my-object', new stdClass()); $stdClass = $serviceManager->get('my-object'); var_dump($stdClass); /** output object(stdClass)#3 (0) { } */
通过这种方式系统能够把某个”资源”,比如一个对象的实例注册到ServiceManager, 之后就可以方便的调用。
ServiceManager::setService的内部逻辑:
public function setService($name, $service) { ... $this->instances[$cName] = $service; return $this; } public function get($name, $usePeeringServiceManagers = true) { ... if (isset($this->instances[$cName])) { return $this->instances[$cName]; } ... }
ServiceManager将$service保存到属性protected $instances = array()中,当调用ServiceManager::get时,ServiceManager直接从$this->instances找到对应的$service并返回给调用者。
1.2 ServiceManager::setInvokableClass 通过类的名称注册一个服务,设置延时加载某个class,当收到服务请求时实例化这个class
$serviceManager->setInvokableClass('request', 'Zend\Http\Request'); $request = $serviceManager->get('request'); var_dump($request); /** output object(Zend\Http\Request)#4 (9) { ["method":protected]=> string(3) "GET" ["uri":protected]=> NULL ["queryParams":protected]=> NULL ["postParams":protected]=> NULL ["fileParams":protected]=> NULL ["version":protected]=> string(3) "1.1" ["headers":protected]=> NULL ["metadata":protected]=> array(0) { } ["content":protected]=> string(0) "" } */
ServiceManager::setInvokableClass的内部逻辑
public function setInvokableClass($name, $invokableClass, $shared = null) { ... $this->invokableClasses[$cName] = $invokableClass; ... return $this; } // 此方法最终有ServiceManager::get()调用 public function doCreate($rName, $cName) { $instance = false; ... if ($instance === false && isset($this->invokableClasses[$cName])) { // 调用$this->createFromInvokable($cName, $rName) $instance = $this->createFromInvokable($cName, $rName); } ... return $instance; } protected function createFromInvokable($canonicalName, $requestedName) { $invokable = $this->invokableClasses[$canonicalName]; ... // 创建一个实例 $instance = new $invokable; return $instance; }
ServiceManager::setInvokableClass将$invokableClass保存到属性protected $invokableClasses = array()中,当调用ServiceManager::get时,ServiceManager在属性$this->invokableClasses中找到对应的$invokableClass后,创建一个$invokableClass的实例,保存到$this->instances中,并且将实例返回给调用者。
1.3 ServiceManager::setFactory 通过工厂类(这个工厂类必须实现了Zend\ServiceManager\FactoryInterface中的createService()方法)的名称注册一个服务,当收到服务请求时,ServiceManager将调用对应的工厂类中createService()方法,以获取到对应的服务实例
$serviceManager->setInvokableClass('SharedEventManager', 'Zend\EventManager\SharedEventManager'); $serviceManager->setFactory('EventManager', 'Zend\Mvc\Service\EventManagerFactory'); $eventManager = $serviceManager->get('EventManager'); var_dump($eventManager); /** output object(Zend\EventManager\EventManager)#6 (4) { ["events":protected]=> array(0) { } ["eventClass":protected]=> string(23) "Zend\EventManager\Event" ["identifiers":protected]=> array(0) { } ["sharedManager":protected]=> object(Zend\EventManager\SharedEventManager)#7 (1) { ["identifiers":protected]=> array(0) { } } } */
ServiceManager::setFactory的内部逻辑
public function setFactory($name, $factory, $shared = null) { ... $this->factories[$cName] = $factory; ... return $this; } // 此方法最终有ServiceManager::get()调用 public function doCreate($rName, $cName) { $instance = false; if (isset($this->factories[$cName])) { // 调用$this->createFromFactory($cName, $rName) $instance = $this->createFromFactory($cName, $rName); } ... return $instance; } protected function createFromFactory($canonicalName, $requestedName) { $factory = $this->factories[$canonicalName]; if (is_string($factory) && class_exists($factory, true)) { $factory = new $factory; $this->factories[$canonicalName] = $factory; } if ($factory instanceof FactoryInterface) { // 调用工厂类提供的createService()方法 $instance = $this->createServiceViaCallback(array($factory, 'createService'), $canonicalName, $requestedName); } elseif (is_callable($factory)) { $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName); } else { ... } return $instance; }
ServiceManager::setFactory将工厂类的名称$factory保存到属性protected $factories = array()中,当调用ServiceManager::get时,ServiceManager在$factory中找到对应的工厂类,并完成以下步骤:
step1. 创建工厂类$factory的实例,并将这个实例保存到属性$this->factories中
比如上面的例子,ServiceManager将创建Zend\Mvc\Service\EventManagerFactory的一个实例
step2. 调用工厂类$factory实例的createService()方法,获取到该工厂类生产的对应的实例
比如上面的例子,ServiceManager将调用Zend\Mvc\Service\EventManagerFactory的实例的createService()方法,在createService()方法中,将返回一个Zend\EventManager\EventManager的实例
step3. ServiceManager将,获取到该工厂类生产的对应的实例保存到属性$this->instances, 并将实例返回给调用者
1.4 ServiceManager::setAlias 给已注册的服务设置别名,已注册的服务可以是通过setService,setInvokableClass,setFactory设置的服务
$serviceManager = new Zend\ServiceManager\ServiceManager(); $serviceManager->setService('my-object', new stdClass()); $serviceManager->setInvokableClass('request', 'Zend\Http\Request'); $serviceManager->setInvokableClass('SharedEventManager', 'Zend\EventManager\SharedEventManager'); $serviceManager->setFactory('EventManager', 'Zend\Mvc\Service\EventManagerFactory'); $serviceManager->setAlias('my-object-alias', 'my-object'); $serviceManager->setAlias('request-alias', 'request'); $serviceManager->setAlias('EventManager-alias', 'EventManager'); var_dump($serviceManager->get('my-object-alias')); var_dump($serviceManager->get('request-alias')); var_dump($serviceManager->get('EventManager-alias')); /** output object(stdClass)#3 (0) { } object(Zend\Http\Request)#4 (9) { ["method":protected]=> string(3) "GET" ["uri":protected]=> NULL ["queryParams":protected]=> NULL ["postParams":protected]=> NULL ["fileParams":protected]=> NULL ["version":protected]=> string(3) "1.1" ["headers":protected]=> NULL ["metadata":protected]=> array(0) { } ["content":protected]=> string(0) "" } object(Zend\EventManager\EventManager)#6 (4) { ["events":protected]=> array(0) { } ["eventClass":protected]=> string(23) "Zend\EventManager\Event" ["identifiers":protected]=> array(0) { } ["sharedManager":protected]=> object(Zend\EventManager\SharedEventManager)#7 (1) { ["identifiers":protected]=> array(0) { } } } */
ServiceManager::setAlias的内部逻辑
public function setAlias($alias, $nameOrAlias) { ... $cAlias = $this->canonicalizeName($alias); $nameOrAlias = $this->canonicalizeName($nameOrAlias); ... $this->aliases[$cAlias] = $nameOrAlias; return $this; } public function get($name, $usePeeringServiceManagers = true) { ... // 如果别名存在,则找到真正的服务名称赋值给$cName if (isset($this->aliases[$cName])) { $isAlias = true; do { $cName = $this->aliases[$cName]; } while ($this->hasAlias($cName)); } // 下面的逻辑根据真正的服务名去定位服务实例并返回 ... }
ServiceManager::setAlias将服务的别名保存到属性protected $aliases = array()中,当调用ServiceManager::get时,ServiceManager先到$this->alias如果匹配到对应的别名,就能够找到对应的真正的服务名,再用真正的服务名去定位服务实例并返回,这个过程就和上面的1.1,1.2,1.3的定位逻辑一样了
1.5 ServiceManager::addAbstractFactory 添加抽象工厂类,为service服务提供fallback机制
class MyAbstractFactory implements AbstractFactoryInterface { public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) { // this abstract factory only knows about 'foo' and 'bar' return $requestedName === 'foo' || $requestedName === 'bar'; } public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName) { $service = new \stdClass(); $service->name = $requestedName; return $service; } } $serviceManager->addAbstractFactory('MyAbstractFactory'); var_dump($serviceManager->get('foo')->name); /** output string(3) "foo" */
ServiceManager::addAbstractFactory的内部逻辑
public function addAbstractFactory($factory, $topOfStack = true) { if (!$factory instanceof AbstractFactoryInterface && is_string($factory)) { $factory = new $factory(); } ... if ($topOfStack) { array_unshift($this->abstractFactories, $factory); } else { array_push($this->abstractFactories, $factory); } return $this; } // 此方法最终由ServiceManager::get()调用 public function doCreate($rName, $cName) { $instance = false; if (isset($this->factories[$cName])) { $instance = $this->createFromFactory($cName, $rName); } if ($instance === false && isset($this->invokableClasses[$cName])) { $instance = $this->createFromInvokable($cName, $rName); } // 在$this->instances, $this->factories,$this->invokableClasses都没有定位到请求的服务时, // 到$this->abstractFactories中去查找,具体看下面的createFromAbstractFactory($cName, $rName)的代码 if ($instance === false && $this->canCreateFromAbstractFactory($cName, $rName)) { $instance = $this->createFromAbstractFactory($cName, $rName); } ... return $instance; } // 此方法最终由ServiceManager::get()调用 protected function createFromAbstractFactory($canonicalName, $requestedName) { foreach ($this->abstractFactories as $index => $abstractFactory) { if (is_string($abstractFactory) && class_exists($abstractFactory, true)) { // 创建抽象工厂类的实例 $this->abstractFactories[$index] = $abstractFactory = new $abstractFactory; } elseif (!$abstractFactory instanceof AbstractFactoryInterface) { .... } try { <strong>// 调用抽象工厂的方法canCreateServiceWithName($this, $canonicalName, $requestedName)</strong> if ($abstractFactory->canCreateServiceWithName($this, $canonicalName, $requestedName)) { $this->pendingAbstractFactoryRequests[get_class($abstractFactory)] = $requestedName; // 调用抽象工厂的方法createServiceWithName $instance = $this->createServiceViaCallback( array($abstractFactory, 'createServiceWithName'), $canonicalName, $requestedName ); unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]); } else { $instance = false; } } catch (\Exception $e) { ... } if (is_object($instance)) { break; } } return $instance; }
ServiceManager创建一个$factory的实例,并把实例保存到属性protected $abstractFactories = array()中,这里的参数$factory必须是一个抽象工厂类,必须实现了AbstractFactoryInterface接口中定义的两个方法canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)和createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName),当ServiceManager收到get请求后,如果在$instance,$invokableClasses,$factories,$aliases中没有找到对应的服务,ServiceManager会遍历调用$abstractFactories中每个abstractFactory提供的方法canCreateServiceWithName()和createServiceWithName(),直到获取到一个service对象
1.6 ServiceManager::addInitializer 添加初始化控制器,为service服务提供callback机制
use Zend\ServiceManager\ServiceLocatorInterface; use Zend\ServiceManager\InitializerInterface; class MyInitializer implements InitializerInterface { public function initialize($instance, ServiceLocatorInterface $serviceLocator) { if ($instance instanceof \stdClass) { $instance->initialized = 'initialized!'; } } } $serviceManager->setInvokableClass('my-service', 'stdClass'); var_dump($serviceManager->get('my-service')->initialized); /** output string(12) "initialized!" */
ServiceManager::addInitializer的内部逻辑
public function addInitializer($initializer, $topOfStack = true) { if (!($initializer instanceof InitializerInterface || is_callable($initializer))) { if (is_string($initializer)) { $initializer = new $initializer; } ... } if ($topOfStack) { array_unshift($this->initializers, $initializer); } else { array_push($this->initializers, $initializer); } return $this; } // 此方法最终由ServiceManager::get()调用 public function doCreate($rName, $cName) { $instance = false; if (isset($this->factories[$cName])) { $instance = $this->createFromFactory($cName, $rName); } if ($instance === false && isset($this->invokableClasses[$cName])) { $instance = $this->createFromInvokable($cName, $rName); } if ($instance === false && $this->canCreateFromAbstractFactory($cName, $rName)) { $instance = $this->createFromAbstractFactory($cName, $rName); } ... // 到这里时$instance已被创建,以下将调用初始化管理器 foreach ($this->initializers as $initializer) { if ($initializer instanceof InitializerInterface) { $initializer->initialize($instance, $this); } else { call_user_func($initializer, $instance, $this); } } return $instance; }
ServiceManager创建$initializer的一个实例,并把实例保存到属性protected $initializers = array()中,当调用ServiceManager::get()时,serviceManager内部在创建了对应的服务实例后,会遍历调用$this->initializers中每个$initializer,每个$initializer内部可以设置初始化的逻辑。