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@0: $arguments = array(); Chris@0: Chris@0: if (is_array($controller)) { Chris@0: $reflection = new \ReflectionMethod($controller[0], $controller[1]); Chris@0: } 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@0: $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param), $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@0: * @return null|string Chris@0: */ Chris@0: private function getType(\ReflectionParameter $parameter) Chris@0: { Chris@0: if ($this->supportsParameterType) { Chris@0: if (!$type = $parameter->getType()) { Chris@0: return; Chris@0: } Chris@0: $typeName = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); Chris@0: if ('array' === $typeName && !$type->isBuiltin()) { Chris@0: // Special case for HHVM with variadics Chris@0: return; Chris@0: } Chris@0: Chris@0: return $typeName; Chris@0: } Chris@0: Chris@0: if (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $info)) { Chris@0: return $info[1]; Chris@0: } Chris@0: } Chris@0: }