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