Passed
Push — master ( b292e6...c5f4fa )
by butschster
07:03
created

AbstractLocator   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Test Coverage

Coverage 92.31%

Importance

Changes 3
Bugs 2 Features 0
Metric Value
wmc 9
eloc 33
c 3
b 2
f 0
dl 0
loc 85
rs 10
ccs 24
cts 26
cp 0.9231

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A classReflection() 0 36 5
A availableReflections() 0 16 3
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;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Finder\Finder 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...
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 326
    public function __construct(
26
        protected Finder $finder,
27
        protected readonly bool $debug = false
28
    ) {
29
    }
30
31
    /**
32
     * Available file reflections. Generator.
33
     *
34
     * @throws \Exception
35
     *
36
     * @return \Generator<int, ReflectionFile, mixed, void>
37
     */
38 324
    protected function availableReflections(): \Generator
39
    {
40 324
        foreach ($this->finder->getIterator() as $file) {
41 324
            $reflection = new ReflectionFile((string)$file);
42
43 324
            if ($reflection->hasIncludes()) {
44
                // We are not analyzing files which has includes, it's not safe to require such reflections
45 20
                $this->getLogger()->warning(
46 20
                    \sprintf('File `%s` has includes and excluded from analysis', (string) $file),
47
                    ['file' => $file]
48
                );
49
50 20
                continue;
51
            }
52
53 324
            yield $reflection;
54
        }
55
    }
56
57
    /**
58
     * Safely get class reflection, class loading errors will be blocked and reflection will be
59
     * excluded from analysis.
60
     *
61
     * @template T
62
     * @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...
63
     * @return \ReflectionClass<T>
64
     *
65
     * @throws LocatorException
66
     */
67 324
    protected function classReflection(string $class): \ReflectionClass
68
    {
69 324
        $loader = static function ($class) {
70 275
            if ($class === LocatorException::class) {
71
                return;
72
            }
73
74 275
            throw new LocatorException(\sprintf("Class '%s' can not be loaded", $class));
75
        };
76
77
        //To suspend class dependency exception
78 324
        \spl_autoload_register($loader);
79
80
        try {
81
            //In some cases reflection can thrown an exception if class invalid or can not be loaded,
82
            //we are going to handle such exception and convert it soft exception
83 324
            return new \ReflectionClass($class);
84 275
        } catch (\Throwable $e) {
85 275
            if ($e instanceof LocatorException && $e->getPrevious() != null) {
86
                $e = $e->getPrevious();
87
            }
88
89 275
            $this->getLogger()->error(
90 275
                \sprintf(
91
                    '%s: %s in %s:%s',
92
                    $class,
93 275
                    $e->getMessage(),
94 275
                    $e->getFile(),
95 275
                    $e->getLine()
96
                ),
97
                ['error' => $e]
98
            );
99
100 275
            throw new LocatorException($e->getMessage(), (int) $e->getCode(), $e);
101
        } finally {
102 324
            \spl_autoload_unregister($loader);
103
        }
104
    }
105
}
106