|
13 | 13 |
|
14 | 14 | namespace Guanguans\PHPStanRules\Support; |
15 | 15 |
|
16 | | -use Composer\Autoload\ClassLoader; |
17 | | -use Illuminate\Support\Collection; |
18 | 16 | use PhpParser\Node; |
19 | 17 | use PhpParser\NodeTraverser; |
20 | 18 | use PhpParser\NodeVisitor\CloningVisitor; |
21 | 19 |
|
22 | | -if (!\function_exists('Guanguans\PHPStanRules\Support\classes')) { |
23 | | - /** |
24 | | - * @see https://github.com/illuminate/collections |
25 | | - * @see https://github.com/alekitto/class-finder |
26 | | - * @see https://github.com/ergebnis/classy |
27 | | - * @see https://gitlab.com/hpierce1102/ClassFinder |
28 | | - * @see https://packagist.org/packages/haydenpierce/class-finder |
29 | | - * @see \get_declared_classes() |
30 | | - * @see \get_declared_interfaces() |
31 | | - * @see \get_declared_traits() |
32 | | - * @see \Composer\Util\ErrorHandler |
33 | | - * @see \Composer\Util\Silencer::call() |
34 | | - * @see \DG\BypassFinals::enable() |
35 | | - * @see \Illuminate\Foundation\Bootstrap\HandleExceptions::bootstrap() |
36 | | - * @see \Monolog\ErrorHandler |
37 | | - * @see \PhpCsFixer\ExecutorWithoutErrorHandler |
38 | | - * @see \Phrity\Util\ErrorHandler |
39 | | - * |
40 | | - * @template TObject of object |
41 | | - * |
42 | | - * @internal |
43 | | - * |
44 | | - * @param null|(callable(class-string<TObject>, string): bool) $filter |
45 | | - * |
46 | | - * @throws \ErrorException |
47 | | - * @throws \ReflectionException |
48 | | - * |
49 | | - * @return \Illuminate\Support\Collection<class-string<TObject>, \ReflectionClass<TObject>> |
50 | | - * |
51 | | - * @noinspection PhpUndefinedNamespaceInspection |
52 | | - */ |
53 | | - function classes(?callable $filter = null): Collection |
54 | | - { |
55 | | - $func = __FUNCTION__; |
56 | | - $errorMessenger = static fn ( |
57 | | - string $file, |
58 | | - string $class |
59 | | - ): string => "Failed to reflect the class [$class] in the file [$file]. " |
60 | | - ."You may need to filter out the class or file using the callback parameter of the function [$func()]."; |
61 | | - |
62 | | - /** @var null|array{file: string, class: class-string<TObject>, line: int} $context */ |
63 | | - static $context = null; |
64 | | - static $registered = false; |
65 | | - |
66 | | - if (!$registered) { |
67 | | - register_shutdown_function( |
68 | | - static function () use (&$context, $errorMessenger): void { |
69 | | - // @codeCoverageIgnoreStart |
70 | | - if ( |
71 | | - null === $context |
72 | | - || null === ($error = error_get_last()) |
73 | | - || !\in_array($error['type'], [\E_COMPILE_ERROR, \E_CORE_ERROR, \E_ERROR, \E_PARSE], true) |
74 | | - ) { |
75 | | - return; |
76 | | - } |
77 | | - |
78 | | - // trigger_error($errorMessenger($context['file'], $context['class']), \E_USER_ERROR); |
79 | | - throw new \ErrorException( |
80 | | - $errorMessenger($context['file'], $context['class']), |
81 | | - 0, |
82 | | - $error['type'], |
83 | | - __FILE__, |
84 | | - $context['line'], |
85 | | - new \ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']) |
86 | | - ); |
87 | | - // @codeCoverageIgnoreEnd |
88 | | - } |
89 | | - ); |
90 | | - $registered = true; |
91 | | - } |
92 | | - |
93 | | - /** @var null|\Illuminate\Support\Collection<string, class-string> $classes */ |
94 | | - static $classes; |
95 | | - $classes ??= collect(spl_autoload_functions())->flatMap( |
96 | | - static fn (callable $loader): array => \is_array($loader) && $loader[0] instanceof ClassLoader |
97 | | - ? $loader[0]->getClassMap() |
98 | | - : [] |
99 | | - ); |
100 | | - $filter ??= static fn (string $class, string $file): bool => true; |
101 | | - |
102 | | - return $classes |
103 | | - ->filter(static fn (string $file, string $class): bool => $filter($class, $file)) |
104 | | - ->mapWithKeys(static function (string $file, string $class) use (&$context, $errorMessenger): array { |
105 | | - try { |
106 | | - $context = ['file' => $file, 'class' => $class, 'line' => __LINE__ + 2]; |
107 | | - |
108 | | - return [$class => new \ReflectionClass($class)]; |
109 | | - } catch (\Throwable $throwable) { |
110 | | - // return [$class => $throwable]; |
111 | | - throw new \ReflectionException($errorMessenger($file, $class), 0, $throwable); |
112 | | - } finally { |
113 | | - $context = null; |
114 | | - } |
115 | | - }); |
116 | | - } |
117 | | -} |
118 | | - |
119 | 20 | if (!\function_exists('Guanguans\PHPStanRules\Support\clone_node')) { |
120 | 21 | /** |
121 | 22 | * @see \DeepCopy\deep_copy() |
|
0 commit comments