Passed
Push — master ( 8f8adf...24c04a )
by butschster
06:15 queued 24s
created

AbstractLocator   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 126
Duplicated Lines 0 %

Test Coverage

Coverage 91.84%

Importance

Changes 0
Metric Value
wmc 17
eloc 47
dl 0
loc 126
ccs 45
cts 49
cp 0.9184
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A classReflection() 0 32 6
A enumReflection() 0 32 6
A availableReflections() 0 18 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Tokenizer;
6
7
use Psr\Log\LoggerAwareInterface;
8
use Spiral\Core\Container\InjectableInterface;
9
use Spiral\Logger\Traits\LoggerTrait;
10
use Spiral\Tokenizer\Exception\LocatorException;
11
use Spiral\Tokenizer\Reflection\ReflectionFile;
12
use Spiral\Tokenizer\Traits\TargetTrait;
13
use Symfony\Component\Finder\Finder;
14
15
/**
16
 * Base class for Class and Invocation locators.
17
 */
18
abstract class AbstractLocator implements InjectableInterface, LoggerAwareInterface
19
{
20
    use LoggerTrait;
21
    use TargetTrait;
22
23
    public const INJECTOR = Tokenizer::class;
24
25 434
    public function __construct(
26
        protected Finder $finder,
27
        protected readonly bool $debug = false,
28
    ) {
29 434
    }
30
31
    /**
32
     * Available file reflections. Generator.
33
     *
34
     * @throws \Exception
35
     *
36
     * @return \Generator<int, ReflectionFile, mixed, void>
37
     */
38 425
    protected function availableReflections(): \Generator
39
    {
40 425
        foreach ($this->finder->getIterator() as $file) {
41 425
            $reflection = new ReflectionFile((string)$file);
42
43 425
            if ($reflection->hasIncludes()) {
44
                // We are not analyzing files which has includes, it's not safe to require such reflections
45 29
                if ($this->debug) {
46 1
                    $this->getLogger()->warning(
47 1
                        \sprintf('File `%s` has includes and excluded from analysis', (string) $file),
48 1
                        ['file' => $file]
49 1
                    );
50
                }
51
52 29
                continue;
53
            }
54
55 425
            yield $reflection;
56
        }
57
    }
58
59
    /**
60
     * Safely get class reflection, class loading errors will be blocked and reflection will be
61
     * excluded from analysis.
62
     *
63
     * @template T
64
     * @param class-string<T> $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
65
     * @return \ReflectionClass<T>
66
     *
67
     * @throws LocatorException
68
     */
69 419
    protected function classReflection(string $class): \ReflectionClass
70
    {
71 419
        $loader = static function ($class) {
72 323
            if ($class === LocatorException::class) {
73
                return;
74
            }
75
76 323
            throw new LocatorException(\sprintf("Class '%s' can not be loaded", $class));
77 419
        };
78
79
        //To suspend class dependency exception
80 419
        \spl_autoload_register($loader);
81
82
        try {
83
            //In some cases reflection can thrown an exception if class invalid or can not be loaded,
84
            //we are going to handle such exception and convert it soft exception
85 419
            return new \ReflectionClass($class);
86 323
        } catch (\Throwable $e) {
87 323
            if ($e instanceof LocatorException && $e->getPrevious() != null) {
88
                $e = $e->getPrevious();
89
            }
90
91 323
            if ($this->debug) {
92 1
                $this->getLogger()->error(
93 1
                    \sprintf('%s: %s in %s:%s', $class, $e->getMessage(), $e->getFile(), $e->getLine()),
94 1
                    ['error' => $e]
95 1
                );
96
            }
97
98 323
            throw new LocatorException($e->getMessage(), (int) $e->getCode(), $e);
99
        } finally {
100 419
            \spl_autoload_unregister($loader);
101
        }
102
    }
103
104
    /**
105
     * Safely get enum reflection, class loading errors will be blocked and reflection will be
106
     * excluded from analysis.
107
     *
108
     * @param class-string $enum
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
109
     *
110
     * @throws LocatorException
111
     */
112 8
    protected function enumReflection(string $enum): \ReflectionEnum
0 ignored issues
show
Bug introduced by
The type ReflectionEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
113
    {
114 8
        $loader = static function (string $enum): void {
115 7
            if ($enum === LocatorException::class) {
116
                return;
117
            }
118
119 7
            throw new LocatorException(\sprintf("Enum '%s' can not be loaded", $enum));
120 8
        };
121
122
        //To suspend class dependency exception
123 8
        \spl_autoload_register($loader);
124
125
        try {
126
            //In some enum reflection can thrown an exception if enum invalid or can not be loaded,
127
            //we are going to handle such exception and convert it soft exception
128 8
            return new \ReflectionEnum($enum);
129 7
        } catch (\Throwable $e) {
130 7
            if ($e instanceof LocatorException && $e->getPrevious() != null) {
131
                $e = $e->getPrevious();
132
            }
133
134 7
            if ($this->debug) {
135 1
                $this->getLogger()->error(
136 1
                    \sprintf('%s: %s in %s:%s', $enum, $e->getMessage(), $e->getFile(), $e->getLine()),
137 1
                    ['error' => $e]
138 1
                );
139
            }
140
141 7
            throw new LocatorException($e->getMessage(), (int) $e->getCode(), $e);
142
        } finally {
143 8
            \spl_autoload_unregister($loader);
144
        }
145
    }
146
}
147