Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Di / Di.php
blobaa440dcd959be2c4b2094c3d2626a039113c0a34
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Di;
12 use Closure;
13 use ReflectionClass;
14 use Zend\Di\Exception\RuntimeException as DiRuntimeException;
15 use Zend\ServiceManager\Exception\ExceptionInterface as ServiceManagerException;
17 /**
18 * Dependency injector that can generate instances using class definitions and configured instance parameters
20 class Di implements DependencyInjectionInterface
22 /**
23 * @var DefinitionList
25 protected $definitions = null;
27 /**
28 * @var InstanceManager
30 protected $instanceManager = null;
32 /**
33 * @var string
35 protected $instanceContext = array();
37 /**
38 * All the class dependencies [source][dependency]
40 * @var array
42 protected $currentDependencies = array();
44 /**
45 * All the class references [dependency][source]
47 * @var array
49 protected $references = array();
51 /**
52 * Resolve method policy
54 * EAGER: explore type preference or go through
56 const RESOLVE_EAGER = 1;
58 /**
59 * Resolve method policy
61 * STRICT: explore type preference or throw exception
63 const RESOLVE_STRICT = 2;
65 /**
67 * use only specified parameters
69 const METHOD_IS_OPTIONAL = 0;
71 /**
73 * resolve mode RESOLVE_EAGER
75 const METHOD_IS_AWARE = 1;
77 /**
79 * resolve mode RESOLVE_EAGER | RESOLVE_STRICT
81 const METHOD_IS_CONSTRUCTOR = 3;
83 /**
85 * resolve mode RESOLVE_EAGER | RESOLVE_STRICT
87 const METHOD_IS_INSTANTIATOR = 3;
89 /**
91 * resolve mode RESOLVE_EAGER | RESOLVE_STRICT
93 const METHOD_IS_REQUIRED = 3;
95 /**
97 * resolve mode RESOLVE_EAGER
99 const METHOD_IS_EAGER = 1;
102 * Constructor
104 * @param null|DefinitionList $definitions
105 * @param null|InstanceManager $instanceManager
106 * @param null|Config $config
108 public function __construct(DefinitionList $definitions = null, InstanceManager $instanceManager = null, Config $config = null)
110 $this->definitions = ($definitions) ?: new DefinitionList(new Definition\RuntimeDefinition());
111 $this->instanceManager = ($instanceManager) ?: new InstanceManager();
113 if ($config) {
114 $this->configure($config);
119 * Provide a configuration object to configure this instance
121 * @param Config $config
122 * @return void
124 public function configure(Config $config)
126 $config->configure($this);
130 * @param DefinitionList $definitions
131 * @return self
133 public function setDefinitionList(DefinitionList $definitions)
135 $this->definitions = $definitions;
137 return $this;
141 * @return DefinitionList
143 public function definitions()
145 return $this->definitions;
149 * Set the instance manager
151 * @param InstanceManager $instanceManager
152 * @return Di
154 public function setInstanceManager(InstanceManager $instanceManager)
156 $this->instanceManager = $instanceManager;
158 return $this;
163 * @return InstanceManager
165 public function instanceManager()
167 return $this->instanceManager;
171 * @param $name
172 * @param array $params
173 * @param string $method
174 * @return array
176 protected function getCallParameters($name, array $params, $method = "__construct")
178 $im = $this->instanceManager;
179 $class = $im->hasAlias($name) ? $im->getClassFromAlias($name) : $name;
180 if ($this->definitions->hasClass($class)) {
181 $callParameters = array();
182 if ($this->definitions->hasMethod($class, $method)) {
183 foreach ($this->definitions->getMethodParameters($class, $method) as $param) {
184 if (isset($params[$param[0]])) {
185 $callParameters[$param[0]] = $params[$param[0]];
189 return $callParameters;
191 return $params;
195 * Lazy-load a class
197 * Attempts to load the class (or service alias) provided. If it has been
198 * loaded before, the previous instance will be returned (unless the service
199 * definition indicates shared instances should not be used).
201 * @param string $name Class name or service alias
202 * @param null|array $params Parameters to pass to the constructor
203 * @return object|null
205 public function get($name, array $params = array())
207 array_push($this->instanceContext, array('GET', $name, null));
209 $im = $this->instanceManager;
211 $callParameters = $this->getCallParameters($name, $params);
212 if ($callParameters) {
213 $fastHash = $im->hasSharedInstanceWithParameters($name, $callParameters, true);
214 if ($fastHash) {
215 array_pop($this->instanceContext);
216 return $im->getSharedInstanceWithParameters(null, array(), $fastHash);
220 if ($im->hasSharedInstance($name, $callParameters)) {
221 array_pop($this->instanceContext);
222 return $im->getSharedInstance($name, $callParameters);
226 $config = $im->getConfig($name);
227 $instance = $this->newInstance($name, $params, $config['shared']);
228 array_pop($this->instanceContext);
230 return $instance;
234 * Retrieve a new instance of a class
236 * Forces retrieval of a discrete instance of the given class, using the
237 * constructor parameters provided.
239 * @param mixed $name Class name or service alias
240 * @param array $params Parameters to pass to the constructor
241 * @param bool $isShared
242 * @return object|null
243 * @throws Exception\ClassNotFoundException
244 * @throws Exception\RuntimeException
246 public function newInstance($name, array $params = array(), $isShared = true)
248 // localize dependencies
249 $definitions = $this->definitions;
250 $instanceManager = $this->instanceManager();
252 if ($instanceManager->hasAlias($name)) {
253 $class = $instanceManager->getClassFromAlias($name);
254 $alias = $name;
255 } else {
256 $class = $name;
257 $alias = null;
260 array_push($this->instanceContext, array('NEW', $class, $alias));
262 if (!$definitions->hasClass($class)) {
263 $aliasMsg = ($alias) ? '(specified by alias ' . $alias . ') ' : '';
264 throw new Exception\ClassNotFoundException(
265 'Class ' . $aliasMsg . $class . ' could not be located in provided definitions.'
269 $instantiator = $definitions->getInstantiator($class);
270 $injectionMethods = array();
271 $injectionMethods[$class] = $definitions->getMethods($class);
273 foreach ($definitions->getClassSupertypes($class) as $supertype) {
274 $injectionMethods[$supertype] = $definitions->getMethods($supertype);
277 if ($instantiator === '__construct') {
278 $instance = $this->createInstanceViaConstructor($class, $params, $alias);
279 if (array_key_exists('__construct', $injectionMethods)) {
280 unset($injectionMethods['__construct']);
282 } elseif (is_callable($instantiator, false)) {
283 $instance = $this->createInstanceViaCallback($instantiator, $params, $alias);
284 } else {
285 if (is_array($instantiator)) {
286 $msg = sprintf(
287 'Invalid instantiator: %s::%s() is not callable.',
288 isset($instantiator[0]) ? $instantiator[0] : 'NoClassGiven',
289 isset($instantiator[1]) ? $instantiator[1] : 'NoMethodGiven'
291 } else {
292 $msg = sprintf(
293 'Invalid instantiator of type "%s" for "%s".',
294 gettype($instantiator),
295 $name
298 throw new Exception\RuntimeException($msg);
301 if ($isShared) {
302 if ($callParameters = $this->getCallParameters($name, $params)) {
303 $this->instanceManager->addSharedInstanceWithParameters($instance, $name, $callParameters);
304 } else {
305 $this->instanceManager->addSharedInstance($instance, $name);
309 $this->handleInjectDependencies($instance, $injectionMethods, $params, $class, $alias, $name);
311 array_pop($this->instanceContext);
313 return $instance;
317 * Inject dependencies
319 * @param object $instance
320 * @param array $params
321 * @return void
323 public function injectDependencies($instance, array $params = array())
325 $definitions = $this->definitions();
326 $class = $this->getClass($instance);
327 $injectionMethods = array(
328 $class => ($definitions->hasClass($class)) ? $definitions->getMethods($class) : array()
330 $parent = $class;
331 while ($parent = get_parent_class($parent)) {
332 if ($definitions->hasClass($parent)) {
333 $injectionMethods[$parent] = $definitions->getMethods($parent);
336 foreach (class_implements($class) as $interface) {
337 if ($definitions->hasClass($interface)) {
338 $injectionMethods[$interface] = $definitions->getMethods($interface);
341 $this->handleInjectDependencies($instance, $injectionMethods, $params, $class, null, null);
345 * @param object $instance
346 * @param array $injectionMethods
347 * @param array $params
348 * @param string|null $instanceClass
349 * @param string|null$instanceAlias
350 * @param string $requestedName
351 * @throws Exception\RuntimeException
353 protected function handleInjectDependencies($instance, $injectionMethods, $params, $instanceClass, $instanceAlias, $requestedName)
355 // localize dependencies
356 $definitions = $this->definitions;
357 $instanceManager = $this->instanceManager();
359 $calledMethods = array('__construct' => true);
361 if ($injectionMethods) {
362 foreach ($injectionMethods as $type => $typeInjectionMethods) {
363 foreach ($typeInjectionMethods as $typeInjectionMethod => $methodRequirementType) {
364 if (!isset($calledMethods[$typeInjectionMethod])) {
365 if ($this->resolveAndCallInjectionMethodForInstance($instance, $typeInjectionMethod, $params, $instanceAlias, $methodRequirementType, $type)) {
366 $calledMethods[$typeInjectionMethod] = true;
372 if ($requestedName) {
373 $instanceConfig = $instanceManager->getConfig($requestedName);
375 if ($instanceConfig['injections']) {
376 $objectsToInject = $methodsToCall = array();
377 foreach ($instanceConfig['injections'] as $injectName => $injectValue) {
378 if (is_int($injectName) && is_string($injectValue)) {
379 $objectsToInject[] = $this->get($injectValue, $params);
380 } elseif (is_string($injectName) && is_array($injectValue)) {
381 if (is_string(key($injectValue))) {
382 $methodsToCall[] = array('method' => $injectName, 'args' => $injectValue);
383 } else {
384 foreach ($injectValue as $methodCallArgs) {
385 $methodsToCall[] = array('method' => $injectName, 'args' => $methodCallArgs);
388 } elseif (is_object($injectValue)) {
389 $objectsToInject[] = $injectValue;
390 } elseif (is_int($injectName) && is_array($injectValue)) {
391 throw new Exception\RuntimeException(
392 'An injection was provided with a keyed index and an array of data, try using'
393 . ' the name of a particular method as a key for your injection data.'
397 if ($objectsToInject) {
398 foreach ($objectsToInject as $objectToInject) {
399 $calledMethods = array('__construct' => true);
400 foreach ($injectionMethods as $type => $typeInjectionMethods) {
401 foreach ($typeInjectionMethods as $typeInjectionMethod => $methodRequirementType) {
402 if (!isset($calledMethods[$typeInjectionMethod])) {
403 $methodParams = $definitions->getMethodParameters($type, $typeInjectionMethod);
404 if ($methodParams) {
405 foreach ($methodParams as $methodParam) {
406 $objectToInjectClass = $this->getClass($objectToInject);
407 if ($objectToInjectClass == $methodParam[1] || self::isSubclassOf($objectToInjectClass, $methodParam[1])) {
408 if ($this->resolveAndCallInjectionMethodForInstance($instance, $typeInjectionMethod, array($methodParam[0] => $objectToInject), $instanceAlias, self::METHOD_IS_REQUIRED, $type)) {
409 $calledMethods[$typeInjectionMethod] = true;
411 continue 3;
420 if ($methodsToCall) {
421 foreach ($methodsToCall as $methodInfo) {
422 $this->resolveAndCallInjectionMethodForInstance($instance, $methodInfo['method'], $methodInfo['args'], $instanceAlias, self::METHOD_IS_REQUIRED, $instanceClass);
431 * Retrieve a class instance based on class name
433 * Any parameters provided will be used as constructor arguments. If any
434 * given parameter is a DependencyReference object, it will be fetched
435 * from the container so that the instance may be injected.
437 * @param string $class
438 * @param array $params
439 * @param string|null $alias
440 * @return object
442 protected function createInstanceViaConstructor($class, $params, $alias = null)
444 $callParameters = array();
445 if ($this->definitions->hasMethod($class, '__construct')) {
446 $callParameters = $this->resolveMethodParameters($class, '__construct', $params, $alias, self::METHOD_IS_CONSTRUCTOR, true);
449 if (!class_exists($class)) {
450 if (interface_exists($class)) {
451 throw new Exception\ClassNotFoundException(sprintf(
452 'Cannot instantiate interface "%s"',
453 $class
456 throw new Exception\ClassNotFoundException(sprintf(
457 'Class "%s" does not exist; cannot instantiate',
458 $class
462 // Hack to avoid Reflection in most common use cases
463 switch (count($callParameters)) {
464 case 0:
465 return new $class();
466 case 1:
467 return new $class($callParameters[0]);
468 case 2:
469 return new $class($callParameters[0], $callParameters[1]);
470 case 3:
471 return new $class($callParameters[0], $callParameters[1], $callParameters[2]);
472 default:
473 $r = new \ReflectionClass($class);
475 return $r->newInstanceArgs($callParameters);
480 * Get an object instance from the defined callback
482 * @param callable $callback
483 * @param array $params
484 * @param string $alias
485 * @return object
486 * @throws Exception\InvalidCallbackException
487 * @throws Exception\RuntimeException
489 protected function createInstanceViaCallback($callback, $params, $alias)
491 if (!is_callable($callback)) {
492 throw new Exception\InvalidCallbackException('An invalid constructor callback was provided');
495 if (is_array($callback)) {
496 $class = (is_object($callback[0])) ? $this->getClass($callback[0]) : $callback[0];
497 $method = $callback[1];
498 } elseif (is_string($callback) && strpos($callback, '::') !== false) {
499 list($class, $method) = explode('::', $callback, 2);
500 } else {
501 throw new Exception\RuntimeException('Invalid callback type provided to ' . __METHOD__);
504 $callParameters = array();
505 if ($this->definitions->hasMethod($class, $method)) {
506 $callParameters = $this->resolveMethodParameters($class, $method, $params, $alias, self::METHOD_IS_INSTANTIATOR, true);
509 return call_user_func_array($callback, $callParameters);
513 * This parameter will handle any injection methods and resolution of
514 * dependencies for such methods
516 * @param object $instance
517 * @param string $method
518 * @param array $params
519 * @param string $alias
520 * @param bool $methodRequirementType
521 * @param string|null $methodClass
522 * @return bool
524 protected function resolveAndCallInjectionMethodForInstance($instance, $method, $params, $alias, $methodRequirementType, $methodClass = null)
526 $methodClass = ($methodClass) ?: $this->getClass($instance);
527 $callParameters = $this->resolveMethodParameters($methodClass, $method, $params, $alias, $methodRequirementType);
528 if ($callParameters == false) {
529 return false;
531 if ($callParameters !== array_fill(0, count($callParameters), null)) {
532 call_user_func_array(array($instance, $method), $callParameters);
534 return true;
537 return false;
541 * Resolve parameters referencing other services
543 * @param string $class
544 * @param string $method
545 * @param array $callTimeUserParams
546 * @param string $alias
547 * @param int|bolean $methodRequirementType
548 * @param bool $isInstantiator
549 * @throws Exception\MissingPropertyException
550 * @throws Exception\CircularDependencyException
551 * @return array
553 protected function resolveMethodParameters($class, $method, array $callTimeUserParams, $alias, $methodRequirementType, $isInstantiator = false)
555 //for BC
556 if (is_bool($methodRequirementType)) {
557 if ($isInstantiator) {
558 $methodRequirementType = Di::METHOD_IS_INSTANTIATOR;
559 } elseif ($methodRequirementType) {
560 $methodRequirementType = Di::METHOD_IS_REQUIRED;
561 } else {
562 $methodRequirementType = Di::METHOD_IS_OPTIONAL;
565 // parameters for this method, in proper order, to be returned
566 $resolvedParams = array();
568 // parameter requirements from the definition
569 $injectionMethodParameters = $this->definitions->getMethodParameters($class, $method);
571 // computed parameters array
572 $computedParams = array(
573 'value' => array(),
574 'retrieval' => array(),
575 'optional' => array()
578 // retrieve instance configurations for all contexts
579 $iConfig = array();
580 $aliases = $this->instanceManager->getAliases();
582 // for the alias in the dependency tree
583 if ($alias && $this->instanceManager->hasConfig($alias)) {
584 $iConfig['thisAlias'] = $this->instanceManager->getConfig($alias);
587 // for the current class in the dependency tree
588 if ($this->instanceManager->hasConfig($class)) {
589 $iConfig['thisClass'] = $this->instanceManager->getConfig($class);
592 // for the parent class, provided we are deeper than one node
593 if (isset($this->instanceContext[0])) {
594 list($requestedClass, $requestedAlias) = ($this->instanceContext[0][0] == 'NEW')
595 ? array($this->instanceContext[0][1], $this->instanceContext[0][2])
596 : array($this->instanceContext[1][1], $this->instanceContext[1][2]);
597 } else {
598 $requestedClass = $requestedAlias = null;
601 if ($requestedClass != $class && $this->instanceManager->hasConfig($requestedClass)) {
602 $iConfig['requestedClass'] = $this->instanceManager->getConfig($requestedClass);
604 if (array_key_exists('parameters', $iConfig['requestedClass'])) {
605 $newParameters = array();
607 foreach($iConfig['requestedClass']['parameters'] as $name=>$parameter) {
608 $newParameters[$requestedClass.'::'.$method.'::'.$name] = $parameter;
611 $iConfig['requestedClass']['parameters'] = $newParameters;
614 if ($requestedAlias) {
615 $iConfig['requestedAlias'] = $this->instanceManager->getConfig($requestedAlias);
619 // This is a 2 pass system for resolving parameters
620 // first pass will find the sources, the second pass will order them and resolve lookups if they exist
621 // MOST methods will only have a single parameters to resolve, so this should be fast
623 foreach ($injectionMethodParameters as $fqParamPos => $info) {
624 list($name, $type, $isRequired) = $info;
626 $fqParamName = substr_replace($fqParamPos, ':' . $info[0], strrpos($fqParamPos, ':'));
628 // PRIORITY 1 - consult user provided parameters
629 if (isset($callTimeUserParams[$fqParamPos]) || isset($callTimeUserParams[$name])) {
631 if (isset($callTimeUserParams[$fqParamPos])) {
632 $callTimeCurValue =& $callTimeUserParams[$fqParamPos];
633 } elseif (isset($callTimeUserParams[$fqParamName])) {
634 $callTimeCurValue =& $callTimeUserParams[$fqParamName];
635 } else {
636 $callTimeCurValue =& $callTimeUserParams[$name];
639 if ($type !== false && is_string($callTimeCurValue)) {
640 if ($this->instanceManager->hasAlias($callTimeCurValue)) {
641 // was an alias provided?
642 $computedParams['retrieval'][$fqParamPos] = array(
643 $callTimeUserParams[$name],
644 $this->instanceManager->getClassFromAlias($callTimeCurValue)
646 } elseif ($this->definitions->hasClass($callTimeUserParams[$name])) {
647 // was a known class provided?
648 $computedParams['retrieval'][$fqParamPos] = array(
649 $callTimeCurValue,
650 $callTimeCurValue
652 } else {
653 // must be a value
654 $computedParams['value'][$fqParamPos] = $callTimeCurValue;
656 } else {
657 // int, float, null, object, etc
658 $computedParams['value'][$fqParamPos] = $callTimeCurValue;
660 unset($callTimeCurValue);
661 continue;
664 // PRIORITY 2 -specific instance configuration (thisAlias) - this alias
665 // PRIORITY 3 -THEN specific instance configuration (thisClass) - this class
666 // PRIORITY 4 -THEN specific instance configuration (requestedAlias) - requested alias
667 // PRIORITY 5 -THEN specific instance configuration (requestedClass) - requested class
669 foreach (array('thisAlias', 'thisClass', 'requestedAlias', 'requestedClass') as $thisIndex) {
670 // check the provided parameters config
671 if (isset($iConfig[$thisIndex]['parameters'][$fqParamPos])
672 || isset($iConfig[$thisIndex]['parameters'][$fqParamName])
673 || isset($iConfig[$thisIndex]['parameters'][$name])) {
675 if (isset($iConfig[$thisIndex]['parameters'][$fqParamPos])) {
676 $iConfigCurValue =& $iConfig[$thisIndex]['parameters'][$fqParamPos];
677 } elseif (isset($iConfig[$thisIndex]['parameters'][$fqParamName])) {
678 $iConfigCurValue =& $iConfig[$thisIndex]['parameters'][$fqParamName];
679 } else {
680 $iConfigCurValue =& $iConfig[$thisIndex]['parameters'][$name];
683 if ($type === false && is_string($iConfigCurValue)) {
684 $computedParams['value'][$fqParamPos] = $iConfigCurValue;
685 } elseif (is_string($iConfigCurValue)
686 && isset($aliases[$iConfigCurValue])) {
687 $computedParams['retrieval'][$fqParamPos] = array(
688 $iConfig[$thisIndex]['parameters'][$name],
689 $this->instanceManager->getClassFromAlias($iConfigCurValue)
691 } elseif (is_string($iConfigCurValue)
692 && $this->definitions->hasClass($iConfigCurValue)) {
693 $computedParams['retrieval'][$fqParamPos] = array(
694 $iConfigCurValue,
695 $iConfigCurValue
697 } elseif (is_object($iConfigCurValue)
698 && $iConfigCurValue instanceof Closure
699 && $type !== 'Closure') {
700 /* @var $iConfigCurValue Closure */
701 $computedParams['value'][$fqParamPos] = $iConfigCurValue();
702 } else {
703 $computedParams['value'][$fqParamPos] = $iConfigCurValue;
705 unset($iConfigCurValue);
706 continue 2;
711 // PRIORITY 6 - globally preferred implementations
713 // next consult alias level preferred instances
714 // RESOLVE_EAGER wants to inject the cross-cutting concerns.
715 // If you want to retrieve an instance from TypePreferences,
716 // use AwareInterface or specify the method requirement option METHOD_IS_EAGER at ClassDefinition
717 if ($methodRequirementType & self::RESOLVE_EAGER) {
718 if ($alias && $this->instanceManager->hasTypePreferences($alias)) {
719 $pInstances = $this->instanceManager->getTypePreferences($alias);
720 foreach ($pInstances as $pInstance) {
721 if (is_object($pInstance)) {
722 $computedParams['value'][$fqParamPos] = $pInstance;
723 continue 2;
725 $pInstanceClass = ($this->instanceManager->hasAlias($pInstance)) ?
726 $this->instanceManager->getClassFromAlias($pInstance) : $pInstance;
727 if ($pInstanceClass === $type || self::isSubclassOf($pInstanceClass, $type)) {
728 $computedParams['retrieval'][$fqParamPos] = array($pInstance, $pInstanceClass);
729 continue 2;
734 // next consult class level preferred instances
735 if ($type && $this->instanceManager->hasTypePreferences($type)) {
736 $pInstances = $this->instanceManager->getTypePreferences($type);
737 foreach ($pInstances as $pInstance) {
738 if (is_object($pInstance)) {
739 $computedParams['value'][$fqParamPos] = $pInstance;
740 continue 2;
742 $pInstanceClass = ($this->instanceManager->hasAlias($pInstance)) ?
743 $this->instanceManager->getClassFromAlias($pInstance) : $pInstance;
744 if ($pInstanceClass === $type || self::isSubclassOf($pInstanceClass, $type)) {
745 $computedParams['retrieval'][$fqParamPos] = array($pInstance, $pInstanceClass);
746 continue 2;
751 if (!$isRequired) {
752 $computedParams['optional'][$fqParamPos] = true;
755 if ($type && $isRequired && ($methodRequirementType & self::RESOLVE_EAGER)) {
756 $computedParams['retrieval'][$fqParamPos] = array($type, $type);
761 $index = 0;
762 foreach ($injectionMethodParameters as $fqParamPos => $value) {
763 $name = $value[0];
765 if (isset($computedParams['value'][$fqParamPos])) {
766 // if there is a value supplied, use it
767 $resolvedParams[$index] = $computedParams['value'][$fqParamPos];
768 } elseif (isset($computedParams['retrieval'][$fqParamPos])) {
769 // detect circular dependencies! (they can only happen in instantiators)
770 if ($isInstantiator && in_array($computedParams['retrieval'][$fqParamPos][1], $this->currentDependencies)) {
771 throw new Exception\CircularDependencyException(
772 "Circular dependency detected: $class depends on {$value[1]} and viceversa"
776 array_push($this->currentDependencies, $class);
777 $dConfig = $this->instanceManager->getConfig($computedParams['retrieval'][$fqParamPos][0]);
779 try {
780 if ($dConfig['shared'] === false) {
781 $resolvedParams[$index] = $this->newInstance($computedParams['retrieval'][$fqParamPos][0], $callTimeUserParams, false);
782 } else {
783 $resolvedParams[$index] = $this->get($computedParams['retrieval'][$fqParamPos][0], $callTimeUserParams);
785 } catch (DiRuntimeException $e) {
786 if ($methodRequirementType & self::RESOLVE_STRICT) {
787 //finally ( be aware to do at the end of flow)
788 array_pop($this->currentDependencies);
789 // if this item was marked strict,
790 // plus it cannot be resolve, and no value exist, bail out
791 throw new Exception\MissingPropertyException(sprintf(
792 'Missing %s for parameter ' . $name . ' for ' . $class . '::' . $method,
793 (($value[0] === null) ? 'value' : 'instance/object' )
795 $e->getCode(),
796 $e);
797 } else {
798 //finally ( be aware to do at the end of flow)
799 array_pop($this->currentDependencies);
800 return false;
802 } catch (ServiceManagerException $e) {
803 // Zend\ServiceManager\Exception\ServiceNotCreatedException
804 if ($methodRequirementType & self::RESOLVE_STRICT) {
805 //finally ( be aware to do at the end of flow)
806 array_pop($this->currentDependencies);
807 // if this item was marked strict,
808 // plus it cannot be resolve, and no value exist, bail out
809 throw new Exception\MissingPropertyException(sprintf(
810 'Missing %s for parameter ' . $name . ' for ' . $class . '::' . $method,
811 (($value[0] === null) ? 'value' : 'instance/object' )
813 $e->getCode(),
814 $e);
815 } else {
816 //finally ( be aware to do at the end of flow)
817 array_pop($this->currentDependencies);
818 return false;
821 array_pop($this->currentDependencies);
822 } elseif (!array_key_exists($fqParamPos, $computedParams['optional'])) {
823 if ($methodRequirementType & self::RESOLVE_STRICT) {
824 // if this item was not marked as optional,
825 // plus it cannot be resolve, and no value exist, bail out
826 throw new Exception\MissingPropertyException(sprintf(
827 'Missing %s for parameter ' . $name . ' for ' . $class . '::' . $method,
828 (($value[0] === null) ? 'value' : 'instance/object' )
830 } else {
831 return false;
833 } else {
834 $resolvedParams[$index] = $value[3];
837 $index++;
840 return $resolvedParams; // return ordered list of parameters
844 * Utility method used to retrieve the class of a particular instance. This is here to allow extending classes to
845 * override how class names are resolved
847 * @internal this method is used by the ServiceLocator\DependencyInjectorProxy class to interact with instances
848 * and is a hack to be used internally until a major refactor does not split the `resolveMethodParameters`. Do not
849 * rely on its functionality.
850 * @param Object $instance
851 * @return string
853 protected function getClass($instance)
855 return get_class($instance);
859 * Checks if the object has this class as one of its parents
861 * @see https://bugs.php.net/bug.php?id=53727
862 * @see https://github.com/zendframework/zf2/pull/1807
864 * @param string $className
865 * @param $type
866 * @return bool
868 protected static function isSubclassOf($className, $type)
870 if (is_subclass_of($className, $type)) {
871 return true;
873 if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
874 return false;
876 if (!interface_exists($type)) {
877 return false;
879 $r = new ReflectionClass($className);
881 return $r->implementsInterface($type);