5 * @link http://mnapoli.github.com/PHP-DI/
6 * @copyright Matthieu Napoli (http://mnapoli.fr/)
7 * @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
10 namespace DI\Definition\Resolver;
12 use DI\Definition\ObjectDefinition;
13 use DI\Definition\Exception\DefinitionException;
14 use DI\Definition\Helper\DefinitionHelper;
15 use DI\Definition\ObjectDefinition\MethodInjection;
18 * Resolves parameters for a function call.
21 * @author Matthieu Napoli <matthieu@mnapoli.fr>
23 class ParameterResolver
26 * @var DefinitionResolver
28 private $definitionResolver;
31 * @param DefinitionResolver $definitionResolver Will be used to resolve nested definitions.
33 public function __construct(DefinitionResolver $definitionResolver)
35 $this->definitionResolver = $definitionResolver;
39 * @param MethodInjection $definition
40 * @param \ReflectionFunctionAbstract $functionReflection
41 * @param array $parameters
43 * @throws DefinitionException A parameter has no value defined or guessable.
44 * @return array Parameters to use to call the function.
46 public function resolveParameters(
47 MethodInjection $definition = null,
48 \ReflectionFunctionAbstract $functionReflection = null,
49 array $parameters = []
53 if (! $functionReflection) {
57 $definitionParameters = $definition ? $definition->getParameters() : array();
59 foreach ($functionReflection->getParameters() as $index => $parameter) {
60 if (array_key_exists($parameter->getName(), $parameters)) {
61 // Look in the $parameters array
62 $value = &$parameters[$parameter->getName()];
63 } elseif (array_key_exists($index, $definitionParameters)) {
64 // Look in the definition
65 $value = &$definitionParameters[$index];
67 // If the parameter is optional and wasn't specified, we take its default value
68 if ($parameter->isOptional()) {
69 $args[] = $this->getParameterDefaultValue($parameter, $functionReflection);
73 throw new DefinitionException(sprintf(
74 "The parameter '%s' of %s has no value defined or guessable",
75 $parameter->getName(),
76 $this->getFunctionName($functionReflection)
80 if ($value instanceof DefinitionHelper) {
81 $nestedDefinition = $value->getDefinition('');
83 // If the container cannot produce the entry, we can use the default parameter value
84 if ($parameter->isOptional() && !$this->definitionResolver->isResolvable($nestedDefinition)) {
85 $value = $this->getParameterDefaultValue($parameter, $functionReflection);
87 $value = $this->definitionResolver->resolve($nestedDefinition);
98 * Returns the default value of a function parameter.
100 * @param \ReflectionParameter $parameter
101 * @param \ReflectionFunctionAbstract $function
103 * @throws DefinitionException Can't get default values from PHP internal classes and functions
106 private function getParameterDefaultValue(
107 \ReflectionParameter $parameter,
108 \ReflectionFunctionAbstract $function
111 return $parameter->getDefaultValue();
112 } catch (\ReflectionException $e) {
113 throw new DefinitionException(sprintf(
114 "The parameter '%s' of %s has no type defined or guessable. It has a default value, "
115 . "but the default value can't be read through Reflection because it is a PHP internal class.",
116 $parameter->getName(),
117 $this->getFunctionName($function)
122 private function getFunctionName(\ReflectionFunctionAbstract $reflectionFunction)
124 if ($reflectionFunction instanceof \ReflectionMethod) {
127 $reflectionFunction->getDeclaringClass()->getName(),
128 $reflectionFunction->getName()
130 } elseif ($reflectionFunction->isClosure()) {
132 'closure defined in %s at line %d',
133 $reflectionFunction->getFileName(),
134 $reflectionFunction->getStartLine()
138 return $reflectionFunction->getName();