getName();
}
/**
* Print the method, property or class modifiers.
*
* @param \ReflectionMethod|\ReflectionProperty|\ReflectionClass $reflector
*
* @return string Formatted modifiers
*/
private static function formatModifiers(\Reflector $reflector): string
{
return \implode(' ', \array_map(function ($modifier) {
return \sprintf('%s', $modifier);
}, \Reflection::getModifierNames($reflector->getModifiers())));
}
/**
* Format a class signature.
*
* @param \ReflectionClass $reflector
*
* @return string Formatted signature
*/
private static function formatClass(\ReflectionClass $reflector): string
{
$chunks = [];
if ($modifiers = self::formatModifiers($reflector)) {
$chunks[] = $modifiers;
}
if ($reflector->isTrait()) {
$chunks[] = 'trait';
} else {
$chunks[] = $reflector->isInterface() ? 'interface' : 'class';
}
$chunks[] = \sprintf('%s', self::formatName($reflector));
if ($parent = $reflector->getParentClass()) {
$chunks[] = 'extends';
$chunks[] = \sprintf('%s', $parent->getName());
}
$interfaces = $reflector->getInterfaceNames();
if (!empty($interfaces)) {
\sort($interfaces);
$chunks[] = $reflector->isInterface() ? 'extends' : 'implements';
$chunks[] = \implode(', ', \array_map(function ($name) {
return \sprintf('%s', $name);
}, $interfaces));
}
return \implode(' ', $chunks);
}
/**
* Format a constant signature.
*
* @param ReflectionClassConstant|\ReflectionClassConstant $reflector
*
* @return string Formatted signature
*/
private static function formatClassConstant($reflector): string
{
$value = $reflector->getValue();
$style = self::getTypeStyle($value);
return \sprintf(
'const %s = <%s>%s%s>',
self::formatName($reflector),
$style,
OutputFormatter::escape(Json::encode($value)),
$style
);
}
/**
* Format a constant signature.
*
* @param ReflectionConstant_ $reflector
*
* @return string Formatted signature
*/
private static function formatConstant(ReflectionConstant_ $reflector): string
{
$value = $reflector->getValue();
$style = self::getTypeStyle($value);
return \sprintf(
'define(%s, <%s>%s%s>)',
OutputFormatter::escape(Json::encode($reflector->getName())),
$style,
OutputFormatter::escape(Json::encode($value)),
$style
);
}
/**
* Helper for getting output style for a given value's type.
*
* @param mixed $value
*/
private static function getTypeStyle($value): string
{
if (\is_int($value) || \is_float($value)) {
return 'number';
} elseif (\is_string($value)) {
return 'string';
} elseif (\is_bool($value) || $value === null) {
return 'bool';
} else {
return 'strong'; // @codeCoverageIgnore
}
}
/**
* Format a property signature.
*
* @param \ReflectionProperty $reflector
*
* @return string Formatted signature
*/
private static function formatProperty(\ReflectionProperty $reflector): string
{
return \sprintf(
'%s $%s',
self::formatModifiers($reflector),
$reflector->getName()
);
}
/**
* Format a function signature.
*
* @param \ReflectionFunction $reflector
*
* @return string Formatted signature
*/
private static function formatFunction(\ReflectionFunctionAbstract $reflector): string
{
return \sprintf(
'function %s%s(%s)%s',
$reflector->returnsReference() ? '&' : '',
self::formatName($reflector),
\implode(', ', self::formatFunctionParams($reflector)),
self::formatFunctionReturnType($reflector)
);
}
/**
* Format a function signature's return type (if available).
*
* @param \ReflectionFunctionAbstract $reflector
*
* @return string Formatted return type
*/
private static function formatFunctionReturnType(\ReflectionFunctionAbstract $reflector): string
{
if (!\method_exists($reflector, 'hasReturnType') || !$reflector->hasReturnType()) {
return '';
}
return \sprintf(': %s', self::formatReflectionType($reflector->getReturnType()));
}
/**
* Format a method signature.
*
* @param \ReflectionMethod $reflector
*
* @return string Formatted signature
*/
private static function formatMethod(\ReflectionMethod $reflector): string
{
return \sprintf(
'%s %s',
self::formatModifiers($reflector),
self::formatFunction($reflector)
);
}
/**
* Print the function params.
*
* @param \ReflectionFunctionAbstract $reflector
*
* @return array
*/
private static function formatFunctionParams(\ReflectionFunctionAbstract $reflector): array
{
$params = [];
foreach ($reflector->getParameters() as $param) {
$hint = '';
try {
if (\method_exists($param, 'getType')) {
$hint = self::formatReflectionType($param->getType());
} else {
if ($param->isArray()) {
$hint = 'array';
} elseif ($class = $param->getClass()) {
$hint = \sprintf('%s', $class->getName());
}
}
} catch (\Throwable $e) {
// sometimes we just don't know...
// bad class names, or autoloaded classes that haven't been loaded yet, or whathaveyou.
// come to think of it, the only time I've seen this is with the intl extension.
// Hax: we'll try to extract it :P
// @codeCoverageIgnoreStart
$chunks = \explode('$'.$param->getName(), (string) $param);
$chunks = \explode(' ', \trim($chunks[0]));
$guess = \end($chunks);
$hint = \sprintf('%s', OutputFormatter::escape($guess));
// @codeCoverageIgnoreEnd
}
if ($param->isOptional()) {
if (!$param->isDefaultValueAvailable()) {
$value = 'unknown';
$typeStyle = 'urgent';
} else {
$value = $param->getDefaultValue();
$typeStyle = self::getTypeStyle($value);
$value = \is_array($value) ? '[]' : ($value === null ? 'null' : \var_export($value, true));
}
$default = \sprintf(' = <%s>%s%s>', $typeStyle, OutputFormatter::escape($value), $typeStyle);
} else {
$default = '';
}
$params[] = \sprintf(
'%s%s%s$%s%s',
$param->isPassedByReference() ? '&' : '',
$hint,
$hint !== '' ? ' ' : '',
$param->getName(),
$default
);
}
return $params;
}
/**
* Print function param or return type(s).
*
* @param \ReflectionType $type
*/
private static function formatReflectionType(\ReflectionType $type = null): string
{
if ($type === null) {
return '';
}
$types = $type instanceof \ReflectionUnionType ? $type->getTypes() : [$type];
$formattedTypes = [];
foreach ($types as $type) {
$typeStyle = $type->isBuiltin() ? 'keyword' : 'class';
// PHP 7.0 didn't have `getName` on reflection types, so wheee!
$typeName = \method_exists($type, 'getName') ? $type->getName() : (string) $type;
// @todo Do we want to include the ? for nullable types? Maybe only sometimes?
$formattedTypes[] = \sprintf('<%s>%s%s>', $typeStyle, OutputFormatter::escape($typeName), $typeStyle);
}
return \implode('|', $formattedTypes);
}
}