Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / psy / psysh / src / Formatter / SignatureFormatter.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2018 Justin Hileman
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Psy\Formatter;
13
14 use Psy\Reflection\ReflectionClassConstant;
15 use Psy\Reflection\ReflectionConstant_;
16 use Psy\Reflection\ReflectionLanguageConstruct;
17 use Psy\Util\Json;
18 use Symfony\Component\Console\Formatter\OutputFormatter;
19
20 /**
21  * An abstract representation of a function, class or property signature.
22  */
23 class SignatureFormatter implements Formatter
24 {
25     /**
26      * Format a signature for the given reflector.
27      *
28      * Defers to subclasses to do the actual formatting.
29      *
30      * @param \Reflector $reflector
31      *
32      * @return string Formatted signature
33      */
34     public static function format(\Reflector $reflector)
35     {
36         switch (true) {
37             case $reflector instanceof \ReflectionFunction:
38             case $reflector instanceof ReflectionLanguageConstruct:
39                 return self::formatFunction($reflector);
40
41             // this case also covers \ReflectionObject:
42             case $reflector instanceof \ReflectionClass:
43                 return self::formatClass($reflector);
44
45             case $reflector instanceof ReflectionClassConstant:
46             case $reflector instanceof \ReflectionClassConstant:
47                 return self::formatClassConstant($reflector);
48
49             case $reflector instanceof \ReflectionMethod:
50                 return self::formatMethod($reflector);
51
52             case $reflector instanceof \ReflectionProperty:
53                 return self::formatProperty($reflector);
54
55             case $reflector instanceof ReflectionConstant_:
56                 return self::formatConstant($reflector);
57
58             default:
59                 throw new \InvalidArgumentException('Unexpected Reflector class: ' . \get_class($reflector));
60         }
61     }
62
63     /**
64      * Print the signature name.
65      *
66      * @param \Reflector $reflector
67      *
68      * @return string Formatted name
69      */
70     public static function formatName(\Reflector $reflector)
71     {
72         return $reflector->getName();
73     }
74
75     /**
76      * Print the method, property or class modifiers.
77      *
78      * @param \Reflector $reflector
79      *
80      * @return string Formatted modifiers
81      */
82     private static function formatModifiers(\Reflector $reflector)
83     {
84         if ($reflector instanceof \ReflectionClass && $reflector->isTrait()) {
85             // For some reason, PHP 5.x returns `abstract public` modifiers for
86             // traits. Let's just ignore that business entirely.
87             if (\version_compare(PHP_VERSION, '7.0.0', '<')) {
88                 return [];
89             }
90         }
91
92         return \implode(' ', \array_map(function ($modifier) {
93             return \sprintf('<keyword>%s</keyword>', $modifier);
94         }, \Reflection::getModifierNames($reflector->getModifiers())));
95     }
96
97     /**
98      * Format a class signature.
99      *
100      * @param \ReflectionClass $reflector
101      *
102      * @return string Formatted signature
103      */
104     private static function formatClass(\ReflectionClass $reflector)
105     {
106         $chunks = [];
107
108         if ($modifiers = self::formatModifiers($reflector)) {
109             $chunks[] = $modifiers;
110         }
111
112         if ($reflector->isTrait()) {
113             $chunks[] = 'trait';
114         } else {
115             $chunks[] = $reflector->isInterface() ? 'interface' : 'class';
116         }
117
118         $chunks[] = \sprintf('<class>%s</class>', self::formatName($reflector));
119
120         if ($parent = $reflector->getParentClass()) {
121             $chunks[] = 'extends';
122             $chunks[] = \sprintf('<class>%s</class>', $parent->getName());
123         }
124
125         $interfaces = $reflector->getInterfaceNames();
126         if (!empty($interfaces)) {
127             \sort($interfaces);
128
129             $chunks[] = 'implements';
130             $chunks[] = \implode(', ', \array_map(function ($name) {
131                 return \sprintf('<class>%s</class>', $name);
132             }, $interfaces));
133         }
134
135         return \implode(' ', $chunks);
136     }
137
138     /**
139      * Format a constant signature.
140      *
141      * @param ReflectionClassConstant|\ReflectionClassConstant $reflector
142      *
143      * @return string Formatted signature
144      */
145     private static function formatClassConstant($reflector)
146     {
147         $value = $reflector->getValue();
148         $style = self::getTypeStyle($value);
149
150         return \sprintf(
151             '<keyword>const</keyword> <const>%s</const> = <%s>%s</%s>',
152             self::formatName($reflector),
153             $style,
154             OutputFormatter::escape(Json::encode($value)),
155             $style
156         );
157     }
158
159     /**
160      * Format a constant signature.
161      *
162      * @param ReflectionConstant_ $reflector
163      *
164      * @return string Formatted signature
165      */
166     private static function formatConstant($reflector)
167     {
168         $value = $reflector->getValue();
169         $style = self::getTypeStyle($value);
170
171         return \sprintf(
172             '<keyword>define</keyword>(<string>%s</string>, <%s>%s</%s>)',
173             OutputFormatter::escape(Json::encode($reflector->getName())),
174             $style,
175             OutputFormatter::escape(Json::encode($value)),
176             $style
177         );
178     }
179
180     /**
181      * Helper for getting output style for a given value's type.
182      *
183      * @param mixed $value
184      *
185      * @return string
186      */
187     private static function getTypeStyle($value)
188     {
189         if (\is_int($value) || \is_float($value)) {
190             return 'number';
191         } elseif (\is_string($value)) {
192             return 'string';
193         } elseif (\is_bool($value) || \is_null($value)) {
194             return 'bool';
195         } else {
196             return 'strong'; // @codeCoverageIgnore
197         }
198     }
199
200     /**
201      * Format a property signature.
202      *
203      * @param \ReflectionProperty $reflector
204      *
205      * @return string Formatted signature
206      */
207     private static function formatProperty(\ReflectionProperty $reflector)
208     {
209         return \sprintf(
210             '%s <strong>$%s</strong>',
211             self::formatModifiers($reflector),
212             $reflector->getName()
213         );
214     }
215
216     /**
217      * Format a function signature.
218      *
219      * @param \ReflectionFunction $reflector
220      *
221      * @return string Formatted signature
222      */
223     private static function formatFunction(\ReflectionFunctionAbstract $reflector)
224     {
225         return \sprintf(
226             '<keyword>function</keyword> %s<function>%s</function>(%s)',
227             $reflector->returnsReference() ? '&' : '',
228             self::formatName($reflector),
229             \implode(', ', self::formatFunctionParams($reflector))
230         );
231     }
232
233     /**
234      * Format a method signature.
235      *
236      * @param \ReflectionMethod $reflector
237      *
238      * @return string Formatted signature
239      */
240     private static function formatMethod(\ReflectionMethod $reflector)
241     {
242         return \sprintf(
243             '%s %s',
244             self::formatModifiers($reflector),
245             self::formatFunction($reflector)
246         );
247     }
248
249     /**
250      * Print the function params.
251      *
252      * @param \ReflectionFunctionAbstract $reflector
253      *
254      * @return array
255      */
256     private static function formatFunctionParams(\ReflectionFunctionAbstract $reflector)
257     {
258         $params = [];
259         foreach ($reflector->getParameters() as $param) {
260             $hint = '';
261             try {
262                 if ($param->isArray()) {
263                     $hint = '<keyword>array</keyword> ';
264                 } elseif ($class = $param->getClass()) {
265                     $hint = \sprintf('<class>%s</class> ', $class->getName());
266                 }
267             } catch (\Exception $e) {
268                 // sometimes we just don't know...
269                 // bad class names, or autoloaded classes that haven't been loaded yet, or whathaveyou.
270                 // come to think of it, the only time I've seen this is with the intl extension.
271
272                 // Hax: we'll try to extract it :P
273
274                 // @codeCoverageIgnoreStart
275                 $chunks = \explode('$' . $param->getName(), (string) $param);
276                 $chunks = \explode(' ', \trim($chunks[0]));
277                 $guess  = \end($chunks);
278
279                 $hint = \sprintf('<urgent>%s</urgent> ', $guess);
280                 // @codeCoverageIgnoreEnd
281             }
282
283             if ($param->isOptional()) {
284                 if (!$param->isDefaultValueAvailable()) {
285                     $value     = 'unknown';
286                     $typeStyle = 'urgent';
287                 } else {
288                     $value     = $param->getDefaultValue();
289                     $typeStyle = self::getTypeStyle($value);
290                     $value     = \is_array($value) ? 'array()' : \is_null($value) ? 'null' : \var_export($value, true);
291                 }
292                 $default = \sprintf(' = <%s>%s</%s>', $typeStyle, OutputFormatter::escape($value), $typeStyle);
293             } else {
294                 $default = '';
295             }
296
297             $params[] = \sprintf(
298                 '%s%s<strong>$%s</strong>%s',
299                 $param->isPassedByReference() ? '&' : '',
300                 $hint,
301                 $param->getName(),
302                 $default
303             );
304         }
305
306         return $params;
307     }
308 }