TraitUseTrait   B
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 285
Duplicated Lines 8.07 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 77.23%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 41
c 2
b 0
f 1
lcom 1
cbo 5
dl 23
loc 285
rs 8.2769
ccs 78
cts 101
cp 0.7723

16 Methods

Rating   Name   Duplication   Size   Complexity  
getIndex() 0 1 ?
A getTraits() 0 12 3
A getTraitNames() 0 4 1
B getAllTraits() 0 14 5
A getAllTraitNames() 0 10 2
A getSelfTraits() 18 18 4
B getTraitsProperties() 5 17 5
B getTraitsMethods() 0 20 6
A getTraitAliases() 0 10 2
A getTraitMethodAlias() 0 4 1
A getTraitMethodPrecedences() 0 4 1
A getAliasedMethodName() 0 10 4
A isReplacedByPrecedence() 0 10 4
A addTrait() 0 6 1
A addTraitMethodAlias() 0 10 1
A addTraitMethodPrecedences() 0 10 1

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 TraitUseTrait 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 TraitUseTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Benoth\StaticReflection\Reflection\Parts;
4
5
use Benoth\StaticReflection\Reflection\ReflectionClass;
6
use Benoth\StaticReflection\Reflection\ReflectionTrait;
7
use Benoth\StaticReflection\ReflectionsIndex;
8
9
trait TraitUseTrait
10
{
11
    protected $traits                  = [];
12
    protected $traitsMethodAliases     = [];
13
    protected $traitsMethodPrecedences = [];
14
15
    /**
16
     * Must be implemented by classes using this trait
17
     */
18
    abstract public function getIndex();
19
20
    /**
21
     * Returns an array of traits used by this class, without traits inherited from parents.
22
     *
23
     * Note that getTraits will NOT return any traits inherited from a parent.
24
     * This is currently viewed as the desired behavior.
25
     *
26
     * @see http://php.net/manual/en/reflectionclass.gettraits.php#116513
27
     * @see self::getAllTraits()
28
     *
29
     * @return ReflectionTrait[]
30
     */
31 579
    public function getTraits()
32
    {
33 579
        $traits = $this->getSelfTraits();
34
35 579
        foreach ($traits as $trait) {
36 192
            foreach ($trait->getTraits() as $parentTrait) {
37 192
                $traits[$parentTrait->getName()] = $parentTrait;
38 192
            }
39 579
        }
40
41 579
        return $traits;
42
    }
43
44
    /**
45
     * Returns an array of names of traits used by this class, without traits inherited from parents.
46
     *
47
     * This return only the trait names from the current class
48
     *
49
     * @see http://php.net/manual/en/reflectionclass.gettraitnames.php#113785
50
     * @see self::getAllTraitNames()
51
     *
52
     * @return string[]
53
     */
54
    public function getTraitNames()
55
    {
56
        return $this->traits;
57
    }
58
59
    /**
60
     * Returns an array of traits used by this class, with traits inherited from parents.
61
     *
62
     * @return ReflectionTrait[]
63
     */
64 579
    public function getAllTraits()
65
    {
66 579
        $traits = $this->getTraits();
67
68 579
        if ($this instanceof ReflectionClass && $this->getParentClass() instanceof ReflectionClass) {
69 192
            foreach ($this->getParentClass()->getAllTraits() as $trait) {
70
                if (!array_key_exists($trait->getName(), $traits)) {
71
                    $traits[$trait->getName()] = $trait;
72
                }
73 192
            }
74 192
        }
75
76 579
        return $traits;
77
    }
78
79
    /**
80
     * Returns an array of names of traits used by this class, with traits inherited from parents.
81
     *
82
     * @return string[]
83
     */
84
    public function getAllTraitNames()
85
    {
86
        $names = [];
87
88
        foreach ($this->getAllTraits() as $trait) {
89
            $names[] = $trait->getName();
90
        }
91
92
        return $names;
93
    }
94
95
    /**
96
     * Gets the traits, without inherited ones.
97
     *
98
     * @return ReflectionTrait[]
99
     */
100 579 View Code Duplication
    public function getSelfTraits()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

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

Loading history...
101
    {
102 579
        $traits = [];
103
104 579
        if (!$this->getIndex() instanceof ReflectionsIndex) {
105
            return $traits;
106
        }
107
108 579
        foreach ($this->traits as $trait) {
109 192
            $trait = $this->getIndex()->getTrait($trait);
110 192
            if (!$trait instanceof ReflectionTrait) {
111
                continue;
112
            }
113 192
            $traits[$trait->getName()] = $trait;
114 579
        }
115
116 579
        return $traits;
117
    }
118
119
    /**
120
     * Gets an array of properties defined in class traits, with inherited ones.
121
     *
122
     * @return \Benoth\StaticReflection\Reflection\ReflectionProperty[]
123
     */
124 195
    public function getTraitsProperties()
125
    {
126 195
        $properties = [];
127
128 195
        foreach ($this->getAllTraits() as $trait) {
129 78
            if (!$trait instanceof ReflectionTrait) {
130
                continue;
131
            }
132 78 View Code Duplication
            foreach ($trait->getProperties() as $property) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

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

Loading history...
133 78
                if (!array_key_exists($property->getName(), $properties)) {
134 78
                    $properties[$property->getName()] = $property;
135 78
                }
136 78
            }
137 195
        }
138
139 195
        return $properties;
140
    }
141
142
    /**
143
     * Gets an array of methods defined in class traits, including inherited ones.
144
     *
145
     * @return Benoth\StaticReflection\Reflection\ReflectionMethod[]
146
     */
147 387
    public function getTraitsMethods()
148
    {
149 387
        $methods = [];
150
151 387
        foreach ($this->getAllTraits() as $traitName => $trait) {
152 117
            if (!$trait instanceof ReflectionTrait) {
153
                continue;
154
            }
155 117
            foreach ($trait->getMethods() as $method) {
156 117
                $alias = $this->getAliasedMethodName($traitName, $method->getName());
157 117
                if (!$this->isReplacedByPrecedence($traitName, $method->getName())) {
158 117
                    $methods[$alias] = $method;
159 117
                } elseif (!array_key_exists($alias, $methods)) {
160
                    $methods[$alias] = $method;
161
                }
162 117
            }
163 387
        }
164
165 387
        return $methods;
166
    }
167
168
    /**
169
     * Returns an array of trait methods aliases.
170
     *
171
     * @return string[] New method names in keys and original names (in the format "TraitName::original") in values
172
     */
173
    public function getTraitAliases()
174
    {
175
        $aliases = [];
176
177
        foreach ($this->getTraitMethodAlias() as $alias) {
178
            $aliases[$alias['newName']] = $alias['trait'].'::'.$alias['oldName'];
179
        }
180
181
        return $aliases;
182
    }
183
184
    /**
185
     * Returns an array of trait methods aliases.
186
     *
187
     * @return array[] Numeric keys with 3 values associative array : trait (name of the trait), oldName (old method name), newName (new method name)
188
     */
189 117
    public function getTraitMethodAlias()
190
    {
191 117
        return $this->traitsMethodAliases;
192
    }
193
194
    /**
195
     * Returns an array of trait methods precedences.
196
     *
197
     * @return array[] Numeric keys with 3 values associative array : trait (name of the trait used), insteadof (name of the trait replaced), method (method name)
198
     */
199 117
    public function getTraitMethodPrecedences()
200
    {
201 117
        return $this->traitsMethodPrecedences;
202
    }
203
204
    /**
205
     * Gets a method aliased name.
206
     *
207
     * @param string $traitName  Fully Qualified Name of the trait
208
     * @param string $methodName Name of the method
209
     *
210
     * @return string Aliased name or the method original name il no alias found
211
     */
212 117
    public function getAliasedMethodName($traitName, $methodName)
213
    {
214 117
        foreach ($this->getTraitMethodAlias() as $alias) {
215 117
            if ($traitName === $alias['trait'] && $methodName === $alias['oldName']) {
216 117
                return $alias['newName'];
217
            }
218 117
        }
219
220 117
        return $methodName;
221
    }
222
223
    /**
224
     * Check if a method from a trait is replaced by precedence.
225
     *
226
     * @param string $traitName  Fully Qualified Name of the trait
227
     * @param string $methodName
228
     *
229
     * @return bool
230
     */
231 117
    public function isReplacedByPrecedence($traitName, $methodName)
232
    {
233 117
        foreach ($this->getTraitMethodPrecedences() as $precedence) {
234 117
            if ($traitName === $precedence['insteadof'] && $methodName === $precedence['method']) {
235 117
                return true;
236
            }
237 117
        }
238
239 117
        return false;
240
    }
241
242
    /**
243
     * Add a trait use on the current entity.
244
     *
245
     * @param string $trait Fully Qualified Trait Name
246
     *
247
     * @return self
248
     */
249 258
    public function addTrait($trait)
250
    {
251 258
        $this->traits[] = (string) $trait;
252
253 258
        return $this;
254
    }
255
256
    /**
257
     * Add a trait method alias.
258
     *
259
     * @param string $trait   Fully Qualified Name of the trait
260
     * @param string $oldName Old method name
261
     * @param string $newName New method name
262
     *
263
     * @return self
264
     */
265 258
    public function addTraitMethodAlias($trait, $oldName, $newName)
266
    {
267 258
        $this->traitsMethodAliases[] = [
268 258
            'trait'   => (string) $trait,
269 258
            'oldName' => (string) $oldName,
270 258
            'newName' => (string) $newName,
271
        ];
272
273 258
        return $this;
274
    }
275
276
    /**
277
     * Add a trait method precedence.
278
     *
279
     * @param string $trait     Fully Qualified Name of the trait to use
280
     * @param string $insteadof Fully Qualified Name of the replaced trait
281
     * @param string $method    Method name
282
     */
283 258
    public function addTraitMethodPrecedences($trait, $insteadof, $method)
284
    {
285 258
        $this->traitsMethodPrecedences[] = [
286 258
            'trait'     => (string) $trait,
287 258
            'insteadof' => (string) $insteadof,
288 258
            'method'    => (string) $method,
289
        ];
290
291 258
        return $this;
292
    }
293
}
294