Passed
Push — master ( 1fb040...5fddea )
by Satoshi
02:25
created

FullyQualifiedStructuralElementName   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 188
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 86
dl 0
loc 188
rs 8.64
c 0
b 0
f 0
wmc 47

19 Methods

Rating   Name   Duplication   Size   Complexity  
A isName() 0 3 1
A isPropertyElement() 0 11 4
A isFullyQualifiedClassElement() 0 19 6
A createProperty() 0 4 1
A createTrait() 0 4 1
A createInterface() 0 4 1
A createClassConstant() 0 4 1
A isClassConstantElement() 0 10 3
A createConstant() 0 4 1
A createClass() 0 3 1
A createFromReflection() 0 15 6
B createFromString() 0 17 7
A createNamespace() 0 3 1
A formatName() 0 3 2
A isMethodElement() 0 11 4
A createMethod() 0 4 1
A createFunction() 0 4 1
A isFunctionElement() 0 4 2
A isNamespaceElement() 0 9 3

How to fix   Complexity   

Complex Class

Complex classes like FullyQualifiedStructuralElementName 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.

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

1
<?php
2
declare(strict_types=1);
3
4
namespace DependencyAnalyzer\DependencyGraph;
5
6
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Base;
7
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Class_;
8
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\ClassConstant;
9
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Constant;
10
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Function_;
11
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Interface_;
12
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Method;
13
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Namespace_;
14
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Property;
15
use DependencyAnalyzer\DependencyGraph\FullyQualifiedStructuralElementName\Trait_;
16
use DependencyAnalyzer\Exceptions\InvalidFullyQualifiedStructureElementNameException;
17
use DependencyAnalyzer\Exceptions\InvalidReflectionException;
18
19
class FullyQualifiedStructuralElementName
20
{
21
    const TYPE_NAMESPACE = 'namespace';
22
    const TYPE_CLASS = 'class';
23
    const TYPE_METHOD = 'method';
24
    const TYPE_PROPERTY = 'property';
25
    const TYPE_CLASS_CONSTANT = 'class_constant';
26
    const TYPE_INTERFACE = 'interface';
27
    const TYPE_TRAIT = 'trait';
28
    const TYPE_FUNCTION = 'function';
29
    const TYPE_CONSTANT = 'constant';
30
31
    public static function createFromString(string $element): Base
32
    {
33
        if (self::isNamespaceElement($element)) {
34
            return new Namespace_($element);
35
        } elseif (self::isMethodElement($element)) {
36
            return new Method($element);
37
        } elseif (self::isPropertyElement($element)) {
38
            return new Property($element);
39
        } elseif (self::isClassConstantElement($element)) {
40
            return new ClassConstant($element);
41
        } elseif (self::isFunctionElement($element)) {
42
            return new Function_($element);
43
        } elseif (self::isFullyQualifiedClassElement($element)) {
44
            return new Class_($element);
45
        }
46
47
        throw new InvalidFullyQualifiedStructureElementNameException($element);
48
    }
49
50
    protected static function isNamespaceElement(string $element): bool
51
    {
52
        if ($element === '\\') {
53
            return true;
54
        }
55
56
        // TODO: This is my original definition...
57
        return substr($element, -1) === '\\' &&
58
            self::isFullyQualifiedClassElement(substr($element, 0, -1));
59
    }
60
61
    protected static function isMethodElement(string $element): bool
62
    {
63
        if (strpos($element, '::') === false) {
64
            return false;
65
        }
66
67
        list($fqcn, $method) = explode('::', $element, 2);
68
69
        return self::isFullyQualifiedClassElement($fqcn) &&
70
            substr($method, -2) === '()' &&
71
            self::isName(substr($method, 0, -2));
72
    }
73
74
    protected static function isPropertyElement(string $element): bool
75
    {
76
        if (strpos($element, '::') === false) {
77
            return false;
78
        }
79
80
        list($fqcn, $property) = explode('::', $element, 2);
81
82
        return self::isFullyQualifiedClassElement($fqcn) &&
83
            substr($property, 0, 1) === '$' &&
84
            self::isName(substr($property, 1));
85
    }
86
87
    protected static function isClassConstantElement(string $element): bool
88
    {
89
        if (strpos($element, '::') === false) {
90
            return false;
91
        }
92
93
        list($fqcn, $constant) = explode('::', $element, 2);
94
95
        return self::isFullyQualifiedClassElement($fqcn) &&
96
            self::isName($constant);
97
    }
98
99
    protected static function isFunctionElement(string $element): bool
100
    {
101
        return substr($element, -2) === '()' &&
102
            self::isFullyQualifiedClassElement(substr($element, 0, -2));
103
    }
104
105
    protected static function isFullyQualifiedClassElement(string $element): bool
106
    {
107
        if (substr($element, 0, 1) !== '\\') {
108
            return false;
109
        }
110
111
        $names = explode('\\', $element);
112
        if (array_shift($names) !== '') {
113
            return false;
114
        } elseif (count($names) <= 0) {
115
            return false;
116
        }
117
        foreach ($names as $name) {
118
            if (!self::isName($name)) {
119
                return false;
120
            }
121
        }
122
123
        return true;
124
    }
125
126
    protected static function isName(string $element): bool
127
    {
128
        return preg_match('/^[a-zA-Z\_][0-9a-zA-Z\_]+$/', $element) === 1;
129
    }
130
131
    public static function createNamespace(string $namespaceName): Namespace_
132
    {
133
        return new Namespace_(self::formatName($namespaceName));
134
    }
135
136
    public static function createClass(string $className): Class_
137
    {
138
        return new Class_(self::formatName($className));
139
    }
140
141
    public static function createMethod(string $className, string $methodName): Method
142
    {
143
        $className = self::formatName($className);
144
        return new Method("{$className}::{$methodName}()");
145
    }
146
147
    public static function createProperty(string $className, string $propertyName): Property
148
    {
149
        $className = self::formatName($className);
150
        return new Property("{$className}::\${$propertyName}");
151
    }
152
153
    public static function createClassConstant(string $className, string $constantName): ClassConstant
154
    {
155
        $className = self::formatName($className);
156
        return new ClassConstant("{$className}::{$constantName}");
157
    }
158
159
    public static function createInterface(string $interfaceName): Interface_
160
    {
161
        $interfaceName = self::formatName($interfaceName);
162
        return new Interface_($interfaceName);
163
    }
164
165
    public static function createTrait(string $traitName): Trait_
166
    {
167
        $traitName = self::formatName($traitName);
168
        return new Trait_($traitName);
169
    }
170
171
    public static function createFunction(string $functionName): Function_
172
    {
173
        $functionName = self::formatName($functionName);
174
        return new Function_("{$functionName}()");
175
    }
176
177
    public static function createConstant(string $constantName): Constant
178
    {
179
        $constantName = self::formatName($constantName);
180
        return new Constant("{$constantName}");
181
    }
182
183
    /**
184
     * @param \ReflectionClass|\ReflectionMethod|\ReflectionProperty|\ReflectionClassConstant|\ReflectionFunction $reflection
185
     * @return Base
186
     */
187
    public static function createFromReflection($reflection): Base
188
    {
189
        if ($reflection instanceof \ReflectionClass) {
190
            return self::createClass($reflection->getName());
191
        } elseif ($reflection instanceof \ReflectionMethod) {
192
            return self::createMethod($reflection->getDeclaringClass()->getName(), $reflection->getName());
193
        } elseif ($reflection instanceof \ReflectionProperty) {
194
            return self::createProperty($reflection->getDeclaringClass()->getName(), $reflection->getName());
195
        } elseif ($reflection instanceof \ReflectionClassConstant) {
196
            return self::createClassConstant($reflection->getDeclaringClass()->getName(), $reflection->getName());
197
        } elseif ($reflection instanceof \ReflectionFunction) {
0 ignored issues
show
introduced by
$reflection is always a sub-type of ReflectionFunction.
Loading history...
198
            return self::createFunction($reflection->getName());
199
        }
200
201
        throw new InvalidReflectionException($reflection);
202
    }
203
204
    protected static function formatName(string $className): string
205
    {
206
        return substr($className, 0, 1) === '\\' ? $className : "\\{$className}";
207
    }
208
}
209