3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\ServiceManager
;
12 class ServiceManager
implements ServiceLocatorInterface
17 const SCOPE_PARENT
= 'parent';
18 const SCOPE_CHILD
= 'child';
22 * Lookup for canonicalized names.
26 protected $canonicalNames = [];
31 protected $allowOverride = false;
36 protected $invokableClasses = [];
39 * @var string|callable|\Closure|FactoryInterface[]
41 protected $factories = [];
44 * @var AbstractFactoryInterface[]
46 protected $abstractFactories = [];
51 protected $delegators = [];
56 protected $pendingAbstractFactoryRequests = [];
61 protected $nestedContextCounter = -1;
66 protected $nestedContext = [];
71 protected $shared = [];
74 * Registered services and cached values
78 protected $instances = [];
83 protected $aliases = [];
88 protected $initializers = [];
91 * @var ServiceManager[]
93 protected $peeringServiceManagers = [];
96 * Whether or not to share by default
100 protected $shareByDefault = true;
105 protected $retrieveFromPeeringManagerFirst = false;
108 * @var bool Track whether not to throw exceptions during create()
110 protected $throwExceptionInCreate = true;
113 * @var array map of characters to be replaced through strtr
115 protected $canonicalNamesReplacements = ['-' => '', '_' => '', ' ' => '', '\\' => '', '/' => ''];
118 * @var ServiceLocatorInterface
120 protected $serviceManagerCaller;
125 * @param ConfigInterface $config
127 public function __construct(ConfigInterface
$config = null)
130 $config->configureServiceManager($this);
137 * @param $allowOverride
138 * @return ServiceManager
140 public function setAllowOverride($allowOverride)
142 $this->allowOverride
= (bool) $allowOverride;
151 public function getAllowOverride()
153 return $this->allowOverride
;
157 * Set flag indicating whether services are shared by default
159 * @param bool $shareByDefault
160 * @return ServiceManager
161 * @throws Exception\RuntimeException if allowOverride is false
163 public function setShareByDefault($shareByDefault)
165 if ($this->allowOverride
=== false) {
166 throw new Exception\
RuntimeException(sprintf(
167 '%s: cannot alter default shared service setting; container is marked immutable (allow_override is false)',
168 get_class($this) . '::' . __FUNCTION__
171 $this->shareByDefault
= (bool) $shareByDefault;
176 * Are services shared by default?
180 public function shareByDefault()
182 return $this->shareByDefault
;
186 * Set throw exceptions in create
188 * @param bool $throwExceptionInCreate
189 * @return ServiceManager
191 public function setThrowExceptionInCreate($throwExceptionInCreate)
193 $this->throwExceptionInCreate
= $throwExceptionInCreate;
198 * Get throw exceptions in create
202 public function getThrowExceptionInCreate()
204 return $this->throwExceptionInCreate
;
208 * Set flag indicating whether to pull from peering manager before attempting creation
210 * @param bool $retrieveFromPeeringManagerFirst
211 * @return ServiceManager
213 public function setRetrieveFromPeeringManagerFirst($retrieveFromPeeringManagerFirst = true)
215 $this->retrieveFromPeeringManagerFirst
= (bool) $retrieveFromPeeringManagerFirst;
220 * Should we retrieve from the peering manager prior to attempting to create a service?
224 public function retrieveFromPeeringManagerFirst()
226 return $this->retrieveFromPeeringManagerFirst
;
230 * Set invokable class
232 * @param string $name
233 * @param string $invokableClass
234 * @param bool $shared
235 * @return ServiceManager
236 * @throws Exception\InvalidServiceNameException
238 public function setInvokableClass($name, $invokableClass, $shared = null)
240 $cName = $this->canonicalizeName($name);
242 if ($this->has([$cName, $name], false)) {
243 if ($this->allowOverride
=== false) {
244 throw new Exception\
InvalidServiceNameException(sprintf(
245 'A service by the name or alias "%s" already exists and cannot be overridden; please use an alternate name',
249 $this->unregisterService($cName);
252 if ($shared === null) {
253 $shared = $this->shareByDefault
;
256 $this->invokableClasses
[$cName] = $invokableClass;
257 $this->shared
[$cName] = (bool) $shared;
265 * @param string $name
266 * @param string|FactoryInterface|callable $factory
267 * @param bool $shared
268 * @return ServiceManager
269 * @throws Exception\InvalidArgumentException
270 * @throws Exception\InvalidServiceNameException
272 public function setFactory($name, $factory, $shared = null)
274 $cName = $this->canonicalizeName($name);
276 if (!($factory instanceof FactoryInterface ||
is_string($factory) ||
is_callable($factory))) {
277 throw new Exception\
InvalidArgumentException(sprintf(
278 'Provided factory must be the class name of a factory, callable or an instance of "%s".',
279 FactoryInterface
::class
283 if ($this->has([$cName, $name], false)) {
284 if ($this->allowOverride
=== false) {
285 throw new Exception\
InvalidServiceNameException(sprintf(
286 'A service by the name or alias "%s" already exists and cannot be overridden, please use an alternate name',
290 $this->unregisterService($cName);
293 if ($shared === null) {
294 $shared = $this->shareByDefault
;
297 $this->factories
[$cName] = $factory;
298 $this->shared
[$cName] = (bool) $shared;
304 * Add abstract factory
306 * @param AbstractFactoryInterface|string $factory
307 * @param bool $topOfStack
308 * @return ServiceManager
309 * @throws Exception\InvalidArgumentException if the abstract factory is invalid
311 public function addAbstractFactory($factory, $topOfStack = true)
313 if (!$factory instanceof AbstractFactoryInterface
&& is_string($factory)) {
314 $factory = new $factory();
317 if (!$factory instanceof AbstractFactoryInterface
) {
318 throw new Exception\
InvalidArgumentException(
319 'Provided abstract factory must be the class name of an abstract'
320 . ' factory or an instance of an AbstractFactoryInterface.'
325 array_unshift($this->abstractFactories
, $factory);
327 array_push($this->abstractFactories
, $factory);
333 * Sets the given service name as to be handled by a delegator factory
335 * @param string $serviceName name of the service being the delegate
336 * @param string $delegatorFactoryName name of the service being the delegator factory
338 * @return ServiceManager
340 public function addDelegator($serviceName, $delegatorFactoryName)
342 $cName = $this->canonicalizeName($serviceName);
344 if (!isset($this->delegators
[$cName])) {
345 $this->delegators
[$cName] = [];
348 $this->delegators
[$cName][] = $delegatorFactoryName;
356 * @param callable|InitializerInterface $initializer
357 * @param bool $topOfStack
358 * @return ServiceManager
359 * @throws Exception\InvalidArgumentException
361 public function addInitializer($initializer, $topOfStack = true)
363 if (!($initializer instanceof InitializerInterface ||
is_callable($initializer))) {
364 if (is_string($initializer)) {
365 $initializer = new $initializer;
368 if (!($initializer instanceof InitializerInterface ||
is_callable($initializer))) {
369 throw new Exception\
InvalidArgumentException('$initializer should be callable.');
374 array_unshift($this->initializers
, $initializer);
376 array_push($this->initializers
, $initializer);
382 * Register a service with the locator
384 * @param string $name
385 * @param mixed $service
386 * @return ServiceManager
387 * @throws Exception\InvalidServiceNameException
389 public function setService($name, $service)
391 $cName = $this->canonicalizeName($name);
393 if ($this->has($cName, false)) {
394 if ($this->allowOverride
=== false) {
395 throw new Exception\
InvalidServiceNameException(sprintf(
396 '%s: A service by the name "%s" or alias already exists and cannot be overridden, please use an alternate name.',
397 get_class($this) . '::' . __FUNCTION__
,
401 $this->unregisterService($cName);
404 $this->instances
[$cName] = $service;
410 * @param string $name
411 * @param bool $isShared
412 * @return ServiceManager
413 * @throws Exception\ServiceNotFoundException
415 public function setShared($name, $isShared)
417 $cName = $this->canonicalizeName($name);
419 if (!isset($this->invokableClasses
[$cName])
420 && !isset($this->factories
[$cName])
421 && !$this->canCreateFromAbstractFactory($cName, $name)
423 throw new Exception\
ServiceNotFoundException(sprintf(
424 '%s: A service by the name "%s" was not found and could not be marked as shared',
425 get_class($this) . '::' . __FUNCTION__
,
430 $this->shared
[$cName] = (bool) $isShared;
435 * @param string $name
437 * @throws Exception\ServiceNotFoundException
439 public function isShared($name)
441 $cName = $this->canonicalizeName($name);
443 if (!$this->has($name)) {
444 throw new Exception\
ServiceNotFoundException(sprintf(
445 '%s: A service by the name "%s" was not found',
446 get_class($this) . '::' . __FUNCTION__
,
451 if (!isset($this->shared
[$cName])) {
452 return $this->shareByDefault();
455 return $this->shared
[$cName];
459 * Resolve the alias for the given canonical name
461 * @param string $cName The canonical name to resolve
462 * @return string The resolved canonical name
464 protected function resolveAlias($cName)
468 while ($this->hasAlias($cName)) {
469 if (isset($stack[$cName])) {
470 throw new Exception\
CircularReferenceException(sprintf(
471 'Circular alias reference: %s -> %s',
472 implode(' -> ', $stack),
477 $stack[$cName] = $cName;
478 $cName = $this->aliases
[$this->canonicalizeName($cName)];
485 * Retrieve a registered instance
487 * @param string $name
488 * @param bool $usePeeringServiceManagers
489 * @throws Exception\ServiceNotFoundException
490 * @return object|array
492 public function get($name, $usePeeringServiceManagers = true)
494 // inlined code from ServiceManager::canonicalizeName for performance
495 if (isset($this->canonicalNames
[$name])) {
496 $cName = $this->canonicalNames
[$name];
498 $cName = $this->canonicalizeName($name);
503 if ($this->hasAlias($cName)) {
505 $name = $this->resolveAlias($cName);
506 $cName = $this->canonicalizeName($name);
511 if ($usePeeringServiceManagers && $this->retrieveFromPeeringManagerFirst
) {
512 $instance = $this->retrieveFromPeeringManager($name);
514 if (null !== $instance) {
519 if (isset($this->instances
[$cName])) {
520 return $this->instances
[$cName];
524 $this->checkNestedContextStart($cName);
525 if (isset($this->invokableClasses
[$cName])
526 ||
isset($this->factories
[$cName])
527 ||
isset($this->aliases
[$cName])
528 ||
$this->canCreateFromAbstractFactory($cName, $name)
530 $instance = $this->create([$cName, $name]);
531 } elseif ($isAlias && $this->canCreateFromAbstractFactory($name, $cName)) {
533 * case of an alias leading to an abstract factory :
534 * 'my-alias' => 'my-abstract-defined-service'
536 * $cName = 'my-abstract-defined-service'
538 $instance = $this->create([$name, $cName]);
539 } elseif ($usePeeringServiceManagers && !$this->retrieveFromPeeringManagerFirst
) {
540 $instance = $this->retrieveFromPeeringManager($name);
542 $this->checkNestedContextStop();
545 // Still no instance? raise an exception
546 if ($instance === null) {
547 $this->checkNestedContextStop(true);
549 throw new Exception\
ServiceNotFoundException(sprintf(
550 'An alias "%s" was requested but no service could be found.',
555 throw new Exception\
ServiceNotFoundException(sprintf(
556 '%s was unable to fetch or create an instance for %s',
557 get_class($this) . '::' . __FUNCTION__
,
562 if (($this->shareByDefault
&& !isset($this->shared
[$cName]))
563 ||
(isset($this->shared
[$cName]) && $this->shared
[$cName] === true)
565 $this->instances
[$cName] = $instance;
572 * Create an instance of the requested service
574 * @param string|array $name
576 * @return bool|object
578 public function create($name)
580 if (is_array($name)) {
581 list($cName, $rName) = $name;
585 // inlined code from ServiceManager::canonicalizeName for performance
586 if (isset($this->canonicalNames
[$rName])) {
587 $cName = $this->canonicalNames
[$name];
589 $cName = $this->canonicalizeName($name);
593 if (isset($this->delegators
[$cName])) {
594 return $this->createDelegatorFromFactory($cName, $rName);
597 return $this->doCreate($rName, $cName);
601 * Creates a callback that uses a delegator to create a service
603 * @param DelegatorFactoryInterface|callable $delegatorFactory the delegator factory
604 * @param string $rName requested service name
605 * @param string $cName canonical service name
606 * @param callable $creationCallback callback for instantiating the real service
610 private function createDelegatorCallback($delegatorFactory, $rName, $cName, $creationCallback)
612 return function () use ($delegatorFactory, $rName, $cName, $creationCallback) {
613 return $delegatorFactory instanceof DelegatorFactoryInterface
614 ?
$delegatorFactory->createDelegatorWithName($this, $cName, $rName, $creationCallback)
615 : $delegatorFactory($this, $cName, $rName, $creationCallback);
620 * Actually creates the service
622 * @param string $rName real service name
623 * @param string $cName canonicalized service name
625 * @return bool|mixed|null|object
626 * @throws Exception\ServiceNotFoundException
629 protected function doCreate($rName, $cName)
633 if (isset($this->factories
[$cName])) {
634 $instance = $this->createFromFactory($cName, $rName);
637 if ($instance === null && isset($this->invokableClasses
[$cName])) {
638 $instance = $this->createFromInvokable($cName, $rName);
640 $this->checkNestedContextStart($cName);
641 if ($instance === null && $this->canCreateFromAbstractFactory($cName, $rName)) {
642 $instance = $this->createFromAbstractFactory($cName, $rName);
644 $this->checkNestedContextStop();
646 if ($instance === null && $this->throwExceptionInCreate
) {
647 $this->checkNestedContextStop(true);
648 throw new Exception\
ServiceNotFoundException(sprintf(
649 'No valid instance was found for %s%s',
651 ($rName ?
'(alias: ' . $rName . ')' : '')
655 // Do not call initializers if we do not have an instance
656 if ($instance === null) {
660 foreach ($this->initializers
as $initializer) {
661 if ($initializer instanceof InitializerInterface
) {
662 $initializer->initialize($instance, $this);
664 call_user_func($initializer, $instance, $this);
672 * Determine if we can create an instance.
675 * @param string|array $name
676 * @param bool $checkAbstractFactories
678 * @deprecated this method is being deprecated as of zendframework 2.3, and may be removed in future major versions
680 public function canCreate($name, $checkAbstractFactories = true)
682 trigger_error(sprintf('%s is deprecated; please use %s::has', __METHOD__
, __CLASS__
), E_USER_DEPRECATED
);
683 return $this->has($name, $checkAbstractFactories, false);
687 * Determine if an instance exists.
689 * @param string|array $name An array argument accepts exactly two values.
690 * Example: array('canonicalName', 'requestName')
691 * @param bool $checkAbstractFactories
692 * @param bool $usePeeringServiceManagers
695 public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true)
697 if (is_string($name)) {
700 // inlined code from ServiceManager::canonicalizeName for performance
701 if (isset($this->canonicalNames
[$rName])) {
702 $cName = $this->canonicalNames
[$rName];
704 $cName = $this->canonicalizeName($name);
706 } elseif (is_array($name) && count($name) >= 2) {
707 list($cName, $rName) = $name;
712 if (isset($this->invokableClasses
[$cName])
713 ||
isset($this->factories
[$cName])
714 ||
isset($this->aliases
[$cName])
715 ||
isset($this->instances
[$cName])
716 ||
($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $rName))
721 if ($usePeeringServiceManagers) {
722 $caller = $this->serviceManagerCaller
;
723 foreach ($this->peeringServiceManagers
as $peeringServiceManager) {
724 // ignore peering service manager if they are the same instance
725 if ($caller === $peeringServiceManager) {
729 $peeringServiceManager->serviceManagerCaller
= $this;
731 if ($peeringServiceManager->has($name)) {
732 $peeringServiceManager->serviceManagerCaller
= null;
736 $peeringServiceManager->serviceManagerCaller
= null;
744 * Determine if we can create an instance from an abstract factory.
746 * @param string $cName
747 * @param string $rName
750 public function canCreateFromAbstractFactory($cName, $rName)
752 if (array_key_exists($cName, $this->nestedContext
)) {
753 $context = $this->nestedContext
[$cName];
754 if ($context === false) {
756 } elseif (is_object($context)) {
757 return !isset($this->pendingAbstractFactoryRequests
[get_class($context).$cName]);
760 $this->checkNestedContextStart($cName);
761 // check abstract factories
763 $this->nestedContext
[$cName] = false;
764 foreach ($this->abstractFactories
as $abstractFactory) {
765 $pendingKey = get_class($abstractFactory).$cName;
766 if (isset($this->pendingAbstractFactoryRequests
[$pendingKey])) {
771 if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) {
772 $this->nestedContext
[$cName] = $abstractFactory;
777 $this->checkNestedContextStop();
782 * Ensure the alias definition will not result in a circular reference
784 * @param string $alias
785 * @param string $nameOrAlias
786 * @throws Exception\CircularReferenceException
789 protected function checkForCircularAliasReference($alias, $nameOrAlias)
791 $aliases = $this->aliases
;
792 $aliases[$alias] = $this->canonicalizeName($nameOrAlias);
795 while (isset($aliases[$alias])) {
796 if (isset($stack[$alias])) {
797 throw new Exception\
CircularReferenceException(sprintf(
798 'The alias definition "%s" : "%s" results in a circular reference: "%s" -> "%s"',
801 implode('" -> "', $stack),
806 $stack[$alias] = $alias;
807 $alias = $this->canonicalizeName($aliases[$alias]);
814 * @param string $alias
815 * @param string $nameOrAlias
816 * @return ServiceManager
817 * @throws Exception\ServiceNotFoundException
818 * @throws Exception\InvalidServiceNameException
820 public function setAlias($alias, $nameOrAlias)
822 if (!is_string($alias) ||
!is_string($nameOrAlias)) {
823 throw new Exception\
InvalidServiceNameException('Service or alias names must be strings.');
826 $cAlias = $this->canonicalizeName($alias);
828 if ($alias == '' ||
$nameOrAlias == '') {
829 throw new Exception\
InvalidServiceNameException('Invalid service name alias');
832 if ($this->allowOverride
=== false && $this->has([$cAlias, $alias], false)) {
833 throw new Exception\
InvalidServiceNameException(sprintf(
834 'An alias by the name "%s" or "%s" already exists',
840 if ($this->hasAlias($alias)) {
841 $this->checkForCircularAliasReference($cAlias, $nameOrAlias);
844 $this->aliases
[$cAlias] = $nameOrAlias;
849 * Determine if we have an alias
851 * @param string $alias
854 public function hasAlias($alias)
856 return isset($this->aliases
[$this->canonicalizeName($alias)]);
860 * Create scoped service manager
862 * @param string $peering
863 * @return ServiceManager
865 public function createScopedServiceManager($peering = self
::SCOPE_PARENT
)
867 $scopedServiceManager = new ServiceManager();
868 if ($peering == self
::SCOPE_PARENT
) {
869 $scopedServiceManager->peeringServiceManagers
[] = $this;
871 if ($peering == self
::SCOPE_CHILD
) {
872 $this->peeringServiceManagers
[] = $scopedServiceManager;
874 return $scopedServiceManager;
878 * Add a peering relationship
880 * @param ServiceManager $manager
881 * @param string $peering
882 * @return ServiceManager
884 public function addPeeringServiceManager(ServiceManager
$manager, $peering = self
::SCOPE_PARENT
)
886 if ($peering == self
::SCOPE_PARENT
) {
887 $this->peeringServiceManagers
[] = $manager;
889 if ($peering == self
::SCOPE_CHILD
) {
890 $manager->peeringServiceManagers
[] = $this;
898 * @param string $name
901 protected function canonicalizeName($name)
903 if (isset($this->canonicalNames
[$name])) {
904 return $this->canonicalNames
[$name];
907 // this is just for performance instead of using str_replace
908 return $this->canonicalNames
[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements
));
912 * Create service via callback
914 * @param callable $callable
915 * @param string $cName
916 * @param string $rName
917 * @throws Exception\ServiceNotCreatedException
918 * @throws Exception\ServiceNotFoundException
919 * @throws Exception\CircularDependencyFoundException
922 protected function createServiceViaCallback($callable, $cName, $rName)
924 static $circularDependencyResolver = [];
925 $depKey = spl_object_hash($this) . '-' . $cName;
927 if (isset($circularDependencyResolver[$depKey])) {
928 $circularDependencyResolver = [];
929 throw new Exception\
CircularDependencyFoundException('Circular dependency for LazyServiceLoader was found for instance ' . $rName);
933 $circularDependencyResolver[$depKey] = true;
934 $instance = call_user_func($callable, $this, $cName, $rName);
935 unset($circularDependencyResolver[$depKey]);
936 } catch (Exception\ServiceNotFoundException
$e) {
937 unset($circularDependencyResolver[$depKey]);
939 } catch (\Exception
$e) {
940 unset($circularDependencyResolver[$depKey]);
941 throw new Exception\
ServiceNotCreatedException(
942 sprintf('An exception was raised while creating "%s"; no instance returned', $rName),
947 if ($instance === null) {
948 throw new Exception\
ServiceNotCreatedException('The factory was called but did not return an instance.');
955 * Retrieve a keyed list of all registered services. Handy for debugging!
959 public function getRegisteredServices()
962 'invokableClasses' => array_keys($this->invokableClasses
),
963 'factories' => array_keys($this->factories
),
964 'aliases' => array_keys($this->aliases
),
965 'instances' => array_keys($this->instances
),
970 * Retrieve a keyed list of all canonical names. Handy for debugging!
974 public function getCanonicalNames()
976 return $this->canonicalNames
;
980 * Allows to override the canonical names lookup map with predefined
983 * @param array $canonicalNames
984 * @return ServiceManager
986 public function setCanonicalNames($canonicalNames)
988 $this->canonicalNames
= $canonicalNames;
994 * Attempt to retrieve an instance via a peering manager
996 * @param string $name
999 protected function retrieveFromPeeringManager($name)
1001 if (null !== ($service = $this->loopPeeringServiceManagers($name))) {
1005 $name = $this->canonicalizeName($name);
1007 if ($this->hasAlias($name)) {
1009 $name = $this->aliases
[$name];
1010 } while ($this->hasAlias($name));
1013 if (null !== ($service = $this->loopPeeringServiceManagers($name))) {
1021 * Loop over peering service managers.
1023 * @param string $name
1026 protected function loopPeeringServiceManagers($name)
1028 $caller = $this->serviceManagerCaller
;
1030 foreach ($this->peeringServiceManagers
as $peeringServiceManager) {
1031 // ignore peering service manager if they are the same instance
1032 if ($caller === $peeringServiceManager) {
1036 // pass this instance to peering service manager
1037 $peeringServiceManager->serviceManagerCaller
= $this;
1039 if ($peeringServiceManager->has($name)) {
1040 $this->shared
[$name] = $peeringServiceManager->isShared($name);
1041 $instance = $peeringServiceManager->get($name);
1042 $peeringServiceManager->serviceManagerCaller
= null;
1046 $peeringServiceManager->serviceManagerCaller
= null;
1053 * Attempt to create an instance via an invokable class
1055 * @param string $canonicalName
1056 * @param string $requestedName
1057 * @return null|\stdClass
1058 * @throws Exception\ServiceNotFoundException If resolved class does not exist
1060 protected function createFromInvokable($canonicalName, $requestedName)
1062 $invokable = $this->invokableClasses
[$canonicalName];
1063 if (!class_exists($invokable)) {
1064 throw new Exception\
ServiceNotFoundException(sprintf(
1065 '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist',
1066 get_class($this) . '::' . __FUNCTION__
,
1068 ($requestedName ?
'(alias: ' . $requestedName . ')' : ''),
1072 $instance = new $invokable;
1077 * Attempt to create an instance via a factory
1079 * @param string $canonicalName
1080 * @param string $requestedName
1082 * @throws Exception\ServiceNotCreatedException If factory is not callable
1084 protected function createFromFactory($canonicalName, $requestedName)
1086 $factory = $this->factories
[$canonicalName];
1087 if (is_string($factory) && class_exists($factory, true)) {
1088 $factory = new $factory;
1089 $this->factories
[$canonicalName] = $factory;
1091 if ($factory instanceof FactoryInterface
) {
1092 $instance = $this->createServiceViaCallback([$factory, 'createService'], $canonicalName, $requestedName);
1093 } elseif (is_callable($factory)) {
1094 $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName);
1096 throw new Exception\
ServiceNotCreatedException(sprintf(
1097 'While attempting to create %s%s an invalid factory was registered for this instance type.',
1099 ($requestedName ?
'(alias: ' . $requestedName . ')' : '')
1106 * Attempt to create an instance via an abstract factory
1108 * @param string $canonicalName
1109 * @param string $requestedName
1110 * @return object|null
1111 * @throws Exception\ServiceNotCreatedException If abstract factory is not callable
1113 protected function createFromAbstractFactory($canonicalName, $requestedName)
1115 if (isset($this->nestedContext
[$canonicalName])) {
1116 $abstractFactory = $this->nestedContext
[$canonicalName];
1117 $pendingKey = get_class($abstractFactory).$canonicalName;
1119 $this->pendingAbstractFactoryRequests
[$pendingKey] = true;
1120 $instance = $this->createServiceViaCallback(
1121 [$abstractFactory, 'createServiceWithName'],
1125 unset($this->pendingAbstractFactoryRequests
[$pendingKey]);
1127 } catch (\Exception
$e) {
1128 unset($this->pendingAbstractFactoryRequests
[$pendingKey]);
1129 $this->checkNestedContextStop(true);
1130 throw new Exception\
ServiceNotCreatedException(
1132 'An abstract factory could not create an instance of %s%s.',
1134 ($requestedName ?
'(alias: ' . $requestedName . ')' : '')
1146 * @param string $cName
1149 protected function checkNestedContextStart($cName)
1151 if ($this->nestedContextCounter
=== -1 ||
!isset($this->nestedContext
[$cName])) {
1152 $this->nestedContext
[$cName] = null;
1154 $this->nestedContextCounter++
;
1160 * @param bool $force
1163 protected function checkNestedContextStop($force = false)
1166 $this->nestedContextCounter
= -1;
1167 $this->nestedContext
= [];
1171 $this->nestedContextCounter
--;
1172 if ($this->nestedContextCounter
=== -1) {
1173 $this->nestedContext
= [];
1179 * @param $canonicalName
1180 * @param $requestedName
1182 * @throws Exception\ServiceNotCreatedException
1184 protected function createDelegatorFromFactory($canonicalName, $requestedName)
1186 $delegatorsCount = count($this->delegators
[$canonicalName]);
1187 $creationCallback = function () use ($requestedName, $canonicalName) {
1188 return $this->doCreate($requestedName, $canonicalName);
1191 for ($i = 0; $i < $delegatorsCount; $i +
= 1) {
1192 $delegatorFactory = $this->delegators
[$canonicalName][$i];
1194 if (is_string($delegatorFactory)) {
1195 $delegatorFactory = !$this->has($delegatorFactory) && class_exists($delegatorFactory, true) ?
1196 new $delegatorFactory
1197 : $this->get($delegatorFactory);
1198 $this->delegators
[$canonicalName][$i] = $delegatorFactory;
1201 if (!$delegatorFactory instanceof DelegatorFactoryInterface
&& !is_callable($delegatorFactory)) {
1202 throw new Exception\
ServiceNotCreatedException(sprintf(
1203 'While attempting to create %s%s an invalid factory was registered for this instance type.',
1205 ($requestedName ?
'(alias: ' . $requestedName . ')' : '')
1209 $creationCallback = $this->createDelegatorCallback(
1217 return $creationCallback($this, $canonicalName, $requestedName, $creationCallback);
1221 * Checks if the object has this class as one of its parents
1223 * @see https://bugs.php.net/bug.php?id=53727
1224 * @see https://github.com/zendframework/zf2/pull/1807
1226 * @deprecated since zf 2.3 requires PHP >= 5.3.23
1228 * @param string $className
1229 * @param string $type
1232 * @deprecated this method is being deprecated as of zendframework 2.2, and may be removed in future major versions
1234 protected static function isSubclassOf($className, $type)
1236 return is_subclass_of($className, $type);
1240 * Unregister a service
1242 * Called when $allowOverride is true and we detect that a service being
1243 * added to the instance already exists. This will remove the duplicate
1244 * entry, and also any shared flags previously registered.
1246 * @param string $canonical
1249 protected function unregisterService($canonical)
1251 $types = ['invokableClasses', 'factories', 'aliases'];
1252 foreach ($types as $type) {
1253 if (isset($this->{$type}[$canonical])) {
1254 unset($this->{$type}[$canonical]);
1259 if (isset($this->instances
[$canonical])) {
1260 unset($this->instances
[$canonical]);
1263 if (isset($this->shared
[$canonical])) {
1264 unset($this->shared
[$canonical]);