Completed
Push — develop ( e58221...7a35e1 )
by Jaap
08:17 queued 01:05
created

MethodDescriptor   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 291
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 6

Test Coverage

Coverage 56.67%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 291
ccs 51
cts 90
cp 0.5667
rs 8.295
c 1
b 0
f 0
wmc 42
lcom 2
cbo 6

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A setParent() 0 11 1
A getParent() 0 4 1
A setAbstract() 0 4 1
A isAbstract() 0 4 1
A setFinal() 0 4 1
A isFinal() 0 4 1
A setStatic() 0 4 1
A isStatic() 0 4 1
A setVisibility() 0 4 1
A getVisibility() 0 4 1
A setArguments() 0 7 2
A addArgument() 0 5 1
A getArguments() 0 4 1
A getResponse() 0 16 3
A getFile() 0 4 1
A getReturn() 0 15 3
A getParam() 0 15 4
C getInheritedElement() 0 48 15
A setReturnType() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like MethodDescriptor 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 MethodDescriptor, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Descriptor;
13
use phpDocumentor\Descriptor\Tag\ReturnDescriptor;
14
use phpDocumentor\Reflection\Type;
15
16
/**
17
 * Descriptor representing a Method in a Class, Interface or Trait.
18
 */
19
class MethodDescriptor extends DescriptorAbstract implements Interfaces\MethodInterface, Interfaces\VisibilityInterface
20
{
21
    /** @var ClassDescriptor|InterfaceDescriptor|TraitDescriptor $parent */
22
    protected $parent;
23
24
    /** @var bool $abstract */
25
    protected $abstract = false;
26
27
    /** @var bool $final */
28
    protected $final = false;
29
30
    /** @var bool $static */
31
    protected $static = false;
32
33
    /** @var string $visibility */
34
    protected $visibility = 'public';
35
36
    /** @var Collection */
37
    protected $arguments;
38
39
    /** @var Type */
40 1
    private $returnType;
41
42 1
    /**
43
     * Initializes the all properties representing a collection with a new Collection object.
44 1
     */
45 1
    public function __construct()
46
    {
47
        parent::__construct();
48
49
        $this->setArguments(new Collection());
50
    }
51
52
    /**
53
     * @param ClassDescriptor|InterfaceDescriptor|TraitDescriptor $parent
54
     */
55
    public function setParent($parent)
56
    {
57
        $this->setFullyQualifiedStructuralElementName(
58
            $parent->getFullyQualifiedStructuralElementName() . '::' . $this->getName() . '()'
59
        );
60
61
        // reset cached inherited element so that it can be re-detected.
62
        $this->inheritedElement = null;
63
64
        $this->parent = $parent;
65
    }
66
67
    /**
68
     * @return ClassDescriptor|InterfaceDescriptor|TraitDescriptor
69
     */
70
    public function getParent()
71
    {
72
        return $this->parent;
73 1
    }
74
75 1
    /**
76 1
     * {@inheritDoc}
77
     */
78
    public function setAbstract($abstract)
79
    {
80
        $this->abstract = $abstract;
81 1
    }
82
83 1
    /**
84
     * {@inheritDoc}
85
     */
86
    public function isAbstract()
87
    {
88
        return $this->abstract;
89 1
    }
90
91 1
    /**
92 1
     * {@inheritDoc}
93
     */
94
    public function setFinal($final)
95
    {
96
        $this->final = $final;
97 1
    }
98
99 1
    /**
100
     * {@inheritDoc}
101
     */
102
    public function isFinal()
103
    {
104
        return $this->final;
105 1
    }
106
107 1
    /**
108 1
     * {@inheritDoc}
109
     */
110
    public function setStatic($static)
111
    {
112
        $this->static = $static;
113 1
    }
114
115 1
    /**
116
     * {@inheritDoc}
117
     */
118
    public function isStatic()
119
    {
120
        return $this->static;
121 1
    }
122
123 1
    /**
124 1
     * {@inheritDoc}
125
     */
126
    public function setVisibility($visibility)
127
    {
128
        $this->visibility = $visibility;
129 1
    }
130
131 1
    /**
132
     * {@inheritDoc}
133
     */
134
    public function getVisibility()
135
    {
136
        return $this->visibility;
137 1
    }
138
139 1
    /**
140
     * {@inheritDoc}
141
     */
142 1
    public function setArguments(Collection $arguments)
143 1
    {
144
        foreach( $arguments as $argument) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FOREACH keyword; 0 found
Loading history...
Coding Style introduced by
Space found after opening bracket of FOREACH loop
Loading history...
145
            $argument->setMethod($this);
146
        }
147
        $this->arguments = $arguments;
148
    }
149
150
    /**
151
     * @param string $name
152
     * @param ArgumentDescriptor $argument
153
     */
154
    public function addArgument($name, ArgumentDescriptor $argument)
155
    {
156
        $argument->setMethod($this);
157
        $this->arguments->set($name, $argument);
158 1
    }
159
160 1
    /**
161
     * {@inheritDoc}
162
     */
163
    public function getArguments()
164
    {
165
        return $this->arguments;
166 1
    }
167
168
    /**
169 1
     * @return ReturnDescriptor
170
     */
171 1
    public function getResponse(): ReturnDescriptor
172 1
    {
173 1
        $definedReturn = new ReturnDescriptor('return');
174
        $definedReturn->setTypes($this->returnType);
175
176
        /** @var Collection|null $returnTags */
177
        $returnTags = $this->getReturn();
178
179
        if ($returnTags instanceof Collection && $returnTags->count() > 0) {
180
            /** @var ReturnDescriptor $returnTag */
181 1
            $returnTag = current($returnTags->getAll());
182
            return $returnTag;
183 1
        }
184
185
        return $definedReturn;
186
    }
187
188
    /**
189 1
     * Returns the file associated with the parent class, interface or trait.
190
     *
191
     * @return FileDescriptor
192 1
     */
193 1
    public function getFile()
194 1
    {
195
        return $this->getParent()->getFile();
196
    }
197 1
198 1
    /**
199 1
     * @return Collection
200
     */
201
    public function getReturn()
202
    {
203
        /** @var Collection $var */
204
        $var = $this->getTags()->get('return', new Collection());
205
        if ($var->count() != 0) {
206
            return $var;
207
        }
208 1
209
        $inheritedElement = $this->getInheritedElement();
210
        if ($inheritedElement) {
211 1
            return $inheritedElement->getReturn();
212 1
        }
213 1
214
        return new Collection();
215
    }
216 1
217 1
    /**
218 1
     * @return Collection
219
     */
220
    public function getParam()
221
    {
222
        /** @var Collection $var */
223
        $var = $this->getTags()->get('param', new Collection());
224
        if ($var instanceof Collection && $var->count() > 0) {
225
            return $var;
226
        }
227
228
        $inheritedElement = $this->getInheritedElement();
229
        if ($inheritedElement) {
230
            return $inheritedElement->getParam();
231
        }
232
233
        return new Collection();
234
    }
235
236
    /**
237
     * Returns the Method from which this method should inherit its information, if any.
238
     *
239
     * The inheritance scheme for a method is more complicated than for most elements; the following business rules
240
     * apply:
241
     *
242
     * 1. if the parent class/interface extends another class or other interfaces (interfaces have multiple
243
     *    inheritance!) then:
244
     *    1. Check each parent class/interface's parent if they have a method with the exact same name
245
     *    2. if a method is found with the same name; return the first one encountered.
246
     * 2. if the parent is a class and implements interfaces, check each interface for a method with the exact same
247
     *    name. If such a method is found, return the first hit.
248
     *
249
     * @return MethodDescriptor|null
250
     */
251
    public function getInheritedElement()
252
    {
253
        if ($this->inheritedElement !== null) {
254
            return $this->inheritedElement;
255
        }
256
257
        /** @var ClassDescriptor|InterfaceDescriptor|null $associatedClass */
258
        $associatedClass = $this->getParent();
259
        if (!$associatedClass instanceof ClassDescriptor && !$associatedClass instanceof InterfaceDescriptor) {
260
            return null;
261
        }
262
263
        /** @var ClassDescriptor|InterfaceDescriptor $parentClass|null */
264
        $parentClass = $associatedClass->getParent();
265
        if ($parentClass instanceof ClassDescriptor || $parentClass instanceof Collection) {
266
            // the parent of a class is always a class, but the parent of an interface is a collection of interfaces.
267
            $parents = $parentClass instanceof ClassDescriptor ? array($parentClass) : $parentClass->getAll();
268
            foreach ($parents as $parent) {
269
                if ($parent instanceof ClassDescriptor || $parent instanceof InterfaceDescriptor) {
270
                    $parentMethod = $parent->getMethods()->get($this->getName());
271
                    if ($parentMethod) {
272
                        $this->inheritedElement = $parentMethod;
273
274
                        return $this->inheritedElement;
275
                    }
276
                }
277
            }
278
        }
279
280
        // also check all implemented interfaces next if the parent is a class and not an interface
281
        if ($associatedClass instanceof ClassDescriptor) {
282
            /** @var InterfaceDescriptor $interface */
283
            foreach ($associatedClass->getInterfaces() as $interface) {
284
                if (!$interface instanceof InterfaceDescriptor) {
285
                    continue;
286
                }
287
288
                $parentMethod = $interface->getMethods()->get($this->getName());
289
                if ($parentMethod) {
290
                    $this->inheritedElement = $parentMethod;
291
292
                    return $this->inheritedElement;
293
                }
294
            }
295
        }
296
297
        return null;
298
    }
299
300
    /**
301
     * Sets return type of this method.
302
     *
303
     * @param Type $returnType
304
     */
305
    public function setReturnType(Type $returnType)
306
    {
307
        $this->returnType = $returnType;
308
    }
309
}
310