Chris@0: scalars = $scalars; Chris@0: $this->objects = $objects; Chris@0: $this->wildcards = $wildcards; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getArguments(callable $callable) { Chris@0: $arguments = []; Chris@0: foreach ($this->getReflector($callable)->getParameters() as $parameter) { Chris@0: $arguments[] = $this->getArgument($parameter); Chris@0: } Chris@0: return $arguments; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the argument value for a parameter. Chris@0: * Chris@0: * @param \ReflectionParameter $parameter Chris@0: * The parameter of a callable to get the value for. Chris@0: * Chris@0: * @return mixed Chris@0: * The value of the requested parameter value. Chris@0: * Chris@0: * @throws \RuntimeException Chris@0: * Thrown when there is a missing parameter. Chris@0: */ Chris@0: protected function getArgument(\ReflectionParameter $parameter) { Chris@0: $parameter_type_hint = $parameter->getClass(); Chris@0: $parameter_name = $parameter->getName(); Chris@0: Chris@0: // If the argument exists and is NULL, return it, regardless of Chris@0: // parameter type hint. Chris@0: if (!isset($this->objects[$parameter_name]) && array_key_exists($parameter_name, $this->objects)) { Chris@0: return NULL; Chris@0: } Chris@0: Chris@0: if ($parameter_type_hint) { Chris@0: // If the argument exists and complies with the type hint, return it. Chris@0: if (isset($this->objects[$parameter_name]) && is_object($this->objects[$parameter_name]) && $parameter_type_hint->isInstance($this->objects[$parameter_name])) { Chris@0: return $this->objects[$parameter_name]; Chris@0: } Chris@0: // Otherwise, resolve wildcard arguments by type matching. Chris@0: foreach ($this->wildcards as $wildcard) { Chris@0: if ($parameter_type_hint->isInstance($wildcard)) { Chris@0: return $wildcard; Chris@0: } Chris@0: } Chris@0: } Chris@0: elseif (isset($this->scalars[$parameter_name])) { Chris@0: return $this->scalars[$parameter_name]; Chris@0: } Chris@0: Chris@0: // If the callable provides a default value, use it. Chris@0: if ($parameter->isDefaultValueAvailable()) { Chris@0: return $parameter->getDefaultValue(); Chris@0: } Chris@0: Chris@0: // Can't resolve it: call a method that throws an exception or can be Chris@0: // overridden to do something else. Chris@0: return $this->handleUnresolvedArgument($parameter); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets a reflector for the access check callable. Chris@0: * Chris@0: * The access checker may be either a procedural function (in which case the Chris@0: * callable is the function name) or a method (in which case the callable is Chris@0: * an array of the object and method name). Chris@0: * Chris@0: * @param callable $callable Chris@0: * The callable (either a function or a method). Chris@0: * Chris@0: * @return \ReflectionFunctionAbstract Chris@0: * The ReflectionMethod or ReflectionFunction to introspect the callable. Chris@0: */ Chris@0: protected function getReflector(callable $callable) { Chris@0: return is_array($callable) ? new \ReflectionMethod($callable[0], $callable[1]) : new \ReflectionFunction($callable); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Handles unresolved arguments for getArgument(). Chris@0: * Chris@0: * Subclasses that override this method may return a default value Chris@0: * instead of throwing an exception. Chris@0: * Chris@0: * @throws \RuntimeException Chris@0: * Thrown when there is a missing parameter. Chris@0: */ Chris@0: protected function handleUnresolvedArgument(\ReflectionParameter $parameter) { Chris@0: $class = $parameter->getDeclaringClass(); Chris@0: $function = $parameter->getDeclaringFunction(); Chris@0: if ($class && !$function->isClosure()) { Chris@0: $function_name = $class->getName() . '::' . $function->getName(); Chris@0: } Chris@0: else { Chris@0: $function_name = $function->getName(); Chris@0: } Chris@0: throw new \RuntimeException(sprintf('Callable "%s" requires a value for the "$%s" argument.', $function_name, $parameter->getName())); Chris@0: } Chris@0: Chris@0: }