Completed
Pull Request — master (#157)
by Kévin
03:46
created

Compiler::compile()   F

Complexity

Conditions 20
Paths 1755

Size

Total Lines 91
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 95.6872

Importance

Changes 0
Metric Value
cc 20
eloc 40
nc 1755
nop 1
dl 0
loc 91
ccs 23
cts 54
cp 0.4259
crap 95.6872
rs 2
c 0
b 0
f 0

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
 * @author Patsura Dmitry https://github.com/ovr <[email protected]>
4
 */
5
6
namespace PHPSA;
7
8
use PHPSA\Definition\ClassDefinition;
9
use PHPSA\Definition\FunctionDefinition;
10
use PHPSA\Definition\InterfaceDefinition;
11
use PHPSA\Definition\RuntimeClassDefinition;
12
use PHPSA\Definition\TraitDefinition;
13
use PHPSA\Definition\RuntimeInterfaceDefinition;
14
use ReflectionClass;
15
16
class Compiler
17
{
18
    /**
19
     * @var ClassDefinition[]
20
     */
21
    protected $classes = [];
22
23
    /**
24
     * @var TraitDefinition[]
25
     */
26
    protected $traits = array();
27
28
    /**
29
     * @var FunctionDefinition[]
30
     */
31
    protected $functions = [];
32
33
    /**
34
     * @var InterfaceDefinition[]
35
     */
36
    protected $interfaces = [];
37
38
    /**
39
     * @param ClassDefinition $class
40
     */
41 25
    public function addClass(ClassDefinition $class)
42
    {
43 25
        $this->classes[implode('\\', [$class->getNamespace(), $class->getName()])] = $class;
44 25
    }
45
46
    /**
47
     * @param TraitDefinition $class
48
     */
49
    public function addTrait(TraitDefinition $class)
50
    {
51
        $this->traits[implode('\\', [$class->getNamespace(), $class->getName()])] = $class;
52
    }
53
54
    /**
55
     * @param FunctionDefinition $function
56
     */
57 1
    public function addFunction(FunctionDefinition $function)
58
    {
59 1
        $this->functions[] = $function;
60 1
    }
61
62
    /**
63
     * @param InterfaceDefinition $interface
64
     */
65
    public function addInterface(InterfaceDefinition $interface)
66
    {
67
        $this->interfaces[implode('\\', [$interface->getNamespace(), $interface->getName()])] = $interface;
68
    }
69
70
    /**
71
     * @param Context $context
72
     */
73 25
    public function compile(Context $context)
0 ignored issues
show
Complexity introduced by
This operation has 4992 execution paths which exceeds the configured maximum of 200.

A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.

You can also find more information in the “Code” section of your repository.

Loading history...
74
    {
75 25
        $context->scopePointer = null;
76
77 25
        foreach ($this->interfaces as $interface) {
78
            foreach ($interface->getExtendsInterface() as $extendsInterface) {
79
                if (isset($this->interfaces[$extendsInterface])) {
80
                    $interface->addExtendsInterfaceDefinition($this->interfaces[$extendsInterface]);
81
                    continue;
82
                }
83
84
                if (class_exists($extendsInterface, true)) {
85
                    $interface->addExtendsInterfaceDefinition(
86
                        new RuntimeInterfaceDefinition(new ReflectionClass($extendsInterface))
87
                    );
88
                }
89
            }
90 25
        }
91
92
        /**
93
         * @todo Implement class map...
94
         */
95 25
        foreach ($this->classes as $class) {
96 25
            $extends = $class->getExtendsClass();
97 25
            if ($extends) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extends of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
98
                if (isset($this->classes[$extends])) {
99
                    $class->setExtendsClassDefinition($this->classes[$extends]);
100
                } else {
101
                    if (class_exists($extends, true)) {
102
                        $class->setExtendsClassDefinition(
103
                            new RuntimeClassDefinition(
104
                                new ReflectionClass(
105
                                    $extends
106
                                )
107
                            )
108
                        );
109
                    }
110
                }
111
            }
112
113 25
            foreach ($class->getInterfaces() as $interface) {
114
                if (!isset($this->interfaces[$interface])) {
115
                    continue;
116
                }
117
118
                $class->addInterfaceDefinition($this->interfaces[$interface]);
119 25
            }
120 25
        }
121
122 25
        foreach ($this->interfaces as $interface) {
123
            /**
124
             * @todo Configuration
125
             *
126
             * Ignore Interfaces compiling from vendor
127
             */
128
            $checkVendor = strpos($class->getFilepath(), './vendor');
0 ignored issues
show
Bug introduced by
The variable $class seems to be defined by a foreach iteration on line 95. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
129
            if ($checkVendor !== false && $checkVendor < 3) {
130
                continue;
131
            }
132
133
            $interface->compile($context);
134 25
        }
135
136 25
        foreach ($this->functions as $function) {
137
            /**
138
             * @todo Configuration
139
             *
140
             * Ignore functions compiling from vendor
141
             */
142 1
            $checkVendor = strpos($function->getFilepath(), './vendor');
143 1
            if ($checkVendor !== false && $checkVendor < 3) {
144
                continue;
145
            }
146
147 1
            $function->compile($context);
148 25
        }
149
150 25
        foreach ($this->classes as $class) {
151
            /**
152
             * @todo Configuration
153
             *
154
             * Ignore Classes compiling from vendor
155
             */
156 25
            $checkVendor = strpos($class->getFilepath(), './vendor');
157 25
            if ($checkVendor !== false && $checkVendor < 3) {
158
                continue;
159
            }
160
161 25
            $class->compile($context);
162 25
        }
163 25
    }
164
165
    /**
166
     * Try to find function with $namespace from pre-compiled function(s)
167
     *
168
     * @param string $name
169
     * @param string|null $namespace
170
     * @return bool|FunctionDefinition
171
     */
172 10
    public function getFunctionNS($name, $namespace = null)
173
    {
174 10
        foreach ($this->functions as $function) {
175 1
            if ($function->getName() == $name && $function->getNamespace() == $namespace) {
176
                return $function;
177
            }
178 10
        }
179
180 10
        return false;
181
    }
182
183
    /**
184
     * @param string $name
185
     * @return TraitDefinition|null
186
     */
187
    public function getTrait($name)
188
    {
189
        if (isset($this->traits[$name])) {
190
            return $this->traits[$name];
191
        }
192
193
        return null;
194
    }
195
196
    /**
197
     * Try to find function from pre-compiled function(s)
198
     *
199
     * @param string $name
200
     * @return bool|FunctionDefinition
201
     */
202 1
    public function getFunction($name)
203
    {
204 1
        foreach ($this->functions as $function) {
205 1
            if ($function->getName() == $name) {
206
                return $function;
207
            }
208 1
        }
209
210 1
        return false;
211
    }
212
}
213