'', '_' => '', ' ' => '', '\\' => '', '/' => ''); /** * Constructor * * @param ConfigInterface $config */ public function __construct(ConfigInterface $config = null) { if ($config) { $config->configureServiceManager($this); } } /** * Set allow override * * @param $allowOverride * @return ServiceManager */ public function setAllowOverride($allowOverride) { $this->allowOverride = (bool) $allowOverride; return $this; } /** * Get allow override * * @return bool */ public function getAllowOverride() { return $this->allowOverride; } /** * Set flag indicating whether services are shared by default * * @param bool $shareByDefault * @return ServiceManager * @throws Exception\RuntimeException if allowOverride is false */ public function setShareByDefault($shareByDefault) { if ($this->allowOverride === false) { throw new Exception\RuntimeException(sprintf( '%s: cannot alter default shared service setting; container is marked immutable (allow_override is false)', get_class($this) . '::' . __FUNCTION__ )); } $this->shareByDefault = (bool) $shareByDefault; return $this; } /** * Are services shared by default? * * @return bool */ public function shareByDefault() { return $this->shareByDefault; } /** * Set throw exceptions in create * * @param bool $throwExceptionInCreate * @return ServiceManager */ public function setThrowExceptionInCreate($throwExceptionInCreate) { $this->throwExceptionInCreate = $throwExceptionInCreate; return $this; } /** * Get throw exceptions in create * * @return bool */ public function getThrowExceptionInCreate() { return $this->throwExceptionInCreate; } /** * Set flag indicating whether to pull from peering manager before attempting creation * * @param bool $retrieveFromPeeringManagerFirst * @return ServiceManager */ public function setRetrieveFromPeeringManagerFirst($retrieveFromPeeringManagerFirst = true) { $this->retrieveFromPeeringManagerFirst = (bool) $retrieveFromPeeringManagerFirst; return $this; } /** * Should we retrieve from the peering manager prior to attempting to create a service? * * @return bool */ public function retrieveFromPeeringManagerFirst() { return $this->retrieveFromPeeringManagerFirst; } /** * Set invokable class * * @param string $name * @param string $invokableClass * @param bool $shared * @return ServiceManager * @throws Exception\InvalidServiceNameException */ public function setInvokableClass($name, $invokableClass, $shared = null) { $cName = $this->canonicalizeName($name); if ($this->has(array($cName, $name), false)) { if ($this->allowOverride === false) { throw new Exception\InvalidServiceNameException(sprintf( 'A service by the name or alias "%s" already exists and cannot be overridden; please use an alternate name', $name )); } $this->unregisterService($cName); } if ($shared === null) { $shared = $this->shareByDefault; } $this->invokableClasses[$cName] = $invokableClass; $this->shared[$cName] = (bool) $shared; return $this; } /** * Set factory * * @param string $name * @param string|FactoryInterface|callable $factory * @param bool $shared * @return ServiceManager * @throws Exception\InvalidArgumentException * @throws Exception\InvalidServiceNameException */ public function setFactory($name, $factory, $shared = null) { $cName = $this->canonicalizeName($name); if (!($factory instanceof FactoryInterface || is_string($factory) || is_callable($factory))) { throw new Exception\InvalidArgumentException( 'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.' ); } if ($this->has(array($cName, $name), false)) { if ($this->allowOverride === false) { throw new Exception\InvalidServiceNameException(sprintf( 'A service by the name or alias "%s" already exists and cannot be overridden, please use an alternate name', $name )); } $this->unregisterService($cName); } if ($shared === null) { $shared = $this->shareByDefault; } $this->factories[$cName] = $factory; $this->shared[$cName] = (bool) $shared; return $this; } /** * Add abstract factory * * @param AbstractFactoryInterface|string $factory * @param bool $topOfStack * @return ServiceManager * @throws Exception\InvalidArgumentException if the abstract factory is invalid */ public function addAbstractFactory($factory, $topOfStack = true) { if (!$factory instanceof AbstractFactoryInterface && is_string($factory)) { $factory = new $factory(); } if (!$factory instanceof AbstractFactoryInterface) { throw new Exception\InvalidArgumentException( 'Provided abstract factory must be the class name of an abstract' . ' factory or an instance of an AbstractFactoryInterface.' ); } if ($topOfStack) { array_unshift($this->abstractFactories, $factory); } else { array_push($this->abstractFactories, $factory); } return $this; } /** * Sets the given service name as to be handled by a delegator factory * * @param string $serviceName name of the service being the delegate * @param string $delegatorFactoryName name of the service being the delegator factory * * @return ServiceManager */ public function addDelegator($serviceName, $delegatorFactoryName) { $cName = $this->canonicalizeName($serviceName); if (!isset($this->delegators[$cName])) { $this->delegators[$cName] = array(); } $this->delegators[$cName][] = $delegatorFactoryName; return $this; } /** * Add initializer * * @param callable|InitializerInterface $initializer * @param bool $topOfStack * @return ServiceManager * @throws Exception\InvalidArgumentException */ public function addInitializer($initializer, $topOfStack = true) { if (!($initializer instanceof InitializerInterface || is_callable($initializer))) { if (is_string($initializer)) { $initializer = new $initializer; } if (!($initializer instanceof InitializerInterface || is_callable($initializer))) { throw new Exception\InvalidArgumentException('$initializer should be callable.'); } } if ($topOfStack) { array_unshift($this->initializers, $initializer); } else { array_push($this->initializers, $initializer); } return $this; } /** * Register a service with the locator * * @param string $name * @param mixed $service * @return ServiceManager * @throws Exception\InvalidServiceNameException */ public function setService($name, $service) { $cName = $this->canonicalizeName($name); if ($this->has($cName, false)) { if ($this->allowOverride === false) { throw new Exception\InvalidServiceNameException(sprintf( '%s: A service by the name "%s" or alias already exists and cannot be overridden, please use an alternate name.', get_class($this) . '::' . __FUNCTION__, $name )); } $this->unregisterService($cName); } $this->instances[$cName] = $service; return $this; } /** * @param string $name * @param bool $isShared * @return ServiceManager * @throws Exception\ServiceNotFoundException */ public function setShared($name, $isShared) { $cName = $this->canonicalizeName($name); if ( !isset($this->invokableClasses[$cName]) && !isset($this->factories[$cName]) && !$this->canCreateFromAbstractFactory($cName, $name) ) { throw new Exception\ServiceNotFoundException(sprintf( '%s: A service by the name "%s" was not found and could not be marked as shared', get_class($this) . '::' . __FUNCTION__, $name )); } $this->shared[$cName] = (bool) $isShared; return $this; } /** * Resolve the alias for the given canonical name * * @param string $cName The canonical name to resolve * @return string The resolved canonical name */ protected function resolveAlias($cName) { $stack = array(); while ($this->hasAlias($cName)) { if (isset($stack[$cName])) { throw new Exception\CircularReferenceException(sprintf( 'Circular alias reference: %s -> %s', implode(' -> ', $stack), $cName )); } $stack[$cName] = $cName; $cName = $this->aliases[$cName]; } return $cName; } /** * Retrieve a registered instance * * @param string $name * @param bool $usePeeringServiceManagers * @throws Exception\ServiceNotFoundException * @return object|array */ public function get($name, $usePeeringServiceManagers = true) { // inlined code from ServiceManager::canonicalizeName for performance if (isset($this->canonicalNames[$name])) { $cName = $this->canonicalNames[$name]; } else { $cName = $this->canonicalizeName($name); } $isAlias = false; if ($this->hasAlias($cName)) { $isAlias = true; $cName = $this->resolveAlias($cName); } $instance = null; if ($usePeeringServiceManagers && $this->retrieveFromPeeringManagerFirst) { $instance = $this->retrieveFromPeeringManager($name); if (null !== $instance) { return $instance; } } if (isset($this->instances[$cName])) { return $this->instances[$cName]; } if (!$instance) { if ( isset($this->invokableClasses[$cName]) || isset($this->factories[$cName]) || isset($this->aliases[$cName]) || $this->canCreateFromAbstractFactory($cName, $name) ) { $instance = $this->create(array($cName, $name)); } elseif ($isAlias && $this->canCreateFromAbstractFactory($name, $cName)) { /* * case of an alias leading to an abstract factory : * 'my-alias' => 'my-abstract-defined-service' * $name = 'my-alias' * $cName = 'my-abstract-defined-service' */ $instance = $this->create(array($name, $cName)); } elseif ($usePeeringServiceManagers && !$this->retrieveFromPeeringManagerFirst) { $instance = $this->retrieveFromPeeringManager($name); } } // Still no instance? raise an exception if ($instance === null) { if ($isAlias) { throw new Exception\ServiceNotFoundException(sprintf( 'An alias "%s" was requested but no service could be found.', $name )); } throw new Exception\ServiceNotFoundException(sprintf( '%s was unable to fetch or create an instance for %s', get_class($this) . '::' . __FUNCTION__, $name )); } if ( ($this->shareByDefault && !isset($this->shared[$cName])) || (isset($this->shared[$cName]) && $this->shared[$cName] === true) ) { $this->instances[$cName] = $instance; } return $instance; } /** * Create an instance of the requested service * * @param string|array $name * * @return bool|object */ public function create($name) { if (is_array($name)) { list($cName, $rName) = $name; } else { $rName = $name; // inlined code from ServiceManager::canonicalizeName for performance if (isset($this->canonicalNames[$rName])) { $cName = $this->canonicalNames[$name]; } else { $cName = $this->canonicalizeName($name); } } if (isset($this->delegators[$cName])) { return $this->createDelegatorFromFactory($cName, $rName); } return $this->doCreate($rName, $cName); } /** * Creates a callback that uses a delegator to create a service * * @param DelegatorFactoryInterface|callable $delegatorFactory the delegator factory * @param string $rName requested service name * @param string $cName canonical service name * @param callable $creationCallback callback for instantiating the real service * * @return callable */ private function createDelegatorCallback($delegatorFactory, $rName, $cName, $creationCallback) { $serviceManager = $this; return function () use ($serviceManager, $delegatorFactory, $rName, $cName, $creationCallback) { return $delegatorFactory instanceof DelegatorFactoryInterface ? $delegatorFactory->createDelegatorWithName($serviceManager, $cName, $rName, $creationCallback) : $delegatorFactory($serviceManager, $cName, $rName, $creationCallback); }; } /** * Actually creates the service * * @param string $rName real service name * @param string $cName canonicalized service name * * @return bool|mixed|null|object * @throws Exception\ServiceNotFoundException * * @internal this method is internal because of PHP 5.3 compatibility - do not explicitly use it */ public function doCreate($rName, $cName) { $instance = null; if (isset($this->factories[$cName])) { $instance = $this->createFromFactory($cName, $rName); } if ($instance === null && isset($this->invokableClasses[$cName])) { $instance = $this->createFromInvokable($cName, $rName); } if ($instance === null && $this->canCreateFromAbstractFactory($cName, $rName)) { $instance = $this->createFromAbstractFactory($cName, $rName); } if ($instance === null && $this->throwExceptionInCreate) { throw new Exception\ServiceNotFoundException(sprintf( 'No valid instance was found for %s%s', $cName, ($rName ? '(alias: ' . $rName . ')' : '') )); } // Do not call initializers if we do not have an instance if ($instance === null) { return $instance; } foreach ($this->initializers as $initializer) { if ($initializer instanceof InitializerInterface) { $initializer->initialize($instance, $this); } else { call_user_func($initializer, $instance, $this); } } return $instance; } /** * Determine if we can create an instance. * * @param string|array $name * @param bool $checkAbstractFactories * @return bool * * @deprecated this method is being deprecated as of zendframework 2.2, and may be removed in future major versions */ public function canCreate($name, $checkAbstractFactories = true) { if (is_array($name)) { list($cName, $rName) = $name; } else { $rName = $name; $cName = $this->canonicalizeName($rName); } return ( isset($this->invokableClasses[$cName]) || isset($this->factories[$cName]) || isset($this->aliases[$cName]) || isset($this->instances[$cName]) || ($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $rName)) ); } /** * @param string|array $name * @param bool $checkAbstractFactories * @param bool $usePeeringServiceManagers * @return bool */ public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true) { if (is_array($name)) { list($cName, $rName) = $name; } else { $rName = $name; // inlined code from ServiceManager::canonicalizeName for performance if (isset($this->canonicalNames[$rName])) { $cName = $this->canonicalNames[$name]; } else { $cName = $this->canonicalizeName($name); } } if ( isset($this->invokableClasses[$cName]) || isset($this->factories[$cName]) || isset($this->aliases[$cName]) || isset($this->instances[$cName]) || ($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $name)) ) { return true; } if ($usePeeringServiceManagers) { foreach ($this->peeringServiceManagers as $peeringServiceManager) { if ($peeringServiceManager->has($rName)) { return true; } } } return false; } /** * Determine if we can create an instance from an abstract factory. * * @param string $cName * @param string $rName * @return bool */ public function canCreateFromAbstractFactory($cName, $rName) { // check abstract factories foreach ($this->abstractFactories as $abstractFactory) { $factoryClass = get_class($abstractFactory); if ( isset($this->pendingAbstractFactoryRequests[$factoryClass]) && $this->pendingAbstractFactoryRequests[$factoryClass] == $rName ) { return false; } $objectHash = spl_object_hash($abstractFactory); if ($this->lastAbstractFactoryUsed === $objectHash && $this->lastCanonicalNameUsed === $cName) { $this->lastAbstractFactoryUsed = $this->lastCanonicalNameUsed = null; return false; } $this->lastAbstractFactoryUsed = $objectHash; $this->lastCanonicalNameUsed = $cName; if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) { $this->lastAbstractFactoryUsed = $this->lastCanonicalNameUsed = null; return true; } } return false; } /** * Ensure the alias definition will not result in a circular reference * * @param string $alias * @param string $nameOrAlias * @throws Exception\CircularReferenceException * @return self */ protected function checkForCircularAliasReference($alias, $nameOrAlias) { $aliases = $this->aliases; $aliases[$alias] = $nameOrAlias; $stack = array(); while (isset($aliases[$alias])) { if (isset($stack[$alias])) { throw new Exception\CircularReferenceException(sprintf( 'The alias definition "%s" : "%s" results in a circular reference: "%s" -> "%s"', $alias, $nameOrAlias, implode('" -> "', $stack), $alias )); } $stack[$alias] = $alias; $alias = $aliases[$alias]; } return $this; } /** * @param string $alias * @param string $nameOrAlias * @return ServiceManager * @throws Exception\ServiceNotFoundException * @throws Exception\InvalidServiceNameException */ public function setAlias($alias, $nameOrAlias) { if (!is_string($alias) || !is_string($nameOrAlias)) { throw new Exception\InvalidServiceNameException('Service or alias names must be strings.'); } $cAlias = $this->canonicalizeName($alias); $nameOrAlias = $this->canonicalizeName($nameOrAlias); if ($alias == '' || $nameOrAlias == '') { throw new Exception\InvalidServiceNameException('Invalid service name alias'); } if ($this->allowOverride === false && $this->has(array($cAlias, $alias), false)) { throw new Exception\InvalidServiceNameException(sprintf( 'An alias by the name "%s" or "%s" already exists', $cAlias, $alias )); } if ($this->hasAlias($alias)) { $this->checkForCircularAliasReference($cAlias, $nameOrAlias); } $this->aliases[$cAlias] = $nameOrAlias; return $this; } /** * Determine if we have an alias * * @param string $alias * @return bool */ public function hasAlias($alias) { return isset($this->aliases[$this->canonicalizeName($alias)]); } /** * Create scoped service manager * * @param string $peering * @return ServiceManager */ public function createScopedServiceManager($peering = self::SCOPE_PARENT) { $scopedServiceManager = new ServiceManager(); if ($peering == self::SCOPE_PARENT) { $scopedServiceManager->peeringServiceManagers[] = $this; } if ($peering == self::SCOPE_CHILD) { $this->peeringServiceManagers[] = $scopedServiceManager; } return $scopedServiceManager; } /** * Add a peering relationship * * @param ServiceManager $manager * @param string $peering * @return ServiceManager */ public function addPeeringServiceManager(ServiceManager $manager, $peering = self::SCOPE_PARENT) { if ($peering == self::SCOPE_PARENT) { $this->peeringServiceManagers[] = $manager; } if ($peering == self::SCOPE_CHILD) { $manager->peeringServiceManagers[] = $this; } return $this; } /** * Canonicalize name * * @param string $name * @return string */ protected function canonicalizeName($name) { if (isset($this->canonicalNames[$name])) { return $this->canonicalNames[$name]; } // this is just for performance instead of using str_replace return $this->canonicalNames[$name] = strtolower(strtr($name, $this->canonicalNamesReplacements)); } /** * Create service via callback * * @param callable $callable * @param string $cName * @param string $rName * @throws Exception\ServiceNotCreatedException * @throws Exception\ServiceNotFoundException * @throws Exception\CircularDependencyFoundException * @return object */ protected function createServiceViaCallback($callable, $cName, $rName) { static $circularDependencyResolver = array(); $depKey = spl_object_hash($this) . '-' . $cName; if (isset($circularDependencyResolver[$depKey])) { $circularDependencyResolver = array(); throw new Exception\CircularDependencyFoundException('Circular dependency for LazyServiceLoader was found for instance ' . $rName); } try { $circularDependencyResolver[$depKey] = true; $instance = call_user_func($callable, $this, $cName, $rName); unset($circularDependencyResolver[$depKey]); } catch (Exception\ServiceNotFoundException $e) { unset($circularDependencyResolver[$depKey]); throw $e; } catch (\Exception $e) { unset($circularDependencyResolver[$depKey]); throw new Exception\ServiceNotCreatedException( sprintf('An exception was raised while creating "%s"; no instance returned', $rName), $e->getCode(), $e ); } if ($instance === null) { throw new Exception\ServiceNotCreatedException('The factory was called but did not return an instance.'); } return $instance; } /** * Retrieve a keyed list of all registered services. Handy for debugging! * * @return array */ public function getRegisteredServices() { return array( 'invokableClasses' => array_keys($this->invokableClasses), 'factories' => array_keys($this->factories), 'aliases' => array_keys($this->aliases), 'instances' => array_keys($this->instances), ); } /** * Retrieve a keyed list of all canonical names. Handy for debugging! * * @return array */ public function getCanonicalNames() { return $this->canonicalNames; } /** * Allows to override the canonical names lookup map with predefined * values. * * @param array $canonicalNames * @return ServiceManager */ public function setCanonicalNames($canonicalNames) { $this->canonicalNames = $canonicalNames; return $this; } /** * Attempt to retrieve an instance via a peering manager * * @param string $name * @return mixed */ protected function retrieveFromPeeringManager($name) { foreach ($this->peeringServiceManagers as $peeringServiceManager) { if ($peeringServiceManager->has($name)) { return $peeringServiceManager->get($name); } } $name = $this->canonicalizeName($name); if ($this->hasAlias($name)) { do { $name = $this->aliases[$name]; } while ($this->hasAlias($name)); } foreach ($this->peeringServiceManagers as $peeringServiceManager) { if ($peeringServiceManager->has($name)) { return $peeringServiceManager->get($name); } } return null; } /** * Attempt to create an instance via an invokable class * * @param string $canonicalName * @param string $requestedName * @return null|\stdClass * @throws Exception\ServiceNotFoundException If resolved class does not exist */ protected function createFromInvokable($canonicalName, $requestedName) { $invokable = $this->invokableClasses[$canonicalName]; if (!class_exists($invokable)) { throw new Exception\ServiceNotFoundException(sprintf( '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist', get_class($this) . '::' . __FUNCTION__, $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : ''), $invokable )); } $instance = new $invokable; return $instance; } /** * Attempt to create an instance via a factory * * @param string $canonicalName * @param string $requestedName * @return mixed * @throws Exception\ServiceNotCreatedException If factory is not callable */ 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) { $instance = $this->createServiceViaCallback(array($factory, 'createService'), $canonicalName, $requestedName); } elseif (is_callable($factory)) { $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName); } else { throw new Exception\ServiceNotCreatedException(sprintf( 'While attempting to create %s%s an invalid factory was registered for this instance type.', $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : '') )); } return $instance; } /** * Attempt to create an instance via an abstract factory * * @param string $canonicalName * @param string $requestedName * @return object|null * @throws Exception\ServiceNotCreatedException If abstract factory is not callable */ protected function createFromAbstractFactory($canonicalName, $requestedName) { foreach ($this->abstractFactories as $index => $abstractFactory) { // support factories as strings if (is_string($abstractFactory) && class_exists($abstractFactory, true)) { $this->abstractFactories[$index] = $abstractFactory = new $abstractFactory; } elseif (!$abstractFactory instanceof AbstractFactoryInterface) { throw new Exception\ServiceNotCreatedException(sprintf( 'While attempting to create %s%s an abstract factory could not produce a valid instance.', $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : '') )); } try { if ($abstractFactory->canCreateServiceWithName($this, $canonicalName, $requestedName)) { $this->pendingAbstractFactoryRequests[get_class($abstractFactory)] = $requestedName; $instance = $this->createServiceViaCallback( array($abstractFactory, 'createServiceWithName'), $canonicalName, $requestedName ); unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]); } else { $instance = null; } } catch (\Exception $e) { unset($this->pendingAbstractFactoryRequests[get_class($abstractFactory)]); throw new Exception\ServiceNotCreatedException( sprintf( 'An abstract factory could not create an instance of %s%s.', $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : '') ), $e->getCode(), $e ); } if ($instance !== null) { return $instance; } } } /** * @param $canonicalName * @param $requestedName * @return mixed * @throws Exception\ServiceNotCreatedException */ protected function createDelegatorFromFactory($canonicalName, $requestedName) { $serviceManager = $this; $delegatorsCount = count($this->delegators[$canonicalName]); $creationCallback = function () use ($serviceManager, $requestedName, $canonicalName) { return $serviceManager->doCreate($requestedName, $canonicalName); }; for ($i = 0; $i < $delegatorsCount; $i += 1) { $delegatorFactory = $this->delegators[$canonicalName][$i]; if (is_string($delegatorFactory)) { $delegatorFactory = !$this->has($delegatorFactory) && class_exists($delegatorFactory, true) ? new $delegatorFactory : $this->get($delegatorFactory); $this->delegators[$canonicalName][$i] = $delegatorFactory; } if (!$delegatorFactory instanceof DelegatorFactoryInterface && !is_callable($delegatorFactory)) { throw new Exception\ServiceNotCreatedException(sprintf( 'While attempting to create %s%s an invalid factory was registered for this instance type.', $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : '') )); } $creationCallback = $this->createDelegatorCallback( $delegatorFactory, $requestedName, $canonicalName, $creationCallback ); } return $creationCallback($serviceManager, $canonicalName, $requestedName, $creationCallback); } /** * Checks if the object has this class as one of its parents * * @see https://bugs.php.net/bug.php?id=53727 * @see https://github.com/zendframework/zf2/pull/1807 * * @param string $className * @param string $type * @return bool * * @deprecated this method is being deprecated as of zendframework 2.2, and may be removed in future major versions */ protected static function isSubclassOf($className, $type) { if (is_subclass_of($className, $type)) { return true; } if (version_compare(PHP_VERSION, '5.3.7', '>=')) { return false; } if (!interface_exists($type)) { return false; } $r = new ReflectionClass($className); return $r->implementsInterface($type); } /** * Unregister a service * * Called when $allowOverride is true and we detect that a service being * added to the instance already exists. This will remove the duplicate * entry, and also any shared flags previously registered. * * @param string $canonical * @return void */ protected function unregisterService($canonical) { $types = array('invokableClasses', 'factories', 'aliases'); foreach ($types as $type) { if (isset($this->{$type}[$canonical])) { unset($this->{$type}[$canonical]); break; } } if (isset($this->instances[$canonical])) { unset($this->instances[$canonical]); } if (isset($this->shared[$canonical])) { unset($this->shared[$canonical]); } } }