Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\HttpKernel\ControllerMetadata; Chris@0: Chris@0: /** Chris@0: * Builds {@see ArgumentMetadata} objects based on the given Controller. Chris@0: * Chris@0: * @author Iltar van der Berg Chris@0: */ Chris@0: final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface Chris@0: { Chris@0: /** Chris@0: * If the ...$arg functionality is available. Chris@0: * Chris@0: * Requires at least PHP 5.6.0 or HHVM 3.9.1 Chris@0: * Chris@0: * @var bool Chris@0: */ Chris@0: private $supportsVariadic; Chris@0: Chris@0: /** Chris@0: * If the reflection supports the getType() method to resolve types. Chris@0: * Chris@0: * Requires at least PHP 7.0.0 or HHVM 3.11.0 Chris@0: * Chris@0: * @var bool Chris@0: */ Chris@0: private $supportsParameterType; Chris@0: Chris@0: public function __construct() Chris@0: { Chris@0: $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic'); Chris@0: $this->supportsParameterType = method_exists('ReflectionParameter', 'getType'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function createArgumentMetadata($controller) Chris@0: { Chris@17: $arguments = []; Chris@0: Chris@17: if (\is_array($controller)) { Chris@0: $reflection = new \ReflectionMethod($controller[0], $controller[1]); Chris@17: } elseif (\is_object($controller) && !$controller instanceof \Closure) { Chris@0: $reflection = (new \ReflectionObject($controller))->getMethod('__invoke'); Chris@0: } else { Chris@0: $reflection = new \ReflectionFunction($controller); Chris@0: } Chris@0: Chris@0: foreach ($reflection->getParameters() as $param) { Chris@16: $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $this->isVariadic($param), $this->hasDefaultValue($param), $this->getDefaultValue($param), $param->allowsNull()); Chris@0: } Chris@0: Chris@0: return $arguments; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns whether an argument is variadic. Chris@0: * Chris@0: * @param \ReflectionParameter $parameter Chris@0: * Chris@0: * @return bool Chris@0: */ Chris@0: private function isVariadic(\ReflectionParameter $parameter) Chris@0: { Chris@0: return $this->supportsVariadic && $parameter->isVariadic(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines whether an argument has a default value. Chris@0: * Chris@0: * @param \ReflectionParameter $parameter Chris@0: * Chris@0: * @return bool Chris@0: */ Chris@0: private function hasDefaultValue(\ReflectionParameter $parameter) Chris@0: { Chris@0: return $parameter->isDefaultValueAvailable(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns a default value if available. Chris@0: * Chris@0: * @param \ReflectionParameter $parameter Chris@0: * Chris@0: * @return mixed|null Chris@0: */ Chris@0: private function getDefaultValue(\ReflectionParameter $parameter) Chris@0: { Chris@0: return $this->hasDefaultValue($parameter) ? $parameter->getDefaultValue() : null; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns an associated type to the given parameter if available. Chris@0: * Chris@0: * @param \ReflectionParameter $parameter Chris@0: * Chris@17: * @return string|null Chris@0: */ Chris@16: private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function) Chris@0: { Chris@0: if ($this->supportsParameterType) { Chris@0: if (!$type = $parameter->getType()) { Chris@0: return; Chris@0: } Chris@16: $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); Chris@16: if ('array' === $name && !$type->isBuiltin()) { Chris@0: // Special case for HHVM with variadics Chris@0: return; Chris@0: } Chris@16: } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $name)) { Chris@16: $name = $name[1]; Chris@16: } else { Chris@16: return; Chris@16: } Chris@16: $lcName = strtolower($name); Chris@0: Chris@16: if ('self' !== $lcName && 'parent' !== $lcName) { Chris@16: return $name; Chris@0: } Chris@16: if (!$function instanceof \ReflectionMethod) { Chris@16: return; Chris@16: } Chris@16: if ('self' === $lcName) { Chris@16: return $function->getDeclaringClass()->name; Chris@16: } Chris@16: if ($parent = $function->getDeclaringClass()->getParentClass()) { Chris@16: return $parent->name; Chris@0: } Chris@0: } Chris@0: }