Completed
Push — master ( ed922a...ce73d9 )
by Nikola
03:26
created

ClassLoader::load()   C

Complexity

Conditions 11
Paths 12

Size

Total Lines 57
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
dl 0
loc 57
ccs 0
cts 45
cp 0
rs 6.4824
c 0
b 0
f 0
cc 11
eloc 34
nc 12
nop 1
crap 132

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * This file is part of the Abstract builder package, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\AbstractBuilder\Ast;
11
12
use PhpParser\NodeTraverser;
13
use PhpParser\NodeVisitor\NameResolver;
14
use PhpParser\ParserFactory;
15
use RunOpenCode\AbstractBuilder\Ast\Visitor\ClassIntrospectionVisitor;
16
use RunOpenCode\AbstractBuilder\Exception\RuntimeException;
17
18
class ClassLoader
19
{
20
    /**
21
     * @var \PhpParser\Parser
22
     */
23
    private $parser;
24
25
    /**
26
     * @var \PhpParser\NodeTraverser
27
     */
28
    private $traverser;
29
30
    /**
31
     * @var ClassIntrospectionVisitor
32
     */
33
    private $introspector;
34
35
    /**
36
     * ClassLoader constructor.
37
     */
38
    public function __construct()
39
    {
40
        $this->parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
41
        $this->traverser = new NodeTraverser();
42
        $this->introspector = new ClassIntrospectionVisitor();
43
44
        $this->traverser->addVisitor(new NameResolver());
45
        $this->traverser->addVisitor($this->introspector);
46
    }
47
48
    /**
49
     * Load class and build its metadata value object
50
     *
51
     * @param string $class Filename or full qualified class name
52
     *
53
     * @return ClassMetadata
54
     *
55
     * @throws \RunOpenCode\AbstractBuilder\Exception\RuntimeException
56
     * @throws \RunOpenCode\AbstractBuilder\Exception\InvalidArgumentException
57
     */
58
    public function load($class)
59
    {
60
        $filename = $class;
61
62
        if (class_exists($class, true)) {
63
            $filename = (new \ReflectionClass($class))->getFileName();
64
        }
65
66
        if (file_exists($filename)) {
67
68
            $this->traverser->traverse($this->parser->parse(file_get_contents($filename)));
0 ignored issues
show
Bug introduced by
It seems like $this->parser->parse(fil...et_contents($filename)) targeting PhpParser\Parser::parse() can also be of type null; however, PhpParser\NodeTraverser::traverse() does only seem to accept array<integer,object<PhpParser\Node>>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
69
            $classes = $this->introspector->getClasses();
70
71
            if (0 === count($classes)) {
72
                throw new RuntimeException(sprintf('Class definition does not exist in "%s".', $filename));
73
            }
74
75
            if ($filename === $class && count($classes) > 1) {
76
                throw new RuntimeException(sprintf('There are more than one class definition in "%s" and it can not be determined which class to use.', $filename));
77
            }
78
79
            if (1 === count($classes)) {
80
81
                return new ClassMetadata(
82
                    $classes[0]['ast'],
83
                    $classes[0]['namespace'],
84
                    $classes[0]['class'],
85
                    $filename,
86
                    $classes[0]['final'],
87
                    $classes[0]['abstract'],
88
                    $classes[0]['methods'],
89
                    null !== $classes[0]['parent'] ? $this->load($classes[0]['parent']) : null
90
                );
91
            }
92
93
            $class = trim('\\', $class);
94
95
            foreach ($classes as $metadata) {
96
97
                if ($class === $metadata['fqcn']) {
98
99
                    return new ClassMetadata(
100
                        $metadata['ast'],
101
                        $metadata['namespace'],
102
                        $metadata['class'],
103
                        $filename,
104
                        $metadata['final'],
105
                        $metadata['abstract'],
106
                        $metadata['methods'],
107
                        null !== $metadata['parent'] ? $this->load($metadata['parent']) : null
108
                    );
109
                }
110
            }
111
        }
112
113
        throw new RuntimeException(sprintf('Unable to load class from "%s".', $class));
114
    }
115
}
116