{"action":"created","comment":{"url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/comments/39658910","id":39658910,"diff_hunk":"@@ -48,1224 +51,427 @@ class ServiceManager implements ServiceLocatorInterface, ContainerInterface\n     protected $abstractFactories = [];\n \n     /**\n-     * @var array[]\n+     * @var string[]|DelegatorFactoryInterface[]\n      */\n     protected $delegators = [];\n \n     /**\n      * @var array\n      */\n-    protected $pendingAbstractFactoryRequests = [];\n+    protected $lazyServices = [];\n \n     /**\n-     * @var integer\n+     * @var Proxy\\LazyServiceFactory\n      */\n-    protected $nestedContextCounter = -1;\n+    protected $lazyServicesDelegator;\n \n     /**\n-     * @var array\n+     * @var InitializerInterface[]\n      */\n-    protected $nestedContext = [];\n-\n-    /**\n-     * @var array\n-     */\n-    protected $shared = [];\n+    protected $initializers = [];\n \n     /**\n-     * Registered services and cached values\n+     * A list of aliases\n+     *\n+     * Should map one alias to a service name, or another alias (aliases are recursively resolved)\n      *\n-     * @var array\n-     */\n-    protected $instances = [];\n-\n-    /**\n      * @var array\n      */\n     protected $aliases = [];\n \n     /**\n+     * A list of already loaded services (this act as a local cache)\n+     *\n      * @var array\n      */\n-    protected $initializers = [];\n+    protected $services = [];\n \n     /**\n-     * @var ServiceManager[]\n-     */\n-    protected $peeringServiceManagers = [];\n-\n-    /**\n-     * Whether or not to share by default\n+     * Should the services be shared by default?\n      *\n      * @var bool\n      */\n-    protected $shareByDefault = true;\n-\n-    /**\n-     * @var bool\n-     */\n-    protected $retrieveFromPeeringManagerFirst = false;\n+    protected $sharedByDefault = true;\n \n     /**\n-     * @var bool Track whether not to throw exceptions during create()\n-     */\n-    protected $throwExceptionInCreate = true;\n-\n-    /**\n-     * @var array map of characters to be replaced through strtr\n-     */\n-    protected $canonicalNamesReplacements = ['-' => '', '_' => '', ' ' => '', '\\\\' => '', '/' => ''];\n-\n-    /**\n-     * @var ServiceLocatorInterface\n-     */\n-    protected $serviceManagerCaller;\n-\n-    /**\n-     * Constructor\n+     * Allow to activate/deactivate shared per service name\n      *\n-     * @param ConfigInterface $config\n-     */\n-    public function __construct(ConfigInterface $config = null)\n-    {\n-        if ($config) {\n-            $config->configureServiceManager($this);\n-        }\n-    }\n-\n-    /**\n-     * Set allow override\n+     * Example configuration:\n      *\n-     * @param $allowOverride\n-     * @return ServiceManager\n-     */\n-    public function setAllowOverride($allowOverride)\n-    {\n-        $this->allowOverride = (bool) $allowOverride;\n-        return $this;\n-    }\n-\n-    /**\n-     * Get allow override\n-     *\n-     * @return bool\n-     */\n-    public function getAllowOverride()\n-    {\n-        return $this->allowOverride;\n-    }\n-\n-    /**\n-     * Set flag indicating whether services are shared by default\n+     * 'shared' => [\n+     *     MyService::class => true, // will be shared, even if \"sharedByDefault\" is false\n+     *     MyOtherService::class => false // won't be shared, even if \"sharedByDefault\" is true\n+     * ]\n      *\n-     * @param  bool $shareByDefault\n-     * @return ServiceManager\n-     * @throws Exception\\RuntimeException if allowOverride is false\n+     * @var array\n      */\n-    public function setShareByDefault($shareByDefault)\n-    {\n-        if ($this->allowOverride === false) {\n-            throw new Exception\\RuntimeException(sprintf(\n-                '%s: cannot alter default shared service setting; container is marked immutable (allow_override is false)',\n-                get_class($this) . '::' . __FUNCTION__\n-            ));\n-        }\n-        $this->shareByDefault = (bool) $shareByDefault;\n-        return $this;\n-    }\n+    protected $shared = [];\n \n     /**\n-     * Are services shared by default?\n-     *\n-     * @return bool\n+     * @var ContainerInterface\n      */\n-    public function shareByDefault()\n-    {\n-        return $this->shareByDefault;\n-    }\n+    protected $creationContext;\n \n     /**\n-     * Set throw exceptions in create\n+     * Constructor.\n      *\n-     * @param  bool $throwExceptionInCreate\n-     * @return ServiceManager\n-     */\n-    public function setThrowExceptionInCreate($throwExceptionInCreate)\n-    {\n-        $this->throwExceptionInCreate = $throwExceptionInCreate;\n-        return $this;\n-    }\n-\n-    /**\n-     * Get throw exceptions in create\n+     * See {@see \\Zend\\ServiceManager\\ServiceManager::configure()} for details\n+     * on what $config accepts.\n      *\n-     * @return bool\n+     * @param array $config\n      */\n-    public function getThrowExceptionInCreate()\n+    public function __construct(array $config = [])\n     {\n-        return $this->throwExceptionInCreate;\n+        $this->creationContext = $this;\n+        $this->configure($config);\n     }\n \n     /**\n-     * Set flag indicating whether to pull from peering manager before attempting creation\n+     * Create a new service locator that merges the provided configuration.\n      *\n-     * @param  bool $retrieveFromPeeringManagerFirst\n-     * @return ServiceManager\n-     */\n-    public function setRetrieveFromPeeringManagerFirst($retrieveFromPeeringManagerFirst = true)\n-    {\n-        $this->retrieveFromPeeringManagerFirst = (bool) $retrieveFromPeeringManagerFirst;\n-        return $this;\n-    }\n-\n-    /**\n-     * Should we retrieve from the peering manager prior to attempting to create a service?\n+     * Note that the original service locator is left untouched (as with PSR-7\n+     * interfaces).\n      *\n-     * @return bool\n-     */\n-    public function retrieveFromPeeringManagerFirst()\n-    {\n-        return $this->retrieveFromPeeringManagerFirst;\n-    }\n-\n-    /**\n-     * Set invokable class\n+     * See {@see \\Zend\\ServiceManager\\ServiceManager::configure()} for details\n+     * on what $config accepts.\n      *\n-     * @param  string  $name\n-     * @param  string  $invokableClass\n-     * @param  bool $shared\n-     * @return ServiceManager\n-     * @throws Exception\\InvalidServiceNameException\n+     * @param  array $config\n+     * @return ContainerInterface\n      */\n-    public function setInvokableClass($name, $invokableClass, $shared = null)\n+    public function withConfig(array $config)\n     {\n-        $cName = $this->canonicalizeName($name);\n-\n-        if ($this->has([$cName, $name], false)) {\n-            if ($this->allowOverride === false) {\n-                throw new Exception\\InvalidServiceNameException(sprintf(\n-                    'A service by the name or alias \"%s\" already exists and cannot be overridden; please use an alternate name',\n-                    $name\n-                ));\n-            }\n-            $this->unregisterService($cName);\n-        }\n-\n-        if ($shared === null) {\n-            $shared = $this->shareByDefault;\n-        }\n-\n-        $this->invokableClasses[$cName] = $invokableClass;\n-        $this->shared[$cName]           = (bool) $shared;\n-\n-        return $this;\n+        $container                  = clone $this;\n+        $container->creationContext = $container;\n+        $container->configure($config);\n+        return $container;\n     }\n \n     /**\n-     * Set factory\n-     *\n-     * @param  string                           $name\n-     * @param  string|FactoryInterface|callable $factory\n-     * @param  bool                             $shared\n-     * @return ServiceManager\n-     * @throws Exception\\InvalidArgumentException\n-     * @throws Exception\\InvalidServiceNameException\n+     * {@inheritDoc}\n      */\n-    public function setFactory($name, $factory, $shared = null)\n+    public function get($name)\n     {\n-        $cName = $this->canonicalizeName($name);\n+        $name = $this->resolveAlias($name);\n \n-        if (!($factory instanceof FactoryInterface || is_string($factory) || is_callable($factory))) {\n-            throw new Exception\\InvalidArgumentException(\n-                'Provided abstract factory must be the class name of an abstract factory or an instance of an AbstractFactoryInterface.'\n-            );\n+        // We start by checking if the service is cached (this is the fastest method).\n+        if (isset($this->services[$name])) {\n+            return $this->services[$name];\n         }\n \n-        if ($this->has([$cName, $name], false)) {\n-            if ($this->allowOverride === false) {\n-                throw new Exception\\InvalidServiceNameException(sprintf(\n-                    'A service by the name or alias \"%s\" already exists and cannot be overridden, please use an alternate name',\n-                    $name\n-                ));\n-            }\n-            $this->unregisterService($cName);\n-        }\n-\n-        if ($shared === null) {\n-            $shared = $this->shareByDefault;\n-        }\n-\n-        $this->factories[$cName] = $factory;\n-        $this->shared[$cName]    = (bool) $shared;\n-\n-        return $this;\n-    }\n-\n-    /**\n-     * Add abstract factory\n-     *\n-     * @param  AbstractFactoryInterface|string $factory\n-     * @param  bool                            $topOfStack\n-     * @return ServiceManager\n-     * @throws Exception\\InvalidArgumentException if the abstract factory is invalid\n-     */\n-    public function addAbstractFactory($factory, $topOfStack = true)\n-    {\n-        if (!$factory instanceof AbstractFactoryInterface && is_string($factory)) {\n-            $factory = new $factory();\n-        }\n+        $object = $this->doCreate($name);\n \n-        if (!$factory instanceof AbstractFactoryInterface) {\n-            throw new Exception\\InvalidArgumentException(\n-                'Provided abstract factory must be the class name of an abstract'\n-                . ' factory or an instance of an AbstractFactoryInterface.'\n-            );\n+        if (($this->sharedByDefault && !isset($this->shared[$name]))\n+            || (isset($this->shared[$name]) && $this->shared[$name])) {\n+            $this->services[$name] = $object;\n         }\n \n-        if ($topOfStack) {\n-            array_unshift($this->abstractFactories, $factory);\n-        } else {\n-            array_push($this->abstractFactories, $factory);\n-        }\n-        return $this;\n+        return $object;\n     }\n \n     /**\n-     * Sets the given service name as to be handled by a delegator factory\n-     *\n-     * @param  string $serviceName          name of the service being the delegate\n-     * @param  string $delegatorFactoryName name of the service being the delegator factory\n-     *\n-     * @return ServiceManager\n+     * {@inheritDoc}\n      */\n-    public function addDelegator($serviceName, $delegatorFactoryName)\n+    public function build($name, array $options = null)\n     {\n-        $cName = $this->canonicalizeName($serviceName);\n-\n-        if (!isset($this->delegators[$cName])) {\n-            $this->delegators[$cName] = [];\n-        }\n-\n-        $this->delegators[$cName][] = $delegatorFactoryName;\n-\n-        return $this;\n+        // We never cache when using \"build\"\n+        return $this->doCreate($this->resolveAlias($name), $options);\n     }\n \n     /**\n-     * Add initializer\n-     *\n-     * @param  callable|InitializerInterface $initializer\n-     * @param  bool                          $topOfStack\n-     * @return ServiceManager\n-     * @throws Exception\\InvalidArgumentException\n+     * {@inheritDoc}\n      */\n-    public function addInitializer($initializer, $topOfStack = true)\n+    public function has($name, $checkAbstractFactories = false)\n     {\n-        if (!($initializer instanceof InitializerInterface || is_callable($initializer))) {\n-            if (is_string($initializer)) {\n-                $initializer = new $initializer;\n-            }\n+        $name  = $this->resolveAlias($name);\n+        $found = isset($this->services[$name]) || isset($this->factories[$name]);\n \n-            if (!($initializer instanceof InitializerInterface || is_callable($initializer))) {\n-                throw new Exception\\InvalidArgumentException('$initializer should be callable.');\n-            }\n+        if ($found || !$checkAbstractFactories) {\n+            return $found;\n         }\n \n-        if ($topOfStack) {\n-            array_unshift($this->initializers, $initializer);\n-        } else {\n-            array_push($this->initializers, $initializer);\n-        }\n-        return $this;\n-    }\n-\n-    /**\n-     * Register a service with the locator\n-     *\n-     * @param  string  $name\n-     * @param  mixed   $service\n-     * @return ServiceManager\n-     * @throws Exception\\InvalidServiceNameException\n-     */\n-    public function setService($name, $service)\n-    {\n-        $cName = $this->canonicalizeName($name);\n-\n-        if ($this->has($cName, false)) {\n-            if ($this->allowOverride === false) {\n-                throw new Exception\\InvalidServiceNameException(sprintf(\n-                    '%s: A service by the name \"%s\" or alias already exists and cannot be overridden, please use an alternate name.',\n-                    get_class($this) . '::' . __FUNCTION__,\n-                    $name\n-                ));\n+        // Check abstract factories\n+        foreach ($this->abstractFactories as $abstractFactory) {\n+            if ($abstractFactory->canCreateServiceWithName($this, $name)) {\n+                return true;\n             }\n-            $this->unregisterService($cName);\n         }\n \n-        $this->instances[$cName] = $service;\n-\n-        return $this;\n-    }\n-\n-    /**\n-     * @param  string $name\n-     * @param  bool   $isShared\n-     * @return ServiceManager\n-     * @throws Exception\\ServiceNotFoundException\n-     */\n-    public function setShared($name, $isShared)\n-    {\n-        $cName = $this->canonicalizeName($name);\n-\n-        if (\n-            !isset($this->invokableClasses[$cName])\n-            && !isset($this->factories[$cName])\n-            && !$this->canCreateFromAbstractFactory($cName, $name)\n-        ) {\n-            throw new Exception\\ServiceNotFoundException(sprintf(\n-                '%s: A service by the name \"%s\" was not found and could not be marked as shared',\n-                get_class($this) . '::' . __FUNCTION__,\n-                $name\n-            ));\n-        }\n-\n-        $this->shared[$cName] = (bool) $isShared;\n-        return $this;\n+        return false;\n     }\n \n     /**\n-     * @param  string $name\n-     * @return bool\n-     * @throws Exception\\ServiceNotFoundException\n+     * Configure the service manager\n+     *\n+     * Valid top keys are:\n+     *\n+     * - services: service name => service instance pairs\n+     * - factories: service name => factory pairs; factories may be any\n+     *   callable, string name resolving to an invokable class, or string name\n+     *   resolving to a FactoryInterface instance.\n+     * - abstract_factories: an array of abstract factories; these may be\n+     *   instances of AbstractFactoryInterface, or string names resolving to\n+     *   classes that implement that interface.\n+     * - delegators: service name => list of delegator factories for the given\n+     *   service; each item in the list may be a callable, a string name\n+     *   resolving to an invokable class, or a string name resolving to a class\n+     *   implementing DelegatorFactoryInterface.\n+     * - shared: service name => flag pairs; the flag is a boolean indicating\n+     *   whether or not the service is shared.\n+     * - aliases: alias => service name pairs.\n+     * - lazy_services: lazy service configuration; can contain the keys:\n+     *   - class_map: service name => class name pairs.\n+     *   - proxies_namespace: string namespace to use for generated proxy\n+     *     classes.\n+     *   - proxies_target_dir: directory in which to write generated proxy\n+     *     classes; uses system temporary by default.\n+     *   - write_proxy_files: boolean indicating whether generated proxy\n+     *     classes should be written; defaults to boolean false.\n+     * - shared_by_default: boolean, indicating if services in this instance\n+     *   should be shared by default.\n+     *\n+     * @param  array $config\n+     * @return void\n      */\n-    public function isShared($name)\n-    {\n-        $cName = $this->canonicalizeName($name);\n-\n-        if (!$this->has($name)) {\n-            throw new Exception\\ServiceNotFoundException(sprintf(\n-                '%s: A service by the name \"%s\" was not found',\n-                get_class($this) . '::' . __FUNCTION__,\n-                $name\n-            ));\n-        }\n-\n-        if (!isset($this->shared[$cName])) {\n-            return $this->shareByDefault();\n-        }\n-\n-        return $this->shared[$cName];\n-    }\n+    protected function configure(array $config)\n+    {\n+        $this->services        = (isset($config['services']) ? $config['services'] : []) + $this->services;\n+        $this->factories       = (isset($config['factories']) ? $config['factories'] : []) + $this->factories;\n+        $this->delegators      = array_merge_recursive($this->delegators, isset($config['delegators'])\n+            ? $config['delegators']\n+            : []);\n+        $this->shared          = (isset($config['shared']) ? $config['shared'] : []) + $this->shared;\n+        $this->aliases         = (isset($config['aliases']) ? $config['aliases'] : []) + $this->aliases;\n+        $this->lazyServices    = array_merge_recursive($this->lazyServices, isset($config['lazy_services'])\n+            ? $config['lazy_services']\n+            : []);\n+        $this->sharedByDefault = isset($config['shared_by_default'])\n+            ? $config['shared_by_default']\n+            : $this->sharedByDefault;\n+\n+        // If lazy service configuration was provided, reset the lazy services\n+        // delegator factory.\n+        if (isset($config['lazy_services']) && ! empty($config['lazy_services'])) {\n+            $this->lazyServicesDelegator = null;\n+        }\n+\n+        // For abstract factories and initializers, we always directly\n+        // instantiate them to avoid checks during service construction.\n+        if (isset($config['abstract_factories'])) {\n+            foreach ($config['abstract_factories'] as $abstractFactory) {\n+                if (is_string($abstractFactory)) {\n+                    $abstractFactory = new $abstractFactory();\n+                }\n \n-    /**\n-     * Resolve the alias for the given canonical name\n-     *\n-     * @param  string $cName The canonical name to resolve\n-     * @return string The resolved canonical name\n-     */\n-    protected function resolveAlias($cName)\n-    {\n-        $stack = [];\n+                if (is_callable($abstractFactory)) {\n+                    $this->abstractFactories[] = $abstractFactory;\n+                    continue;\n+                }\n \n-        while ($this->hasAlias($cName)) {\n-            if (isset($stack[$cName])) {\n-                throw new Exception\\CircularReferenceException(sprintf(\n-                    'Circular alias reference: %s -> %s',\n-                    implode(' -> ', $stack),\n-                    $cName\n+                throw new InvalidArgumentException(sprintf(\n+                    'An invalid abstract factory was registered. A callable or an instance of \"%s\" was expected, '\n+                    . 'but \"%s\" was received',\n+                    AbstractFactoryInterface::class,\n+                    is_object($abstractFactory) ? get_class($abstractFactory) : gettype($abstractFactory)\n                 ));\n             }\n-\n-            $stack[$cName] = $cName;\n-            $cName = $this->aliases[$cName];\n-        }\n-\n-        return $cName;\n-    }\n-\n-    /**\n-     * Retrieve a registered instance\n-     *\n-     * @param  string  $name\n-     * @param  bool    $usePeeringServiceManagers\n-     * @throws Exception\\ServiceNotFoundException\n-     * @return object|array\n-     */\n-    public function get($name, $usePeeringServiceManagers = true)\n-    {\n-        // inlined code from ServiceManager::canonicalizeName for performance\n-        if (isset($this->canonicalNames[$name])) {\n-            $cName = $this->canonicalNames[$name];\n-        } else {\n-            $cName = $this->canonicalizeName($name);\n-        }\n-\n-        $isAlias = false;\n-\n-        if ($this->hasAlias($cName)) {\n-            $isAlias = true;\n-            $cName = $this->resolveAlias($cName);\n-        }\n-\n-        $instance = null;\n-\n-        if ($usePeeringServiceManagers && $this->retrieveFromPeeringManagerFirst) {\n-            $instance = $this->retrieveFromPeeringManager($name);\n-\n-            if (null !== $instance) {\n-                return $instance;\n-            }\n         }\n \n-        if (isset($this->instances[$cName])) {\n-            return $this->instances[$cName];\n-        }\n+        if (isset($config['initializers'])) {\n+            foreach ($config['initializers'] as $initializer) {\n+                if (is_string($initializer)) {\n+                    $initializer = new $initializer();\n+                }\n \n-        if (!$instance) {\n-            $this->checkNestedContextStart($cName);\n-            if (\n-                isset($this->invokableClasses[$cName])\n-                || isset($this->factories[$cName])\n-                || isset($this->aliases[$cName])\n-                || $this->canCreateFromAbstractFactory($cName, $name)\n-            ) {\n-                $instance = $this->create([$cName, $name]);\n-            } elseif ($isAlias && $this->canCreateFromAbstractFactory($name, $cName)) {\n-                /*\n-                 * case of an alias leading to an abstract factory :\n-                 * 'my-alias' => 'my-abstract-defined-service'\n-                 *     $name = 'my-alias'\n-                 *     $cName = 'my-abstract-defined-service'\n-                 */\n-                $instance = $this->create([$name, $cName]);\n-            } elseif ($usePeeringServiceManagers && !$this->retrieveFromPeeringManagerFirst) {\n-                $instance = $this->retrieveFromPeeringManager($name);\n-            }\n-            $this->checkNestedContextStop();\n-        }\n+                if (is_callable($initializer)) {\n+                    $this->initializers[] = $initializer;\n+                    continue;\n+                }\n \n-        // Still no instance? raise an exception\n-        if ($instance === null) {\n-            $this->checkNestedContextStop(true);\n-            if ($isAlias) {\n-                throw new Exception\\ServiceNotFoundException(sprintf(\n-                    'An alias \"%s\" was requested but no service could be found.',\n-                    $name\n+                throw new InvalidArgumentException(sprintf(\n+                    'An invalid initializer was registered. A callable or an instance of \"%s\" was expected, but\n+                    \"%s\" was received',\n+                    InitializerInterface::class,\n+                    is_object($initializer) ? get_class($initializer) : gettype($initializer)\n                 ));\n             }\n-\n-            throw new Exception\\ServiceNotFoundException(sprintf(\n-                '%s was unable to fetch or create an instance for %s',\n-                get_class($this) . '::' . __FUNCTION__,\n-                $name\n-            ));\n-        }\n-\n-        if (\n-            ($this->shareByDefault && !isset($this->shared[$cName]))\n-            || (isset($this->shared[$cName]) && $this->shared[$cName] === true)\n-        ) {\n-            $this->instances[$cName] = $instance;\n         }\n-\n-        return $instance;\n     }\n \n     /**\n-     * Create an instance of the requested service\n+     * Recursively resolve an alias name to a service name\n      *\n-     * @param  string|array $name\n-     *\n-     * @return bool|object\n+     * @param  string $alias\n+     * @return string\n      */\n-    public function create($name)\n+    private function resolveAlias($alias)\n     {\n-        if (is_array($name)) {\n-            list($cName, $rName) = $name;\n-        } else {\n-            $rName = $name;\n+        $name = $alias;\n \n-            // inlined code from ServiceManager::canonicalizeName for performance\n-            if (isset($this->canonicalNames[$rName])) {\n-                $cName = $this->canonicalNames[$name];\n-            } else {\n-                $cName = $this->canonicalizeName($name);\n-            }\n-        }\n-\n-        if (isset($this->delegators[$cName])) {\n-            return $this->createDelegatorFromFactory($cName, $rName);\n-        }\n+        do {\n+            $canBeResolved = isset($this->aliases[$name]);\n+            $name          = $canBeResolved ? $this->aliases[$name] : $name;\n+        } while ($canBeResolved);\n \n-        return $this->doCreate($rName, $cName);\n+        return $name;\n     }\n \n     /**\n-     * Creates a callback that uses a delegator to create a service\n-     *\n-     * @param DelegatorFactoryInterface|callable $delegatorFactory the delegator factory\n-     * @param string                             $rName            requested service name\n-     * @param string                             $cName            canonical service name\n-     * @param callable                           $creationCallback callback for instantiating the real service\n+     * Get a factory for the given service name\n      *\n+     * @param  string $name\n      * @return callable\n+     * @throws ServiceNotFoundException\n      */\n-    private function createDelegatorCallback($delegatorFactory, $rName, $cName, $creationCallback)\n-    {\n-        return function () use ($delegatorFactory, $rName, $cName, $creationCallback) {\n-            return $delegatorFactory instanceof DelegatorFactoryInterface\n-                ? $delegatorFactory->createDelegatorWithName($this, $cName, $rName, $creationCallback)\n-                : $delegatorFactory($this, $cName, $rName, $creationCallback);\n-        };\n-    }\n-\n-    /**\n-     * Actually creates the service\n-     *\n-     * @param string $rName real service name\n-     * @param string $cName canonicalized service name\n-     *\n-     * @return bool|mixed|null|object\n-     * @throws Exception\\ServiceNotFoundException\n-     *\n-     */\n-    protected function doCreate($rName, $cName)\n+    private function getFactory($name)\n     {\n-        $instance = null;\n-\n-        if (isset($this->factories[$cName])) {\n-            $instance = $this->createFromFactory($cName, $rName);\n-        }\n-\n-        if ($instance === null && isset($this->invokableClasses[$cName])) {\n-            $instance = $this->createFromInvokable($cName, $rName);\n-        }\n-        $this->checkNestedContextStart($cName);\n-        if ($instance === null && $this->canCreateFromAbstractFactory($cName, $rName)) {\n-            $instance = $this->createFromAbstractFactory($cName, $rName);\n-        }\n-        $this->checkNestedContextStop();\n+        $factory = isset($this->factories[$name]) ? $this->factories[$name] : null;\n \n-        if ($instance === null && $this->throwExceptionInCreate) {\n-            $this->checkNestedContextStop(true);\n-            throw new Exception\\ServiceNotFoundException(sprintf(\n-                'No valid instance was found for %s%s',\n-                $cName,\n-                ($rName ? '(alias: ' . $rName . ')' : '')\n-            ));\n+        if (is_string($factory)) {\n+            $this->factories[$name] = $factory = new $factory();\n         }\n \n-        // Do not call initializers if we do not have an instance\n-        if ($instance === null) {\n-            return $instance;\n+        if (is_callable($factory)) {\n+            return $factory;\n         }\n \n-        foreach ($this->initializers as $initializer) {\n-            if ($initializer instanceof InitializerInterface) {\n-                $initializer->initialize($instance, $this);\n-            } else {\n-                call_user_func($initializer, $instance, $this);\n+        // Check abstract factories\n+        foreach ($this->abstractFactories as $abstractFactory) {\n+            if ($abstractFactory->canCreateServiceWithName($this, $name)) {\n+                return $abstractFactory;\n             }\n         }\n \n-        return $instance;\n-    }\n-\n-    /**\n-     * Determine if we can create an instance.\n-     * Proxies to has()\n-     *\n-     * @param  string|array $name\n-     * @param  bool         $checkAbstractFactories\n-     * @return bool\n-     * @deprecated this method is being deprecated as of zendframework 2.3, and may be removed in future major versions\n-     */\n-    public function canCreate($name, $checkAbstractFactories = true)\n-    {\n-        trigger_error(sprintf('%s is deprecated; please use %s::has', __METHOD__, __CLASS__), E_USER_DEPRECATED);\n-        return $this->has($name, $checkAbstractFactories, false);\n+        throw new ServiceNotFoundException(sprintf(\n+            'An invalid or missing factory was given for creating service \"%s\". Did you make sure you added the service\n+             into the service manager configuration?',\n+            $name\n+        ));\n     }\n \n     /**\n-     * Determine if an instance exists.\n-     *\n-     * @param  string|array  $name  An array argument accepts exactly two values.\n-     *                              Example: array('canonicalName', 'requestName')\n-     * @param  bool          $checkAbstractFactories\n-     * @param  bool          $usePeeringServiceManagers\n-     * @return bool\n+     * @param  string     $name\n+     * @param  null|array $options\n+     * @return object\n      */\n-    public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = true)\n+    private function createDelegatorFromName($name, array $options = null)\n     {\n-        if (is_string($name)) {\n-            $rName = $name;\n-\n-            // inlined code from ServiceManager::canonicalizeName for performance\n-            if (isset($this->canonicalNames[$rName])) {\n-                $cName = $this->canonicalNames[$rName];\n-            } else {\n-                $cName = $this->canonicalizeName($name);\n-            }\n-        } elseif (is_array($name) && count($name) >= 2) {\n-            list($cName, $rName) = $name;\n-        } else {\n-            return false;\n-        }\n-\n-        if (isset($this->invokableClasses[$cName])\n-            || isset($this->factories[$cName])\n-            || isset($this->aliases[$cName])\n-            || isset($this->instances[$cName])\n-            || ($checkAbstractFactories && $this->canCreateFromAbstractFactory($cName, $rName))\n-        ) {\n-            return true;\n-        }\n-\n-        if ($usePeeringServiceManagers) {\n-            $caller = $this->serviceManagerCaller;\n-            foreach ($this->peeringServiceManagers as $peeringServiceManager) {\n-                // ignore peering service manager if they are the same instance\n-                if ($caller === $peeringServiceManager) {\n-                    continue;\n-                }\n-\n-                $peeringServiceManager->serviceManagerCaller = $this;\n+        $delegatorsCount  = count($this->delegators[$name]);\n+        $creationCallback = function () use ($name, $options) {\n+            // Code is inlined for performance reason, instead of abstracting the creation\n+            $factory = $this->getFactory($name);\n+            return $factory($this->creationContext, $name, $options);\n+        };\n \n-                if ($peeringServiceManager->has($name)) {\n-                    $peeringServiceManager->serviceManagerCaller = null;\n-                    return true;\n-                }\n+        for ($i = 0; $i < $delegatorsCount; $i += 1) {\n+            $delegatorFactory = $this->delegators[$name][$i];\n \n-                $peeringServiceManager->serviceManagerCaller = null;\n+            if ($delegatorFactory === Proxy\\LazyServiceFactory::class) {\n+                $delegatorFactory = $this->createLazyServiceDelegatorFactory();\n             }\n-        }\n \n-        return false;\n-    }\n-\n-    /**\n-     * Determine if we can create an instance from an abstract factory.\n-     *\n-     * @param  string $cName\n-     * @param  string $rName\n-     * @return bool\n-     */\n-    public function canCreateFromAbstractFactory($cName, $rName)\n-    {\n-        if (array_key_exists($cName, $this->nestedContext)) {\n-            $context = $this->nestedContext[$cName];\n-            if ($context === false) {\n-                return false;\n-            } elseif (is_object($context)) {\n-                return !isset($this->pendingAbstractFactoryRequests[get_class($context).$cName]);\n-            }\n-        }\n-        $this->checkNestedContextStart($cName);\n-        // check abstract factories\n-        $result = false;\n-        $this->nestedContext[$cName] = false;\n-        foreach ($this->abstractFactories as $abstractFactory) {\n-            $pendingKey = get_class($abstractFactory).$cName;\n-            if (isset($this->pendingAbstractFactoryRequests[$pendingKey])) {\n-                $result = false;\n-                break;\n+            if (is_string($delegatorFactory) && ! class_exists($delegatorFactory)) {\n+                throw new ServiceNotCreatedException(sprintf(\n+                    'An invalid delegator was provided. A callable or an instance of \"%s\" as expected, '\n+                    . 'but \"%s\" was received',\n+                    DelegatorFactoryInterface::class,\n+                    $delegatorFactory\n+                ));\n             }\n \n-            if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) {\n-                $this->nestedContext[$cName] = $abstractFactory;\n-                $result = true;\n-                break;\n+            if (is_string($delegatorFactory)) {\n+                $delegatorFactory = $this->delegators[$name][$i] = new $delegatorFactory();\n             }\n-        }\n-        $this->checkNestedContextStop();\n-        return $result;\n-    }\n-\n-    /**\n-     * Ensure the alias definition will not result in a circular reference\n-     *\n-     * @param  string $alias\n-     * @param  string $nameOrAlias\n-     * @throws Exception\\CircularReferenceException\n-     * @return self\n-     */\n-    protected function checkForCircularAliasReference($alias, $nameOrAlias)\n-    {\n-        $aliases = $this->aliases;\n-        $aliases[$alias] = $nameOrAlias;\n-        $stack = [];\n \n-        while (isset($aliases[$alias])) {\n-            if (isset($stack[$alias])) {\n-                throw new Exception\\CircularReferenceException(sprintf(\n-                    'The alias definition \"%s\" : \"%s\" results in a circular reference: \"%s\" -> \"%s\"',\n-                    $alias,\n-                    $nameOrAlias,\n-                    implode('\" -> \"', $stack),\n-                    $alias\n+            if (! is_callable($delegatorFactory)) {\n+                throw new ServiceNotCreatedException(sprintf(\n+                    'An invalid delegator was provided. A callable or an instance of \"%s\" as expected, '","path":"src/ServiceManager.php","position":1029,"original_position":1029,"commit_id":"99a18ee4bcdfa20a2e98bdd990fb83296e779052","original_commit_id":"99a18ee4bcdfa20a2e98bdd990fb83296e779052","user":{"login":"Maks3w","id":1301698,"avatar_url":"https://avatars.githubusercontent.com/u/1301698?v=3","gravatar_id":"","url":"https://api.github.com/users/Maks3w","html_url":"https://github.com/Maks3w","followers_url":"https://api.github.com/users/Maks3w/followers","following_url":"https://api.github.com/users/Maks3w/following{/other_user}","gists_url":"https://api.github.com/users/Maks3w/gists{/gist_id}","starred_url":"https://api.github.com/users/Maks3w/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Maks3w/subscriptions","organizations_url":"https://api.github.com/users/Maks3w/orgs","repos_url":"https://api.github.com/users/Maks3w/repos","events_url":"https://api.github.com/users/Maks3w/events{/privacy}","received_events_url":"https://api.github.com/users/Maks3w/received_events","type":"User","site_admin":false},"body":"s/as expected/was expected/","created_at":"2015-09-16T17:23:04Z","updated_at":"2015-09-16T17:23:04Z","html_url":"https://github.com/zendframework/zend-servicemanager/pull/9#discussion_r39658910","pull_request_url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9","_links":{"self":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/comments/39658910"},"html":{"href":"https://github.com/zendframework/zend-servicemanager/pull/9#discussion_r39658910"},"pull_request":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9"}}},"pull_request":{"url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9","id":44047362,"html_url":"https://github.com/zendframework/zend-servicemanager/pull/9","diff_url":"https://github.com/zendframework/zend-servicemanager/pull/9.diff","patch_url":"https://github.com/zendframework/zend-servicemanager/pull/9.patch","issue_url":"https://api.github.com/repos/zendframework/zend-servicemanager/issues/9","number":9,"state":"open","locked":false,"title":"[ZF3] Refactoring Service Manager","user":{"login":"weierophinney","id":25943,"avatar_url":"https://avatars.githubusercontent.com/u/25943?v=3","gravatar_id":"","url":"https://api.github.com/users/weierophinney","html_url":"https://github.com/weierophinney","followers_url":"https://api.github.com/users/weierophinney/followers","following_url":"https://api.github.com/users/weierophinney/following{/other_user}","gists_url":"https://api.github.com/users/weierophinney/gists{/gist_id}","starred_url":"https://api.github.com/users/weierophinney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weierophinney/subscriptions","organizations_url":"https://api.github.com/users/weierophinney/orgs","repos_url":"https://api.github.com/users/weierophinney/repos","events_url":"https://api.github.com/users/weierophinney/events{/privacy}","received_events_url":"https://api.github.com/users/weierophinney/received_events","type":"User","site_admin":false},"body":"This is a rebase of #8 against develop, intended for v3.0. Please see that PR for relevant discussion; we can now start testing and refining against this PR, however.\r\n\r\nTo test, fetch my branch:\r\n\r\n```bash\r\n$ git remote add weierophinney git://github.com/weierophinney/zend-servicemanager\r\n$ git fetch weierophinney\r\n$ git checkout -b refactor-sm weierophinney/refactor-sm\r\n```\r\n\r\n## Remaining TODO\r\n\r\n- [x] Migration guide\r\n  - [x] How does configuration differ? (mostly: invokables, lazy services)\r\n  - [x] How does the consumable API differ? (no ability to `set` or `add` factories)\r\n  - [x] What interfaces have changed?\r\n    - [x] FactoryInterface\r\n    - [x] AbstractFactoryInterface\r\n    - [x] InitializerInterface\r\n    - [x] DelegatorFactoryInterface\r\n    - [x] ServiceLocatorInterface (extends ContainerInterface, adds `build()`)\r\n  - [x] How are plugin managers different?\r\n    - [x] New interface\r\n    - [x] Abstract class has reasonable validation by default, based on a property you define\r\n    - [x] get() proxies to build() (discrete instances by default)","created_at":"2015-09-02T21:53:36Z","updated_at":"2015-09-16T17:23:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"83765182156c96c748bbfd08d759996923c2303c","assignee":null,"milestone":{"url":"https://api.github.com/repos/zendframework/zend-servicemanager/milestones/2","html_url":"https://github.com/zendframework/zend-servicemanager/milestones/3.0.0","labels_url":"https://api.github.com/repos/zendframework/zend-servicemanager/milestones/2/labels","id":1137664,"number":2,"title":"3.0.0","description":"next backward compatibility break release","creator":{"login":"Maks3w","id":1301698,"avatar_url":"https://avatars.githubusercontent.com/u/1301698?v=3","gravatar_id":"","url":"https://api.github.com/users/Maks3w","html_url":"https://github.com/Maks3w","followers_url":"https://api.github.com/users/Maks3w/followers","following_url":"https://api.github.com/users/Maks3w/following{/other_user}","gists_url":"https://api.github.com/users/Maks3w/gists{/gist_id}","starred_url":"https://api.github.com/users/Maks3w/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Maks3w/subscriptions","organizations_url":"https://api.github.com/users/Maks3w/orgs","repos_url":"https://api.github.com/users/Maks3w/repos","events_url":"https://api.github.com/users/Maks3w/events{/privacy}","received_events_url":"https://api.github.com/users/Maks3w/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":1,"state":"open","created_at":"2015-05-28T09:28:15Z","updated_at":"2015-09-04T17:55:17Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9/commits","review_comments_url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9/comments","review_comment_url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/comments{/number}","comments_url":"https://api.github.com/repos/zendframework/zend-servicemanager/issues/9/comments","statuses_url":"https://api.github.com/repos/zendframework/zend-servicemanager/statuses/99a18ee4bcdfa20a2e98bdd990fb83296e779052","head":{"label":"weierophinney:refactor-sm","ref":"refactor-sm","sha":"99a18ee4bcdfa20a2e98bdd990fb83296e779052","user":{"login":"weierophinney","id":25943,"avatar_url":"https://avatars.githubusercontent.com/u/25943?v=3","gravatar_id":"","url":"https://api.github.com/users/weierophinney","html_url":"https://github.com/weierophinney","followers_url":"https://api.github.com/users/weierophinney/followers","following_url":"https://api.github.com/users/weierophinney/following{/other_user}","gists_url":"https://api.github.com/users/weierophinney/gists{/gist_id}","starred_url":"https://api.github.com/users/weierophinney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weierophinney/subscriptions","organizations_url":"https://api.github.com/users/weierophinney/orgs","repos_url":"https://api.github.com/users/weierophinney/repos","events_url":"https://api.github.com/users/weierophinney/events{/privacy}","received_events_url":"https://api.github.com/users/weierophinney/received_events","type":"User","site_admin":false},"repo":{"id":41829492,"name":"zend-servicemanager","full_name":"weierophinney/zend-servicemanager","owner":{"login":"weierophinney","id":25943,"avatar_url":"https://avatars.githubusercontent.com/u/25943?v=3","gravatar_id":"","url":"https://api.github.com/users/weierophinney","html_url":"https://github.com/weierophinney","followers_url":"https://api.github.com/users/weierophinney/followers","following_url":"https://api.github.com/users/weierophinney/following{/other_user}","gists_url":"https://api.github.com/users/weierophinney/gists{/gist_id}","starred_url":"https://api.github.com/users/weierophinney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weierophinney/subscriptions","organizations_url":"https://api.github.com/users/weierophinney/orgs","repos_url":"https://api.github.com/users/weierophinney/repos","events_url":"https://api.github.com/users/weierophinney/events{/privacy}","received_events_url":"https://api.github.com/users/weierophinney/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/weierophinney/zend-servicemanager","description":"ServiceManager component from Zend Framework","fork":true,"url":"https://api.github.com/repos/weierophinney/zend-servicemanager","forks_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/forks","keys_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/keys{/key_id}","collaborators_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/teams","hooks_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/hooks","issue_events_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/issues/events{/number}","events_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/events","assignees_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/assignees{/user}","branches_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/branches{/branch}","tags_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/tags","blobs_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/git/refs{/sha}","trees_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/git/trees{/sha}","statuses_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/statuses/{sha}","languages_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/languages","stargazers_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/stargazers","contributors_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/contributors","subscribers_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/subscribers","subscription_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/subscription","commits_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/commits{/sha}","git_commits_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/git/commits{/sha}","comments_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/comments{/number}","issue_comment_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/issues/comments{/number}","contents_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/contents/{+path}","compare_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/compare/{base}...{head}","merges_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/merges","archive_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/downloads","issues_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/issues{/number}","pulls_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/pulls{/number}","milestones_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/milestones{/number}","notifications_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/labels{/name}","releases_url":"https://api.github.com/repos/weierophinney/zend-servicemanager/releases{/id}","created_at":"2015-09-02T21:49:56Z","updated_at":"2015-09-02T21:49:57Z","pushed_at":"2015-09-16T16:31:44Z","git_url":"git://github.com/weierophinney/zend-servicemanager.git","ssh_url":"git@github.com:weierophinney/zend-servicemanager.git","clone_url":"https://github.com/weierophinney/zend-servicemanager.git","svn_url":"https://github.com/weierophinney/zend-servicemanager","homepage":"https://github.com/zendframework/zf2","size":1918,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"zendframework:develop","ref":"develop","sha":"a4914dd73d7e5661a813db92bf26754a9605787b","user":{"login":"zendframework","id":296074,"avatar_url":"https://avatars.githubusercontent.com/u/296074?v=3","gravatar_id":"","url":"https://api.github.com/users/zendframework","html_url":"https://github.com/zendframework","followers_url":"https://api.github.com/users/zendframework/followers","following_url":"https://api.github.com/users/zendframework/following{/other_user}","gists_url":"https://api.github.com/users/zendframework/gists{/gist_id}","starred_url":"https://api.github.com/users/zendframework/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zendframework/subscriptions","organizations_url":"https://api.github.com/users/zendframework/orgs","repos_url":"https://api.github.com/users/zendframework/repos","events_url":"https://api.github.com/users/zendframework/events{/privacy}","received_events_url":"https://api.github.com/users/zendframework/received_events","type":"Organization","site_admin":false},"repo":{"id":35280826,"name":"zend-servicemanager","full_name":"zendframework/zend-servicemanager","owner":{"login":"zendframework","id":296074,"avatar_url":"https://avatars.githubusercontent.com/u/296074?v=3","gravatar_id":"","url":"https://api.github.com/users/zendframework","html_url":"https://github.com/zendframework","followers_url":"https://api.github.com/users/zendframework/followers","following_url":"https://api.github.com/users/zendframework/following{/other_user}","gists_url":"https://api.github.com/users/zendframework/gists{/gist_id}","starred_url":"https://api.github.com/users/zendframework/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zendframework/subscriptions","organizations_url":"https://api.github.com/users/zendframework/orgs","repos_url":"https://api.github.com/users/zendframework/repos","events_url":"https://api.github.com/users/zendframework/events{/privacy}","received_events_url":"https://api.github.com/users/zendframework/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/zendframework/zend-servicemanager","description":"ServiceManager component from Zend Framework","fork":false,"url":"https://api.github.com/repos/zendframework/zend-servicemanager","forks_url":"https://api.github.com/repos/zendframework/zend-servicemanager/forks","keys_url":"https://api.github.com/repos/zendframework/zend-servicemanager/keys{/key_id}","collaborators_url":"https://api.github.com/repos/zendframework/zend-servicemanager/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/zendframework/zend-servicemanager/teams","hooks_url":"https://api.github.com/repos/zendframework/zend-servicemanager/hooks","issue_events_url":"https://api.github.com/repos/zendframework/zend-servicemanager/issues/events{/number}","events_url":"https://api.github.com/repos/zendframework/zend-servicemanager/events","assignees_url":"https://api.github.com/repos/zendframework/zend-servicemanager/assignees{/user}","branches_url":"https://api.github.com/repos/zendframework/zend-servicemanager/branches{/branch}","tags_url":"https://api.github.com/repos/zendframework/zend-servicemanager/tags","blobs_url":"https://api.github.com/repos/zendframework/zend-servicemanager/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/zendframework/zend-servicemanager/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/zendframework/zend-servicemanager/git/refs{/sha}","trees_url":"https://api.github.com/repos/zendframework/zend-servicemanager/git/trees{/sha}","statuses_url":"https://api.github.com/repos/zendframework/zend-servicemanager/statuses/{sha}","languages_url":"https://api.github.com/repos/zendframework/zend-servicemanager/languages","stargazers_url":"https://api.github.com/repos/zendframework/zend-servicemanager/stargazers","contributors_url":"https://api.github.com/repos/zendframework/zend-servicemanager/contributors","subscribers_url":"https://api.github.com/repos/zendframework/zend-servicemanager/subscribers","subscription_url":"https://api.github.com/repos/zendframework/zend-servicemanager/subscription","commits_url":"https://api.github.com/repos/zendframework/zend-servicemanager/commits{/sha}","git_commits_url":"https://api.github.com/repos/zendframework/zend-servicemanager/git/commits{/sha}","comments_url":"https://api.github.com/repos/zendframework/zend-servicemanager/comments{/number}","issue_comment_url":"https://api.github.com/repos/zendframework/zend-servicemanager/issues/comments{/number}","contents_url":"https://api.github.com/repos/zendframework/zend-servicemanager/contents/{+path}","compare_url":"https://api.github.com/repos/zendframework/zend-servicemanager/compare/{base}...{head}","merges_url":"https://api.github.com/repos/zendframework/zend-servicemanager/merges","archive_url":"https://api.github.com/repos/zendframework/zend-servicemanager/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/zendframework/zend-servicemanager/downloads","issues_url":"https://api.github.com/repos/zendframework/zend-servicemanager/issues{/number}","pulls_url":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls{/number}","milestones_url":"https://api.github.com/repos/zendframework/zend-servicemanager/milestones{/number}","notifications_url":"https://api.github.com/repos/zendframework/zend-servicemanager/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/zendframework/zend-servicemanager/labels{/name}","releases_url":"https://api.github.com/repos/zendframework/zend-servicemanager/releases{/id}","created_at":"2015-05-08T13:28:10Z","updated_at":"2015-09-16T10:00:57Z","pushed_at":"2015-09-16T16:31:45Z","git_url":"git://github.com/zendframework/zend-servicemanager.git","ssh_url":"git@github.com:zendframework/zend-servicemanager.git","clone_url":"https://github.com/zendframework/zend-servicemanager.git","svn_url":"https://github.com/zendframework/zend-servicemanager","homepage":"https://github.com/zendframework/zf2","size":2421,"stargazers_count":14,"watchers_count":14,"language":"PHP","has_issues":true,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":12,"mirror_url":null,"open_issues_count":2,"forks":12,"open_issues":2,"watchers":14,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9"},"html":{"href":"https://github.com/zendframework/zend-servicemanager/pull/9"},"issue":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/issues/9"},"comments":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/issues/9/comments"},"review_comments":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9/comments"},"review_comment":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/pulls/9/commits"},"statuses":{"href":"https://api.github.com/repos/zendframework/zend-servicemanager/statuses/99a18ee4bcdfa20a2e98bdd990fb83296e779052"}}}}