Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.86% |
522 / 528 |
|
33.33% |
2 / 6 |
CRAP | |
0.00% |
0 / 1 |
FileScanner | |
98.86% |
522 / 528 |
|
33.33% |
2 / 6 |
18 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
findInFiles | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
find | |
100.00% |
23 / 23 |
|
100.00% |
1 / 1 |
6 | |||
addDiscoveredClassChange | |
66.67% |
4 / 6 |
|
0.00% |
0 / 1 |
3.33 | |||
addDiscoveredNamespaceChange | |
60.00% |
3 / 5 |
|
0.00% |
0 / 1 |
3.58 | |||
getBuiltIns | |
99.79% |
481 / 482 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * The purpose of this class is only to find changes that should be made. |
4 | * i.e. classes and namespaces to change. |
5 | * Those recorded are updated in a later step. |
6 | */ |
7 | |
8 | namespace BrianHenryIE\Strauss; |
9 | |
10 | use BrianHenryIE\Strauss\Composer\Extra\StraussConfig; |
11 | use BrianHenryIE\Strauss\Types\ClassSymbol; |
12 | use BrianHenryIE\Strauss\Types\ConstantSymbol; |
13 | use BrianHenryIE\Strauss\Types\NamespaceSymbol; |
14 | |
15 | class FileScanner |
16 | { |
17 | |
18 | protected string $namespacePrefix; |
19 | protected string $classmapPrefix; |
20 | |
21 | /** @var string[] */ |
22 | protected array $excludeNamespacesFromPrefixing = array(); |
23 | |
24 | /** @var string[] */ |
25 | protected array $excludeFilePatternsFromPrefixing = array(); |
26 | |
27 | /** @var string[] */ |
28 | protected array $namespaceReplacementPatterns = array(); |
29 | |
30 | protected DiscoveredSymbols $discoveredSymbols; |
31 | |
32 | /** |
33 | * @var string[] |
34 | */ |
35 | protected array $excludePackagesFromPrefixing; |
36 | |
37 | /** |
38 | * FileScanner constructor. |
39 | * @param \BrianHenryIE\Strauss\Composer\Extra\StraussConfig $config |
40 | */ |
41 | public function __construct(StraussConfig $config) |
42 | { |
43 | $this->discoveredSymbols = new DiscoveredSymbols(); |
44 | |
45 | $this->namespacePrefix = $config->getNamespacePrefix(); |
46 | $this->classmapPrefix = $config->getClassmapPrefix(); |
47 | |
48 | $this->excludePackagesFromPrefixing = $config->getExcludePackagesFromPrefixing(); |
49 | $this->excludeNamespacesFromPrefixing = $config->getExcludeNamespacesFromPrefixing(); |
50 | $this->excludeFilePatternsFromPrefixing = $config->getExcludeFilePatternsFromPrefixing(); |
51 | |
52 | $this->namespaceReplacementPatterns = $config->getNamespaceReplacementPatterns(); |
53 | } |
54 | |
55 | /** |
56 | * @param DiscoveredFiles $files |
57 | */ |
58 | public function findInFiles(DiscoveredFiles $files): DiscoveredSymbols |
59 | { |
60 | foreach ($files->getFiles() as $file) { |
61 | if (!$file->isPhpFile()) { |
62 | continue; |
63 | } |
64 | |
65 | $this->find($file->getContents(), $file); |
66 | } |
67 | |
68 | return $this->discoveredSymbols; |
69 | } |
70 | |
71 | |
72 | /** |
73 | * TODO: Don't use preg_replace_callback! |
74 | * |
75 | * @uses self::addDiscoveredNamespaceChange() |
76 | * @uses self::addDiscoveredClassChange() |
77 | * |
78 | * @param string $contents |
79 | */ |
80 | protected function find(string $contents, File $file): void |
81 | { |
82 | // If the entire file is under one namespace, all we want is the namespace. |
83 | // If there were more than one namespace, it would appear as `namespace MyNamespace { ...`, |
84 | // a file with only a single namespace will appear as `namespace MyNamespace;`. |
85 | $singleNamespacePattern = '/ |
86 | (<?php|\r\n|\n) # A new line or the beginning of the file. |
87 | \s* # Allow whitespace before |
88 | namespace\s+(?<namespace>[0-9A-Za-z_\x7f-\xff\\\\]+)[\s\S]*; # Match a single namespace in the file. |
89 | /x'; // # x: ignore whitespace in regex. |
90 | if (1 === preg_match($singleNamespacePattern, $contents, $matches)) { |
91 | $this->addDiscoveredNamespaceChange($matches['namespace'], $file); |
92 | return; |
93 | } |
94 | |
95 | if (0 < preg_match_all('/\s*define\s*\(\s*["\']([^"\']*)["\']\s*,\s*["\'][^"\']*["\']\s*\)\s*;/', $contents, $constants)) { |
96 | foreach ($constants[1] as $constant) { |
97 | $constantObj = new ConstantSymbol($constant, $file); |
98 | $this->discoveredSymbols->add($constantObj); |
99 | } |
100 | } |
101 | |
102 | // TODO traits |
103 | |
104 | // TODO: Is the ";" in this still correct since it's being taken care of in the regex just above? |
105 | // Looks like with the preceding regex, it will never match. |
106 | |
107 | |
108 | preg_replace_callback( |
109 | ' |
110 | ~ # Start the pattern |
111 | [\r\n]+\s*namespace\s+([a-zA-Z0-9_\x7f-\xff\\\\]+)[;{\s\n]{1}[\s\S]*?(?=namespace|$) |
112 | # Look for a preceding namespace declaration, |
113 | # followed by a semicolon, open curly bracket, space or new line |
114 | # up until a |
115 | # potential second namespace declaration or end of file. |
116 | # if found, match that much before continuing the search on |
117 | | # the remainder of the string. |
118 | \/\*[\s\S]*?\*\/ | # Skip multiline comments |
119 | ^\s*\/\/.*$ | # Skip single line comments |
120 | \s* # Whitespace is allowed before |
121 | (?:abstract\sclass|class|interface)\s+ # Look behind for class, abstract class, interface |
122 | ([a-zA-Z0-9_\x7f-\xff]+) # Match the word until the first non-classname-valid character |
123 | \s? # Allow a space after |
124 | (?:{|extends|implements|\n|$) # Class declaration can be followed by {, extends, implements |
125 | # or a new line |
126 | ~x', // # x: ignore whitespace in regex. |
127 | function ($matches) use ($file) { |
128 | |
129 | // If we're inside a namespace other than the global namespace: |
130 | if (1 === preg_match('/^\s*namespace\s+[a-zA-Z0-9_\x7f-\xff\\\\]+[;{\s\n]{1}.*/', $matches[0])) { |
131 | $this->addDiscoveredNamespaceChange($matches[1], $file); |
132 | |
133 | return $matches[0]; |
134 | } |
135 | |
136 | if (count($matches) < 3) { |
137 | return $matches[0]; |
138 | } |
139 | |
140 | // TODO: Why is this [2] and not [1] (which seems to be always empty). |
141 | $this->addDiscoveredClassChange($matches[2], $file); |
142 | |
143 | return $matches[0]; |
144 | }, |
145 | $contents |
146 | ); |
147 | } |
148 | |
149 | protected function addDiscoveredClassChange(string $classname, File $file): void |
150 | { |
151 | |
152 | if ('ReturnTypeWillChange' === $classname) { |
153 | return; |
154 | } |
155 | if (in_array($classname, $this->getBuiltIns())) { |
156 | return; |
157 | } |
158 | |
159 | $classSymbol = new ClassSymbol($classname, $file); |
160 | $this->discoveredSymbols->add($classSymbol); |
161 | } |
162 | |
163 | protected function addDiscoveredNamespaceChange(string $namespace, File $file): void |
164 | { |
165 | |
166 | foreach ($this->excludeNamespacesFromPrefixing as $excludeNamespace) { |
167 | if (0 === strpos($namespace, $excludeNamespace)) { |
168 | return; |
169 | } |
170 | } |
171 | |
172 | $namespaceObj = new NamespaceSymbol($namespace, $file); |
173 | $this->discoveredSymbols->add($namespaceObj); |
174 | } |
175 | |
176 | /** |
177 | * Get a list of PHP built-in classes etc. so they are not prefixed. |
178 | * |
179 | * Polyfilled classes were being prefixed, but the polyfills are only active when the PHP version is below X, |
180 | * so calls to those prefixed polyfilled classnames would fail on newer PHP versions. |
181 | * |
182 | * NB: This list is not exhaustive. Any unloaded PHP extensions are not included. |
183 | * |
184 | * @see https://github.com/BrianHenryIE/strauss/issues/79 |
185 | * |
186 | * ``` |
187 | * array_filter( |
188 | * get_declared_classes(), |
189 | * function(string $className): bool { |
190 | * $reflector = new \ReflectionClass($className); |
191 | * return empty($reflector->getFileName()); |
192 | * } |
193 | * ); |
194 | * ``` |
195 | * |
196 | * @return string[] |
197 | */ |
198 | protected function getBuiltIns(): array |
199 | { |
200 | $builtins = [ |
201 | '7.4' => |
202 | [ |
203 | 'classes' => |
204 | [ |
205 | 'AppendIterator', |
206 | 'ArgumentCountError', |
207 | 'ArithmeticError', |
208 | 'ArrayIterator', |
209 | 'ArrayObject', |
210 | 'AssertionError', |
211 | 'BadFunctionCallException', |
212 | 'BadMethodCallException', |
213 | 'CURLFile', |
214 | 'CachingIterator', |
215 | 'CallbackFilterIterator', |
216 | 'ClosedGeneratorException', |
217 | 'Closure', |
218 | 'Collator', |
219 | 'CompileError', |
220 | 'DOMAttr', |
221 | 'DOMCdataSection', |
222 | 'DOMCharacterData', |
223 | 'DOMComment', |
224 | 'DOMConfiguration', |
225 | 'DOMDocument', |
226 | 'DOMDocumentFragment', |
227 | 'DOMDocumentType', |
228 | 'DOMDomError', |
229 | 'DOMElement', |
230 | 'DOMEntity', |
231 | 'DOMEntityReference', |
232 | 'DOMErrorHandler', |
233 | 'DOMException', |
234 | 'DOMImplementation', |
235 | 'DOMImplementationList', |
236 | 'DOMImplementationSource', |
237 | 'DOMLocator', |
238 | 'DOMNameList', |
239 | 'DOMNameSpaceNode', |
240 | 'DOMNamedNodeMap', |
241 | 'DOMNode', |
242 | 'DOMNodeList', |
243 | 'DOMNotation', |
244 | 'DOMProcessingInstruction', |
245 | 'DOMStringExtend', |
246 | 'DOMStringList', |
247 | 'DOMText', |
248 | 'DOMTypeinfo', |
249 | 'DOMUserDataHandler', |
250 | 'DOMXPath', |
251 | 'DateInterval', |
252 | 'DatePeriod', |
253 | 'DateTime', |
254 | 'DateTimeImmutable', |
255 | 'DateTimeZone', |
256 | 'Directory', |
257 | 'DirectoryIterator', |
258 | 'DivisionByZeroError', |
259 | 'DomainException', |
260 | 'EmptyIterator', |
261 | 'Error', |
262 | 'ErrorException', |
263 | 'Exception', |
264 | 'FFI', |
265 | 'FFI\\CData', |
266 | 'FFI\\CType', |
267 | 'FFI\\Exception', |
268 | 'FFI\\ParserException', |
269 | 'FilesystemIterator', |
270 | 'FilterIterator', |
271 | 'GMP', |
272 | 'Generator', |
273 | 'GlobIterator', |
274 | 'HashContext', |
275 | 'InfiniteIterator', |
276 | 'IntlBreakIterator', |
277 | 'IntlCalendar', |
278 | 'IntlChar', |
279 | 'IntlCodePointBreakIterator', |
280 | 'IntlDateFormatter', |
281 | 'IntlException', |
282 | 'IntlGregorianCalendar', |
283 | 'IntlIterator', |
284 | 'IntlPartsIterator', |
285 | 'IntlRuleBasedBreakIterator', |
286 | 'IntlTimeZone', |
287 | 'InvalidArgumentException', |
288 | 'IteratorIterator', |
289 | 'JsonException', |
290 | 'LengthException', |
291 | 'LibXMLError', |
292 | 'LimitIterator', |
293 | 'Locale', |
294 | 'LogicException', |
295 | 'MessageFormatter', |
296 | 'MultipleIterator', |
297 | 'NoRewindIterator', |
298 | 'Normalizer', |
299 | 'NumberFormatter', |
300 | 'OutOfBoundsException', |
301 | 'OutOfRangeException', |
302 | 'OverflowException', |
303 | 'PDO', |
304 | 'PDOException', |
305 | 'PDORow', |
306 | 'PDOStatement', |
307 | 'ParentIterator', |
308 | 'ParseError', |
309 | 'Phar', |
310 | 'PharData', |
311 | 'PharException', |
312 | 'PharFileInfo', |
313 | 'RangeException', |
314 | 'RecursiveArrayIterator', |
315 | 'RecursiveCachingIterator', |
316 | 'RecursiveCallbackFilterIterator', |
317 | 'RecursiveDirectoryIterator', |
318 | 'RecursiveFilterIterator', |
319 | 'RecursiveIteratorIterator', |
320 | 'RecursiveRegexIterator', |
321 | 'RecursiveTreeIterator', |
322 | 'Reflection', |
323 | 'ReflectionClass', |
324 | 'ReflectionClassConstant', |
325 | 'ReflectionException', |
326 | 'ReflectionExtension', |
327 | 'ReflectionFunction', |
328 | 'ReflectionFunctionAbstract', |
329 | 'ReflectionGenerator', |
330 | 'ReflectionMethod', |
331 | 'ReflectionNamedType', |
332 | 'ReflectionObject', |
333 | 'ReflectionParameter', |
334 | 'ReflectionProperty', |
335 | 'ReflectionReference', |
336 | 'ReflectionType', |
337 | 'ReflectionZendExtension', |
338 | 'RegexIterator', |
339 | 'ResourceBundle', |
340 | 'RuntimeException', |
341 | 'SQLite3', |
342 | 'SQLite3Result', |
343 | 'SQLite3Stmt', |
344 | 'SessionHandler', |
345 | 'SimpleXMLElement', |
346 | 'SimpleXMLIterator', |
347 | 'SoapClient', |
348 | 'SoapFault', |
349 | 'SoapHeader', |
350 | 'SoapParam', |
351 | 'SoapServer', |
352 | 'SoapVar', |
353 | 'SodiumException', |
354 | 'SplDoublyLinkedList', |
355 | 'SplFileInfo', |
356 | 'SplFileObject', |
357 | 'SplFixedArray', |
358 | 'SplHeap', |
359 | 'SplMaxHeap', |
360 | 'SplMinHeap', |
361 | 'SplObjectStorage', |
362 | 'SplPriorityQueue', |
363 | 'SplQueue', |
364 | 'SplStack', |
365 | 'SplTempFileObject', |
366 | 'Spoofchecker', |
367 | 'Transliterator', |
368 | 'TypeError', |
369 | 'UConverter', |
370 | 'UnderflowException', |
371 | 'UnexpectedValueException', |
372 | 'WeakReference', |
373 | 'XMLReader', |
374 | 'XMLWriter', |
375 | 'XSLTProcessor', |
376 | 'ZipArchive', |
377 | '__PHP_Incomplete_Class', |
378 | 'finfo', |
379 | 'mysqli', |
380 | 'mysqli_driver', |
381 | 'mysqli_result', |
382 | 'mysqli_sql_exception', |
383 | 'mysqli_stmt', |
384 | 'mysqli_warning', |
385 | 'php_user_filter', |
386 | 'stdClass', |
387 | 'tidy', |
388 | 'tidyNode', |
389 | ], |
390 | 'interfaces' => |
391 | [ |
392 | 'ArrayAccess', |
393 | 'Countable', |
394 | 'DateTimeInterface', |
395 | 'Iterator', |
396 | 'IteratorAggregate', |
397 | 'JsonSerializable', |
398 | 'OuterIterator', |
399 | 'RecursiveIterator', |
400 | 'Reflector', |
401 | 'SeekableIterator', |
402 | 'Serializable', |
403 | 'SessionHandlerInterface', |
404 | 'SessionIdInterface', |
405 | 'SessionUpdateTimestampHandlerInterface', |
406 | 'SplObserver', |
407 | 'SplSubject', |
408 | 'Throwable', |
409 | 'Traversable', |
410 | ], |
411 | 'traits' => |
412 | [ |
413 | ], |
414 | ], |
415 | '8.1' => |
416 | [ |
417 | 'classes' => |
418 | [ |
419 | 'AddressInfo', |
420 | 'Attribute', |
421 | 'CURLStringFile', |
422 | 'CurlHandle', |
423 | 'CurlMultiHandle', |
424 | 'CurlShareHandle', |
425 | 'DeflateContext', |
426 | 'FTP\\Connection', |
427 | 'Fiber', |
428 | 'FiberError', |
429 | 'GdFont', |
430 | 'GdImage', |
431 | 'InflateContext', |
432 | 'InternalIterator', |
433 | 'IntlDatePatternGenerator', |
434 | 'LDAP\\Connection', |
435 | 'LDAP\\Result', |
436 | 'LDAP\\ResultEntry', |
437 | 'OpenSSLAsymmetricKey', |
438 | 'OpenSSLCertificate', |
439 | 'OpenSSLCertificateSigningRequest', |
440 | 'PSpell\\Config', |
441 | 'PSpell\\Dictionary', |
442 | 'PgSql\\Connection', |
443 | 'PgSql\\Lob', |
444 | 'PgSql\\Result', |
445 | 'PhpToken', |
446 | 'ReflectionAttribute', |
447 | 'ReflectionEnum', |
448 | 'ReflectionEnumBackedCase', |
449 | 'ReflectionEnumUnitCase', |
450 | 'ReflectionFiber', |
451 | 'ReflectionIntersectionType', |
452 | 'ReflectionUnionType', |
453 | 'ReturnTypeWillChange', |
454 | 'Shmop', |
455 | 'Socket', |
456 | 'SysvMessageQueue', |
457 | 'SysvSemaphore', |
458 | 'SysvSharedMemory', |
459 | 'UnhandledMatchError', |
460 | 'ValueError', |
461 | 'WeakMap', |
462 | 'XMLParser', |
463 | ], |
464 | 'interfaces' => |
465 | [ |
466 | 'BackedEnum', |
467 | 'DOMChildNode', |
468 | 'DOMParentNode', |
469 | 'Stringable', |
470 | 'UnitEnum', |
471 | ], |
472 | 'traits' => |
473 | [ |
474 | ], |
475 | ], |
476 | '8.2' => |
477 | [ |
478 | 'classes' => |
479 | [ |
480 | 'AddressInfo', |
481 | 'AllowDynamicProperties', |
482 | 'Attribute', |
483 | 'CURLStringFile', |
484 | 'CurlHandle', |
485 | 'CurlMultiHandle', |
486 | 'CurlShareHandle', |
487 | 'DeflateContext', |
488 | 'FTP\\Connection', |
489 | 'Fiber', |
490 | 'FiberError', |
491 | 'GdFont', |
492 | 'GdImage', |
493 | 'InflateContext', |
494 | 'InternalIterator', |
495 | 'IntlDatePatternGenerator', |
496 | 'LDAP\\Connection', |
497 | 'LDAP\\Result', |
498 | 'LDAP\\ResultEntry', |
499 | 'OpenSSLAsymmetricKey', |
500 | 'OpenSSLCertificate', |
501 | 'OpenSSLCertificateSigningRequest', |
502 | 'PSpell\\Config', |
503 | 'PSpell\\Dictionary', |
504 | 'PgSql\\Connection', |
505 | 'PgSql\\Lob', |
506 | 'PgSql\\Result', |
507 | 'PhpToken', |
508 | 'Random\\BrokenRandomEngineError', |
509 | 'Random\\Engine\\Mt19937', |
510 | 'Random\\Engine\\PcgOneseq128XslRr64', |
511 | 'Random\\Engine\\Secure', |
512 | 'Random\\Engine\\Xoshiro256StarStar', |
513 | 'Random\\RandomError', |
514 | 'Random\\RandomException', |
515 | 'Random\\Randomizer', |
516 | 'ReflectionAttribute', |
517 | 'ReflectionEnum', |
518 | 'ReflectionEnumBackedCase', |
519 | 'ReflectionEnumUnitCase', |
520 | 'ReflectionFiber', |
521 | 'ReflectionIntersectionType', |
522 | 'ReflectionUnionType', |
523 | 'ReturnTypeWillChange', |
524 | 'SensitiveParameter', |
525 | 'SensitiveParameterValue', |
526 | 'Shmop', |
527 | 'Socket', |
528 | 'SysvMessageQueue', |
529 | 'SysvSemaphore', |
530 | 'SysvSharedMemory', |
531 | 'UnhandledMatchError', |
532 | 'ValueError', |
533 | 'WeakMap', |
534 | 'XMLParser', |
535 | ], |
536 | 'interfaces' => |
537 | [ |
538 | 'BackedEnum', |
539 | 'DOMChildNode', |
540 | 'DOMParentNode', |
541 | 'Random\\CryptoSafeEngine', |
542 | 'Random\\Engine', |
543 | 'Stringable', |
544 | 'UnitEnum', |
545 | ], |
546 | 'traits' => |
547 | [ |
548 | ], |
549 | ], |
550 | '8.3' => |
551 | [ |
552 | 'classes' => |
553 | [ |
554 | 'AddressInfo', |
555 | 'AllowDynamicProperties', |
556 | 'Attribute', |
557 | 'CURLStringFile', |
558 | 'CurlHandle', |
559 | 'CurlMultiHandle', |
560 | 'CurlShareHandle', |
561 | 'DateError', |
562 | 'DateException', |
563 | 'DateInvalidOperationException', |
564 | 'DateInvalidTimeZoneException', |
565 | 'DateMalformedIntervalStringException', |
566 | 'DateMalformedPeriodStringException', |
567 | 'DateMalformedStringException', |
568 | 'DateObjectError', |
569 | 'DateRangeError', |
570 | 'DeflateContext', |
571 | 'FTP\\Connection', |
572 | 'Fiber', |
573 | 'FiberError', |
574 | 'GdFont', |
575 | 'GdImage', |
576 | 'InflateContext', |
577 | 'InternalIterator', |
578 | 'IntlDatePatternGenerator', |
579 | 'LDAP\\Connection', |
580 | 'LDAP\\Result', |
581 | 'LDAP\\ResultEntry', |
582 | 'OpenSSLAsymmetricKey', |
583 | 'OpenSSLCertificate', |
584 | 'OpenSSLCertificateSigningRequest', |
585 | 'Override', |
586 | 'PSpell\\Config', |
587 | 'PSpell\\Dictionary', |
588 | 'PgSql\\Connection', |
589 | 'PgSql\\Lob', |
590 | 'PgSql\\Result', |
591 | 'PhpToken', |
592 | 'Random\\BrokenRandomEngineError', |
593 | 'Random\\Engine\\Mt19937', |
594 | 'Random\\Engine\\PcgOneseq128XslRr64', |
595 | 'Random\\Engine\\Secure', |
596 | 'Random\\Engine\\Xoshiro256StarStar', |
597 | 'Random\\IntervalBoundary', |
598 | 'Random\\RandomError', |
599 | 'Random\\RandomException', |
600 | 'Random\\Randomizer', |
601 | 'ReflectionAttribute', |
602 | 'ReflectionEnum', |
603 | 'ReflectionEnumBackedCase', |
604 | 'ReflectionEnumUnitCase', |
605 | 'ReflectionFiber', |
606 | 'ReflectionIntersectionType', |
607 | 'ReflectionUnionType', |
608 | 'ReturnTypeWillChange', |
609 | 'SQLite3Exception', |
610 | 'SensitiveParameter', |
611 | 'SensitiveParameterValue', |
612 | 'Shmop', |
613 | 'Socket', |
614 | 'SysvMessageQueue', |
615 | 'SysvSemaphore', |
616 | 'SysvSharedMemory', |
617 | 'UnhandledMatchError', |
618 | 'ValueError', |
619 | 'WeakMap', |
620 | 'XMLParser', |
621 | ], |
622 | 'interfaces' => |
623 | [ |
624 | 'BackedEnum', |
625 | 'DOMChildNode', |
626 | 'DOMParentNode', |
627 | 'Random\\CryptoSafeEngine', |
628 | 'Random\\Engine', |
629 | 'Stringable', |
630 | 'UnitEnum', |
631 | ], |
632 | 'traits' => |
633 | [ |
634 | ], |
635 | ], |
636 | '8.4' => |
637 | [ |
638 | 'classes' => |
639 | [ |
640 | 'DOM\\Document', |
641 | 'DOM\\HTMLDocument', |
642 | 'DOM\\XMLDocument', |
643 | 'dom\\attr', |
644 | 'dom\\cdatasection', |
645 | 'dom\\characterdata', |
646 | 'dom\\comment', |
647 | 'dom\\documentfragment', |
648 | 'dom\\documenttype', |
649 | 'dom\\domexception', |
650 | 'dom\\element', |
651 | 'dom\\entity', |
652 | 'dom\\entityreference', |
653 | 'dom\\namednodemap', |
654 | 'dom\\namespacenode', |
655 | 'dom\\node', |
656 | 'dom\\nodelist', |
657 | 'dom\\notation', |
658 | 'dom\\processinginstruction', |
659 | 'dom\\text', |
660 | 'dom\\xpath', |
661 | ], |
662 | 'interfaces' => |
663 | [ |
664 | 'dom\\childnode', |
665 | 'dom\\parentnode', |
666 | ], |
667 | 'traits' => |
668 | [ |
669 | ], |
670 | ], |
671 | ]; |
672 | |
673 | $flatArray = array(); |
674 | array_walk_recursive( |
675 | $builtins, |
676 | function ($array) use (&$flatArray) { |
677 | if (is_array($array)) { |
678 | $flatArray = array_merge($flatArray, array_values($array)); |
679 | } else { |
680 | $flatArray[] = $array; |
681 | } |
682 | } |
683 | ); |
684 | return $flatArray; |
685 | } |
686 | } |