Completed
Push — master ( 02285f...915210 )
by personal
05:27
created

Extractor::extract()   D

Complexity

Conditions 17
Paths 27

Size

Total Lines 102
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 2 Features 0
Metric Value
c 8
b 2
f 0
dl 0
loc 102
rs 4.8362
cc 17
eloc 65
nc 27
nop 1

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
/*
4
 * (c) Jean-François Lépine <https://twitter.com/Halleck45>
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Hal\Component\OOP\Extractor;
11
use Hal\Component\OOP\Reflected\ReflectedClass\ReflectedAnonymousClass;
12
use Hal\Component\OOP\Resolver\NameResolver;
13
use Hal\Component\Token\Tokenizer;
14
15
16
/**
17
 * Extracts info about classes in one file
18
 * Remember that one file can contains multiple classes
19
 *
20
 * @author Jean-François Lépine <https://twitter.com/Halleck45>
21
 */
22
class Extractor {
23
24
    /**
25
     * @var Searcher
26
     */
27
    private $searcher;
28
29
    /**
30
     * @var Result
31
     */
32
    private $result;
33
34
    /**
35
     * @var \StdClass
36
     */
37
    private $extractors;
38
39
    /**
40
     * @var \Hal\Component\Token\Tokenizer
41
     */
42
    private $tokenizer;
43
44
    /**
45
     * Constructor
46
     */
47
    public function __construct(Tokenizer $tokenizer) {
48
49
        $this->tokenizer = $tokenizer;
50
        $this->searcher = new Searcher();
51
        $this->result= new Result;
52
53
        $this->extractors = (object) array(
54
            'class' => new ClassExtractor($this->searcher)
55
            , 'interface' => new InterfaceExtractor($this->searcher)
56
            , 'alias' => new AliasExtractor($this->searcher)
57
            , 'method' => new MethodExtractor($this->searcher)
58
            , 'call' => new CallExtractor($this->searcher)
59
        );
60
    }
61
62
    /**
63
     * Extract infos from file
64
     *
65
     * @param $filename
66
     * @return Result
67
     */
68
    public function extract($filename)
69
    {
70
71
        $result = new Result;
72
73
        $tokens = $this->tokenizer->tokenize($filename);
74
        $nameResolver = new NameResolver();
75
76
        // default current values
77
        $class = $interface = $function = $namespace = $method = null;
0 ignored issues
show
Unused Code introduced by
$function is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
Unused Code introduced by
$interface is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
78
79
        $len = sizeof($tokens, COUNT_NORMAL);
80
        $endAnonymous = 0;
81
        $mainContextClass = null; // class containing a anonymous class
82
83
        for($n = 0; $n < $len; $n++) {
84
85
            if($mainContextClass && $n > $endAnonymous) {
86
                // anonymous class is finished. We back to parent class
87
                // methods will be added to the main class now
88
                $class = $mainContextClass;
89
                $mainContextClass = null;
90
            }
91
92
            $token = $tokens[$n];
93
94
            switch($token->getType()) {
95
96
                case T_USE:
97
                    $alias = $this->extractors->alias->extract($n, $tokens);
98
                    if (null !== $alias->name && null !== $alias->alias) {
99
                        $nameResolver->pushAlias($alias);
100
                    }
101
                    break;
102
103
                case T_NAMESPACE:
104
                    $namespace = '\\'.$this->searcher->getFollowingName($n, $tokens);
105
                    $this->extractors->class->setNamespace($namespace);
106
                    $this->extractors->interface->setNamespace($namespace);
107
                    break;
108
109
                case T_INTERFACE:
110
                    $class = $this->extractors->interface->extract($n, $tokens);
111
                    $class->setNameResolver($nameResolver);
112
                    // push class AND in global AND in local class map
113
                    $this->result->pushClass($class);
114
                    $result->pushClass($class);
115
                    break;
116
117
                case T_EXTENDS:
118
                    $i = $n;
119
                    $parent = $this->searcher->getFollowingName($i, $tokens);
120
                    $class->setParent(trim($parent));
121
                    break;
122
123
                case T_IMPLEMENTS:
124
                    $i = $n + 1;
125
                    $contracts = $this->searcher->getUnder(array('{'), $i, $tokens);
126
                    $contracts = explode(',', $contracts);
127
                    $contracts = array_map('trim', $contracts);
128
                    $class->setInterfaces($contracts);
129
                    break;
130
131
                case T_CLASS:
132
                    $c = $this->extractors->class->extract($n, $tokens);
133
                    $c->setNameResolver($nameResolver);
134
                    // push class AND in global AND in local class map
135
                    $this->result->pushClass($c);
136
                    $result->pushClass($c);
137
138
                    // PHP 7 and inner classes
139
                    if($c instanceof ReflectedAnonymousClass) {
140
                        // avoid to consider anonymous class as main class
141
                        $p = $n;
142
                        $endAnonymous = $this->searcher->getPositionOfClosingBrace($p, $tokens);
143
                        $mainContextClass = $class;
144
145
                        // add anonymous class in method
146
                        if($method) {
147
                            $method->pushAnonymousClass($c);
148
                        }
149
                    }
150
                    $class = $c;
151
                    break;
152
153
                case T_FUNCTION:
154
                    if($class) {
155
                        // avoid closure
156
                        $next = $tokens[$n + 1];
157
                        if(T_WHITESPACE != $next->getType()) {
158
                            continue;
159
                        }
160
                        $method = $this->extractors->method->extract($n, $tokens, $class);
161
                        $method->setNamespace($namespace);
162
                        $class->pushMethod($method);
163
                    }
164
                    break;
165
            }
166
167
        }
168
        return $result;
169
    }
170
171
};