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\VarDumper\Caster; Chris@0: Chris@0: use Symfony\Component\VarDumper\Cloner\Stub; Chris@0: Chris@0: /** Chris@0: * Casts Reflector related classes to array representation. Chris@0: * Chris@0: * @author Nicolas Grekas Chris@0: */ Chris@0: class ReflectionCaster Chris@0: { Chris@17: private static $extraMap = [ Chris@0: 'docComment' => 'getDocComment', Chris@0: 'extension' => 'getExtensionName', Chris@0: 'isDisabled' => 'isDisabled', Chris@0: 'isDeprecated' => 'isDeprecated', Chris@0: 'isInternal' => 'isInternal', Chris@0: 'isUserDefined' => 'isUserDefined', Chris@0: 'isGenerator' => 'isGenerator', Chris@0: 'isVariadic' => 'isVariadic', Chris@17: ]; Chris@0: Chris@0: public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, $filter = 0) Chris@0: { Chris@0: $prefix = Caster::PREFIX_VIRTUAL; Chris@0: $c = new \ReflectionFunction($c); Chris@0: Chris@0: $stub->class = 'Closure'; // HHVM generates unique class names for closures Chris@0: $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter); Chris@0: Chris@17: if (false === strpos($c->name, '{closure}')) { Chris@17: $stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name; Chris@17: unset($a[$prefix.'class']); Chris@17: } Chris@17: Chris@0: if (isset($a[$prefix.'parameters'])) { Chris@0: foreach ($a[$prefix.'parameters']->value as &$v) { Chris@0: $param = $v; Chris@17: $v = new EnumStub([]); Chris@17: foreach (static::castParameter($param, [], $stub, true) as $k => $param) { Chris@0: if ("\0" === $k[0]) { Chris@0: $v->value[substr($k, 3)] = $param; Chris@0: } Chris@0: } Chris@0: unset($v->value['position'], $v->value['isVariadic'], $v->value['byReference'], $v); Chris@0: } Chris@0: } Chris@0: Chris@0: if (!($filter & Caster::EXCLUDE_VERBOSE) && $f = $c->getFileName()) { Chris@0: $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); Chris@0: $a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine(); Chris@0: } Chris@0: Chris@0: $prefix = Caster::PREFIX_DYNAMIC; Chris@0: unset($a['name'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']); Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@0: if (!class_exists('ReflectionGenerator', false)) { Chris@0: return $a; Chris@0: } Chris@0: Chris@0: // Cannot create ReflectionGenerator based on a terminated Generator Chris@0: try { Chris@0: $reflectionGenerator = new \ReflectionGenerator($c); Chris@0: } catch (\Exception $e) { Chris@0: $a[Caster::PREFIX_VIRTUAL.'closed'] = true; Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); Chris@0: } Chris@0: Chris@0: public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@0: $prefix = Caster::PREFIX_VIRTUAL; Chris@0: Chris@17: $a += [ Chris@0: $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : $c->__toString(), Chris@0: $prefix.'allowsNull' => $c->allowsNull(), Chris@0: $prefix.'isBuiltin' => $c->isBuiltin(), Chris@17: ]; Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@0: $prefix = Caster::PREFIX_VIRTUAL; Chris@0: Chris@0: if ($c->getThis()) { Chris@0: $a[$prefix.'this'] = new CutStub($c->getThis()); Chris@0: } Chris@0: $function = $c->getFunction(); Chris@17: $frame = [ Chris@0: 'class' => isset($function->class) ? $function->class : null, Chris@0: 'type' => isset($function->class) ? ($function->isStatic() ? '::' : '->') : null, Chris@0: 'function' => $function->name, Chris@0: 'file' => $c->getExecutingFile(), Chris@0: 'line' => $c->getExecutingLine(), Chris@17: ]; Chris@0: if ($trace = $c->getTrace(DEBUG_BACKTRACE_IGNORE_ARGS)) { Chris@0: $function = new \ReflectionGenerator($c->getExecutingGenerator()); Chris@17: array_unshift($trace, [ Chris@0: 'function' => 'yield', Chris@0: 'file' => $function->getExecutingFile(), Chris@0: 'line' => $function->getExecutingLine() - 1, Chris@17: ]); Chris@0: $trace[] = $frame; Chris@0: $a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1); Chris@0: } else { Chris@0: $function = new FrameStub($frame, false, true); Chris@17: $function = ExceptionCaster::castFrameStub($function, [], $function, true); Chris@17: $a[$prefix.'executing'] = new EnumStub([ Chris@12: "\0~separator= \0".$frame['class'].$frame['type'].$frame['function'].'()' => $function[$prefix.'src'], Chris@17: ]); Chris@0: } Chris@0: Chris@0: $a[Caster::PREFIX_VIRTUAL.'closed'] = false; Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castClass(\ReflectionClass $c, array $a, Stub $stub, $isNested, $filter = 0) Chris@0: { Chris@0: $prefix = Caster::PREFIX_VIRTUAL; Chris@0: Chris@0: if ($n = \Reflection::getModifierNames($c->getModifiers())) { Chris@0: $a[$prefix.'modifiers'] = implode(' ', $n); Chris@0: } Chris@0: Chris@17: self::addMap($a, $c, [ Chris@0: 'extends' => 'getParentClass', Chris@0: 'implements' => 'getInterfaceNames', Chris@0: 'constants' => 'getConstants', Chris@17: ]); Chris@0: Chris@0: foreach ($c->getProperties() as $n) { Chris@0: $a[$prefix.'properties'][$n->name] = $n; Chris@0: } Chris@0: Chris@0: foreach ($c->getMethods() as $n) { Chris@0: $a[$prefix.'methods'][$n->name] = $n; Chris@0: } Chris@0: Chris@0: if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { Chris@0: self::addExtra($a, $c); Chris@0: } Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, $isNested, $filter = 0) Chris@0: { Chris@0: $prefix = Caster::PREFIX_VIRTUAL; Chris@0: Chris@17: self::addMap($a, $c, [ Chris@0: 'returnsReference' => 'returnsReference', Chris@0: 'returnType' => 'getReturnType', Chris@0: 'class' => 'getClosureScopeClass', Chris@0: 'this' => 'getClosureThis', Chris@17: ]); Chris@0: Chris@0: if (isset($a[$prefix.'returnType'])) { Chris@0: $v = $a[$prefix.'returnType']; Chris@0: $v = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); Chris@17: $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType']->allowsNull() ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); Chris@0: } Chris@0: if (isset($a[$prefix.'class'])) { Chris@0: $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); Chris@0: } Chris@0: if (isset($a[$prefix.'this'])) { Chris@0: $a[$prefix.'this'] = new CutStub($a[$prefix.'this']); Chris@0: } Chris@0: Chris@0: foreach ($c->getParameters() as $v) { Chris@0: $k = '$'.$v->name; Chris@0: if (method_exists($v, 'isVariadic') && $v->isVariadic()) { Chris@0: $k = '...'.$k; Chris@0: } Chris@0: if ($v->isPassedByReference()) { Chris@0: $k = '&'.$k; Chris@0: } Chris@0: $a[$prefix.'parameters'][$k] = $v; Chris@0: } Chris@0: if (isset($a[$prefix.'parameters'])) { Chris@0: $a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']); Chris@0: } Chris@0: Chris@0: if ($v = $c->getStaticVariables()) { Chris@0: foreach ($v as $k => &$v) { Chris@17: if (\is_object($v)) { Chris@0: $a[$prefix.'use']['$'.$k] = new CutStub($v); Chris@0: } else { Chris@0: $a[$prefix.'use']['$'.$k] = &$v; Chris@0: } Chris@0: } Chris@0: unset($v); Chris@0: $a[$prefix.'use'] = new EnumStub($a[$prefix.'use']); Chris@0: } Chris@0: Chris@0: if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { Chris@0: self::addExtra($a, $c); Chris@0: } Chris@0: Chris@0: // Added by HHVM Chris@0: unset($a[Caster::PREFIX_DYNAMIC.'static']); Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@0: $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@0: $prefix = Caster::PREFIX_VIRTUAL; Chris@0: Chris@0: // Added by HHVM Chris@0: unset($a['info']); Chris@0: Chris@17: self::addMap($a, $c, [ Chris@0: 'position' => 'getPosition', Chris@0: 'isVariadic' => 'isVariadic', Chris@0: 'byReference' => 'isPassedByReference', Chris@0: 'allowsNull' => 'allowsNull', Chris@17: ]); Chris@0: Chris@0: if (method_exists($c, 'getType')) { Chris@0: if ($v = $c->getType()) { Chris@0: $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); Chris@0: } Chris@0: } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $c, $v)) { Chris@0: $a[$prefix.'typeHint'] = $v[1]; Chris@0: } Chris@0: Chris@0: if (isset($a[$prefix.'typeHint'])) { Chris@0: $v = $a[$prefix.'typeHint']; Chris@17: $a[$prefix.'typeHint'] = new ClassStub($v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); Chris@0: } else { Chris@0: unset($a[$prefix.'allowsNull']); Chris@0: } Chris@0: Chris@0: try { Chris@0: $a[$prefix.'default'] = $v = $c->getDefaultValue(); Chris@0: if (method_exists($c, 'isDefaultValueConstant') && $c->isDefaultValueConstant()) { Chris@0: $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); Chris@0: } Chris@0: if (null === $v) { Chris@0: unset($a[$prefix.'allowsNull']); Chris@0: } Chris@0: } catch (\ReflectionException $e) { Chris@0: if (isset($a[$prefix.'typeHint']) && $c->allowsNull() && !class_exists('ReflectionNamedType', false)) { Chris@0: $a[$prefix.'default'] = null; Chris@0: unset($a[$prefix.'allowsNull']); Chris@0: } Chris@0: } Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@0: $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); Chris@0: self::addExtra($a, $c); Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@17: self::addMap($a, $c, [ Chris@0: 'version' => 'getVersion', Chris@0: 'dependencies' => 'getDependencies', Chris@0: 'iniEntries' => 'getIniEntries', Chris@0: 'isPersistent' => 'isPersistent', Chris@0: 'isTemporary' => 'isTemporary', Chris@0: 'constants' => 'getConstants', Chris@0: 'functions' => 'getFunctions', Chris@0: 'classes' => 'getClasses', Chris@17: ]); Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested) Chris@0: { Chris@17: self::addMap($a, $c, [ Chris@0: 'version' => 'getVersion', Chris@0: 'author' => 'getAuthor', Chris@0: 'copyright' => 'getCopyright', Chris@0: 'url' => 'getURL', Chris@17: ]); Chris@0: Chris@0: return $a; Chris@0: } Chris@0: Chris@0: private static function addExtra(&$a, \Reflector $c) Chris@0: { Chris@17: $x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : []; Chris@0: Chris@0: if (method_exists($c, 'getFileName') && $m = $c->getFileName()) { Chris@0: $x['file'] = new LinkStub($m, $c->getStartLine()); Chris@0: $x['line'] = $c->getStartLine().' to '.$c->getEndLine(); Chris@0: } Chris@0: Chris@0: self::addMap($x, $c, self::$extraMap, ''); Chris@0: Chris@0: if ($x) { Chris@0: $a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x); Chris@0: } Chris@0: } Chris@0: Chris@0: private static function addMap(&$a, \Reflector $c, $map, $prefix = Caster::PREFIX_VIRTUAL) Chris@0: { Chris@0: foreach ($map as $k => $m) { Chris@0: if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) { Chris@0: $a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m; Chris@0: } Chris@0: } Chris@0: } Chris@0: }