AbstractStructureParser   F
last analyzed

Complexity

Total Complexity 84

Size/Duplication

Total Lines 366
Duplicated Lines 10.66 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 84
lcom 1
cbo 4
dl 39
loc 366
rs 2
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
B getConstants() 0 33 10
C getDefinition() 8 38 13
A getDefinitionListFromFile() 0 23 4
A getName() 0 19 6
B getNamespace() 11 24 8
A getStructureToken() 0 25 5
A isStructureToken() 0 8 5
D getStructureTokens() 8 59 18
B getUsedStructures() 12 30 9
B resolveUsedNamespace() 0 26 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractStructureParser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractStructureParser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * \AppserverIo\Doppelgaenger\Parser\AbstractStructureParser
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Bernhard Wick <[email protected]>
15
 * @copyright 2015 TechDivision GmbH - <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/doppelgaenger
18
 * @link      http://www.appserver.io/
19
 */
20
21
namespace AppserverIo\Doppelgaenger\Parser;
22
23
use AppserverIo\Doppelgaenger\Entities\Lists\StructureDefinitionList;
24
use AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface;
25
use AppserverIo\Doppelgaenger\Interfaces\StructureParserInterface;
26
use AppserverIo\Doppelgaenger\Entities\Definitions\FileDefinition;
27
28
/**
29
 * The abstract class AbstractStructureParser which provides a basic implementation other structure parsers
30
 * can inherit from
31
 *
32
 * @author    Bernhard Wick <[email protected]>
33
 * @copyright 2015 TechDivision GmbH - <[email protected]>
34
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
35
 * @link      https://github.com/appserver-io/doppelgaenger
36
 * @link      http://www.appserver.io/
37
 */
38
abstract class AbstractStructureParser extends AbstractParser implements StructureParserInterface
39
{
40
41
    /**
42
     * Will return the constants within the main token array
43
     *
44
     * @return array
45
     */
46
    public function getConstants()
47
    {
48
        // Check the tokens
49
        $constants = array();
50
        for ($i = 0; $i < $this->tokenCount; $i++) {
51
            // If we got the class name
52
            if ($this->tokens[$i][0] === T_CONST) {
53
                for ($j = $i + 1; $j < $this->tokenCount; $j++) {
54
                    if ($this->tokens[$j] === ';') {
55
                        break;
56
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
57
                    } elseif ($this->tokens[$j][0] === T_STRING) {
58
                        $constants[$this->tokens[$j][1]] = '';
59
60
                        for ($k = $j + 1; $k < count($this->tokens); $k++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
61
                            if ($this->tokens[$k] === ';') {
62
                                break;
63
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
64
                            } elseif (is_array($this->tokens[$k]) && $this->tokens[$k][0] !== '=') {
65
                                $constants[$this->tokens[$j][1]] .= $this->tokens[$k][1];
66
                            }
67
                        }
68
69
                        // Now trim what we got
70
                        $constants[$this->tokens[$j][1]] = trim($constants[$this->tokens[$j][1]]);
71
                    }
72
                }
73
            }
74
        }
75
76
        // Return what we did or did not found
77
        return $constants;
78
    }
79
80
    /**
81
     * Will return the definition of a specified structure
82
     *
83
     * @param null|string $name         The name of the class we are searching for
84
     * @param boolean     $getRecursive Do we have to get the ancestral conditions as well?
85
     *
86
     * @return boolean|\AppserverIo\Doppelgaenger\Interfaces\StructureDefinitionInterface
87
     */
88
    public function getDefinition($name = null, $getRecursive = true)
89
    {
90
        // Maybe we already got this structure?
91
        if ($this->structureDefinitionHierarchy->entryExists($name)) {
92
            return $this->structureDefinitionHierarchy->getEntry($name);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->structureD...archy->getEntry($name); (boolean) is incompatible with the return type declared by the interface AppserverIo\Doppelgaenge...nterface::getDefinition of type AppserverIo\Doppelgaenge...tureDefinitionInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
93
        }
94
95
        // First of all we need to get the structure tokens
96
        $tokens = $this->getStructureTokens($this->getToken());
97
98
        // Did we get something valuable?
99
        if ($tokens === false) {
100
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface AppserverIo\Doppelgaenge...nterface::getDefinition of type AppserverIo\Doppelgaenge...tureDefinitionInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
101
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
102
        } elseif ($name === null && count($tokens) > 1) {
103
            // If we did not get a structure name and we got more than one class we can fail right here
104
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface AppserverIo\Doppelgaenge...nterface::getDefinition of type AppserverIo\Doppelgaenge...tureDefinitionInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
105
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
106
        } elseif (count($tokens) === 1) {
107
            // We got what we came for
108
            return $this->getDefinitionFromTokens($tokens[0], $getRecursive);
0 ignored issues
show
Bug introduced by
The method getDefinitionFromTokens() does not exist on AppserverIo\Doppelgaenge...AbstractStructureParser. Did you maybe mean getDefinition()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
109
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
110
        } elseif (is_string($name) && count($tokens) > 1) {
111
            // We are still here, but got a structure name to look for
112
113 View Code Duplication
            foreach ($tokens as $key => $token) {
114
                // Now iterate over the array and search for the class we want
115
                for ($i = 0; $i < count($token); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
116
                    if (is_array($token[$i]) && $token[$i] === $this->getToken() && $token[$i + 2] === $name) {
117
                        return $this->getDefinitionFromTokens($tokens[$key], $getRecursive);
0 ignored issues
show
Bug introduced by
The method getDefinitionFromTokens() does not exist on AppserverIo\Doppelgaenge...AbstractStructureParser. Did you maybe mean getDefinition()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
118
                    }
119
                }
120
            }
121
        }
122
123
        // Still here? Must be an error.
124
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface AppserverIo\Doppelgaenge...nterface::getDefinition of type AppserverIo\Doppelgaenge...tureDefinitionInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
125
    }
126
127
    /**
128
     * Will return a list of found structures or false on error
129
     *
130
     * @param string         $file           Path of the file we are searching in
131
     * @param FileDefinition $fileDefinition Definition of the file the class is in
132
     * @param boolean        $getRecursive   Do we have to get the ancestral conditions as well?
133
     *
134
     * @return boolean|StructureDefinitionList
135
     */
136
    public function getDefinitionListFromFile($file, FileDefinition $fileDefinition, $getRecursive = true)
137
    {
138
        // Get all the token arrays for the different classes
139
        $tokens = $this->getStructureTokens($file, $this->getToken());
0 ignored issues
show
Unused Code introduced by
The call to AbstractStructureParser::getStructureTokens() has too many arguments starting with $this->getToken().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
140
141
        // Did we get the right thing?
142
        if (!is_array($tokens)) {
143
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface AppserverIo\Doppelgaenge...tDefinitionListFromFile of type AppserverIo\Doppelgaenge...StructureDefinitionList.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
144
        }
145
146
        $structureDefinitionList = new StructureDefinitionList();
147
        foreach ($tokens as $token) {
148
            try {
149
                $structureDefinitionList->add($this->getDefinitionFromTokens($token, $fileDefinition, $getRecursive));
0 ignored issues
show
Bug introduced by
The method getDefinitionFromTokens() does not exist on AppserverIo\Doppelgaenge...AbstractStructureParser. Did you maybe mean getDefinition()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
150
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
151
            } catch (\UnexpectedValueException $e) {
152
                // Just try the next one
153
                continue;
154
            }
155
        }
156
157
        return $structureDefinitionList;
158
    }
159
160
    /**
161
     * Get the name of the structure
162
     *
163
     * @param array $tokens The token array
164
     *
165
     * @return string
166
     */
167
    protected function getName($tokens)
168
    {
169
        // Check the tokens
170
        $name = '';
171
        $targetToken = $this->getToken();
172
        for ($i = 0; $i < count($tokens); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
173
            // If we got the structure name
174
            if ($tokens[$i][0] === $targetToken && $tokens[$i - 1][0] !== T_PAAMAYIM_NEKUDOTAYIM) {
175
                for ($j = $i + 1; $j < count($tokens); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
176
                    if ($tokens[$j] === '{') {
177
                        $name = $tokens[$i + 2][1];
178
                    }
179
                }
180
            }
181
        }
182
183
        // Return what we did or did not found
184
        return $name;
185
    }
186
187
    /**
188
     * Will return the structure's namespace if found
189
     *
190
     * @return string
191
     */
192
    public function getNamespace()
193
    {
194
        // Check the tokens
195
        $namespace = '';
196
        for ($i = 0; $i < $this->tokenCount; $i++) {
197
            // If we got the namespace
198
            if ($this->tokens[$i][0] === T_NAMESPACE) {
199 View Code Duplication
                for ($j = $i + 1; $j < count($this->tokens); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
200
                    if ($this->tokens[$j][0] === T_STRING) {
201
                        $namespace .= '\\' . $this->tokens[$j][1];
202
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
203
                    } elseif ($this->tokens[$j] === '{' ||
204
                        $this->tokens[$j] === ';' ||
205
                        $this->tokens[$j][0] === T_CURLY_OPEN
206
                    ) {
207
                        break;
208
                    }
209
                }
210
            }
211
        }
212
213
        // Return what we did or did not found
214
        return substr($namespace, 1);
215
    }
216
217
    /**
218
     * Will check the main token array for the occurrence of a certain on (class, interface or trait)
219
     *
220
     * @return string|boolean
221
     */
222
    protected function getStructureToken()
223
    {
224
        for ($i = 0; $i < $this->tokenCount; $i++) {
225
            switch ($this->tokens[$i][0]) {
226
                case T_CLASS:
227
                    return 'class';
228
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
229
230
                case T_INTERFACE:
231
                    return 'interface';
232
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
233
234
                case T_TRAIT:
235
                    return 'trait';
236
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
237
238
                default:
239
                    continue;
240
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
241
            }
242
        }
243
244
        // We are still here? That should not be.
245
        return false;
246
    }
247
248
    /**
249
     * Will check if a certain token describes a structure
250
     *
251
     * @param mixed $token The token to test
252
     *
253
     * @return boolean
254
     */
255
    protected function isStructureToken($token)
256
    {
257
        if (is_array($token) && ($token[0] === T_CLASS || $token[0] === T_INTERFACE || $token[0] === T_TRAIT)) {
258
            return true;
259
        }
260
        // We are still here? That should not be.
261
        return false;
262
    }
263
264
    /**
265
     * Will return a subset of our main token array. This subset includes all tokens belonging to a certain structure.
266
     * Might return false on failure
267
     *
268
     * @param integer $structureToken The structure we are after e.g. T_CLASS, use PHP tokens here
269
     *
270
     * @return array|boolean
271
     */
272
    protected function getStructureTokens($structureToken)
273
    {
274
        // Now iterate over the array and filter different classes from it
275
        $result = array();
276
        for ($i = 0; $i < $this->tokenCount; $i++) {
277
            // If we got a class keyword, we have to check how far the class extends,
278
            // then copy the array withing that bounds
279
280
            if (is_array($this->tokens[$i]) && $this->tokens[$i][0] === $structureToken && $this->tokens[$i - 1][0] !== T_PAAMAYIM_NEKUDOTAYIM) {
281
                // The lower bound should be the last semicolon|closing curly bracket|PHP tag before the structure
282
                $lowerBound = 0;
283
                for ($j = $i - 1; $j >= 0; $j--) {
284
                    if ($this->tokens[$j] === ';' || $this->tokens[$j] === '}' ||
285
                        is_array($this->tokens[$j]) && $this->tokens[$j][0] === T_OPEN_TAG
286
                    ) {
287
                        $lowerBound = $j;
288
                        break;
289
                    }
290
                }
291
292
                // The upper bound should be the first time the curly brackets are even again
293
                $upperBound = $this->tokenCount - 1;
294
                $bracketCounter = null;
295
                for ($j = $i + 1; $j < count($this->tokens); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
296
                    if ($this->tokens[$j] === '{' || $this->tokens[$j][0] === T_CURLY_OPEN) {
297
                        // If we still got null set to 0
298
                        if ($bracketCounter === null) {
299
                            $bracketCounter = 0;
300
                        }
301
302
                        $bracketCounter++;
303
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
304 View Code Duplication
                    } elseif ($this->tokens[$j] === '}') {
305
                        // If we still got null set to 0
306
                        if ($bracketCounter === null) {
307
                            $bracketCounter = 0;
308
                        }
309
310
                        $bracketCounter--;
311
                    }
312
313
                    // Do we have an even amount of brackets yet?
314
                    if ($bracketCounter === 0) {
315
                        $upperBound = $j;
316
                        break;
317
                    }
318
                }
319
320
                $result[] = array_slice($this->tokens, $lowerBound, $upperBound - $lowerBound);
321
            }
322
        }
323
324
        // Last line of defence; did we get something?
325
        if (empty($result)) {
326
            return false;
327
        }
328
329
        return $result;
330
    }
331
332
    /**
333
     * Will return an array of structures which this structure references by use statements
334
     *
335
     * @return array
336
     */
337
    public function getUsedStructures()
338
    {
339
        // Check the tokens
340
        $structures = array();
341
        for ($i = 0; $i < $this->tokenCount; $i++) {
342
            // break as soon as we pass a structure keyword as "use" imports must be globally
343
            if ($this->isStructureToken($this->tokens[$i])) {
344
                break;
345
            }
346
            // if we got a use statement
347
            if ($this->tokens[$i][0] === T_USE) {
348
                $structure = '';
349 View Code Duplication
                for ($j = $i + 1; $j < count($this->tokens); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
350
                    if ($this->tokens[$j][0] === T_STRING) {
351
                        $structure .= '\\' . $this->tokens[$j][1];
352
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
353
                    } elseif ($this->tokens[$j] === '{' ||
354
                        $this->tokens[$j] === ';' ||
355
                        $this->tokens[$j][0] === T_CURLY_OPEN
356
                    ) {
357
                        $structures[] = $structure;
358
                        break;
359
                    }
360
                }
361
            }
362
        }
363
364
        // Return what we did or did not found
365
        return $structures;
366
    }
367
368
    /**
369
     * Will check if a certain structure was mentioned in one(!) use statement.
370
     *
371
     * @param StructureDefinitionInterface $structureDefinition The structure $structureName is compared against
372
     * @param string                       $structureName       The name of the structure we have to check against the
373
     *                                                          use statements of the definition
374
     *
375
     * @return string
376
     */
377
    protected function resolveUsedNamespace(StructureDefinitionInterface & $structureDefinition, $structureName)
378
    {
379
        // If there was no useful name passed we can fail right here
380
        if (empty($structureName)) {
381
            return '';
382
        }
383
384
        // Walk over all namespaces and if we find something we will act accordingly.
385
        $result = $structureDefinition->getQualifiedName();
386
        foreach ($structureDefinition->getUsedStructures() as $key => $usedStructures) {
387
            // Check if the last part of the use statement is our structure
388
            $tmp = explode('\\', $usedStructures);
389
            if (array_pop($tmp) === $structureName) {
390
                // Tell them we succeeded
391
                return trim(implode('\\', $tmp) . '\\' . $structureName, '\\');
392
            }
393
        }
394
395
        // We did not seem to have found anything. Might it be that we are in our own namespace?
396
        if ($structureDefinition->getNamespace() !== null && strpos($structureName, '\\') !== 0) {
397
            return $structureDefinition->getNamespace() . '\\' . $structureName;
398
        }
399
400
        // Still here? Return what we got.
401
        return $result;
402
    }
403
}
404