PropertyTrait   B
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 220
Duplicated Lines 2.27 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 5
Bugs 3 Features 1
Metric Value
wmc 38
c 5
b 3
f 1
lcom 1
cbo 2
dl 5
loc 220
rs 8.3999
ccs 78
cts 78
cp 1

12 Methods

Rating   Name   Duplication   Size   Complexity  
getName() 0 1 ?
getFileName() 0 1 ?
C getProperties() 5 22 8
A getStaticProperties() 0 4 1
A getSelfProperties() 0 9 2
A getProperty() 0 10 3
A hasProperty() 0 10 3
A getDefaultProperties() 0 9 2
B getStaticPropertyValue() 0 15 5
A setStaticPropertyValue() 0 9 3
A addProperty() 0 8 1
B filterProperties() 0 20 10

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace Benoth\StaticReflection\Reflection\Parts;
4
5
use Benoth\StaticReflection\Reflection\ReflectionClass;
6
use Benoth\StaticReflection\Reflection\ReflectionProperty;
7
8
trait PropertyTrait
9
{
10
    protected $properties = [];
11
12
    /**
13
     * Gets the fully qualified entity name (with the namespace).
14
     *
15
     * Must be implemented by classes using this trait
16
     *
17
     * @return string
18
     */
19
    abstract public function getName();
20
21
22
    /**
23
     * Gets the filename of the file in which the class has been defined.
24
     *
25
     * Must be implemented by classes using this trait.
26
     *
27
     * @return string
28
     */
29
    abstract public function getFileName();
30
31
    /**
32
     * Gets an array of properties, with inherited ones.
33
     *
34
     * @param int $filter Any combination of ReflectionProperty::IS_STATIC, ReflectionProperty::IS_PUBLIC, ReflectionProperty::IS_PROTECTED, ReflectionProperty::IS_PRIVATE.
35
     *
36
     * @return \Benoth\StaticReflection\Reflection\ReflectionProperty[]
37
     */
38 195
    public function getProperties($filter = null)
39
    {
40 195
        $properties = $this->getSelfProperties();
41
42 195
        if ($this instanceof ReflectionClass && $this->getParentClass() instanceof ReflectionClass) {
43 78 View Code Duplication
            foreach ($this->getParentClass()->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...
44 78
                if (!array_key_exists($property->getName(), $properties)) {
45 78
                    $properties[$property->getName()] = $property;
46 78
                }
47 78
            }
48 78
        }
49
50 195
        if ($this instanceof ReflectionClass) {
51 195
            foreach ($this->getTraitsProperties() as $propertyName => $property) {
52 78
                if (!array_key_exists($propertyName, $properties)) {
53 78
                    $properties[$propertyName] = $property;
54 78
                }
55 195
            }
56 195
        }
57
58 195
        return $this->filterProperties($properties, $filter);
59
    }
60
61
    /**
62
     * Gets an array of static properties, with inherited ones.
63
     *
64
     * @return \Benoth\StaticReflection\Reflection\ReflectionProperty[]
65
     */
66 51
    public function getStaticProperties()
67
    {
68 51
        return $this->getProperties(ReflectionProperty::IS_STATIC);
69
    }
70
71
    /**
72
     * Gets an array of properties, without inherited ones.
73
     *
74
     * @param int $filter Any combination of ReflectionProperty::IS_STATIC, ReflectionProperty::IS_PUBLIC, ReflectionProperty::IS_PROTECTED, ReflectionProperty::IS_PRIVATE.
75
     *
76
     * @return \Benoth\StaticReflection\Reflection\ReflectionProperty[]
77
     */
78 207
    public function getSelfProperties($filter = null)
79
    {
80 207
        $properties = [];
81 207
        foreach ($this->properties as $property) {
82 195
            $properties[$property->getName()] = $property;
83 207
        }
84
85 207
        return $this->filterProperties($properties, $filter);
86
    }
87
88
    /**
89
     * Gets a ReflectionProperty for an entity.
90
     *
91
     * @param string $propertySearchedName The property name to reflect
92
     *
93
     * @throws \ReflectionException If the property does not exist
94
     *
95
     * @return \Benoth\StaticReflection\Reflection\ReflectionProperty
96
     */
97 63
    public function getProperty($propertySearchedName)
98
    {
99 63
        foreach ($this->getProperties() as $propertyName => $property) {
100 63
            if ($propertyName === $propertySearchedName) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $propertyName (integer) and $propertySearchedName (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
101 54
                return $property;
102
            }
103 48
        }
104
105 9
        throw new \ReflectionException('Property '.$propertySearchedName.' does not exist');
106
    }
107
108
    /**
109
     * Checks if a property is defined.
110
     *
111
     * @param string $propertySearchedName Name of the property being checked for
112
     *
113
     * @return bool
114
     */
115 9
    public function hasProperty($propertySearchedName)
116
    {
117 9
        foreach ($this->getProperties() as $propertyName => $property) {
118 9
            if ($propertyName === $propertySearchedName) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $propertyName (integer) and $propertySearchedName (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
119 9
                return true;
120
            }
121 9
        }
122
123 9
        return false;
124
    }
125
126
    /**
127
     * Gets default properties values, with inherited ones.
128
     *
129
     * @return mixed[]
130
     */
131 12
    public function getDefaultProperties()
132
    {
133 12
        $properties = [];
134 12
        foreach ($this->getProperties() as $propertyName => $property) {
135 9
            $properties[$propertyName] = $property->getDefaultValue();
136 12
        }
137
138 12
        return $properties;
139
    }
140
141
    /**
142
     * Gets static property value.
143
     *
144
     * @param string $name    The name of the static property
145
     * @param mixed  $default Optional default value to return if the property does not exist
0 ignored issues
show
Bug introduced by
There is no parameter named $default. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
146
     *
147
     * @throws \ReflectionException If the property does not exist and default value is omitted.
148
     *
149
     * @return mixed The static property value or the default value if provided and if the property does not exist
150
     */
151 36
    public function getStaticPropertyValue($name)
152
    {
153 36
        if (func_num_args() === 2) {
154 18
            $default = func_get_arg(1);
155 18
        }
156
157 36
        $properties = $this->getStaticProperties();
158 36
        if (!array_key_exists($name, $properties) && !isset($default)) {
159 18
            throw new \ReflectionException('Class '.$this->getName().' does not have a property named '.$name);
160 18
        } elseif (!array_key_exists($name, $properties)) {
161 12
            return $default;
0 ignored issues
show
Bug introduced by
The variable $default does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
162
        }
163
164 9
        return $properties[$name]->getDefaultValue();
165
    }
166
167
    /**
168
     * Sets static property value.
169
     *
170
     * @param string $name  The property name
171
     * @param string $value The new value
172
     *
173
     * @throws \ReflectionException If the property does not exist or is not public
174
     */
175 15
    public function setStaticPropertyValue($name, $value)
176
    {
177 15
        $property = $this->getProperty($name);
178 15
        if (!$property->isPublic() || !$property->isStatic()) {
179 12
            throw new \ReflectionException('Class '.$this->getName().' does not have a property named '.$name);
180
        }
181
182 3
        $property->setDefault(gettype($value), $value);
183 3
    }
184
185
    /**
186
     * Add a property to the reflected class.
187
     *
188
     * @param ReflectionProperty $property
189
     */
190 786
    public function addProperty(ReflectionProperty $property)
191
    {
192 786
        $this->properties[$property->getShortName()] = $property;
193 786
        $property->setDeclaringClassLike($this);
194 786
        $property->setFilename($this->getFileName());
195
196 786
        return $this;
197
    }
198
199
    /**
200
     * Filter an array of properties.
201
     *
202
     * @param \Benoth\StaticReflection\Reflection\ReflectionProperty[] $properties
203
     * @param int                                                      $filter     Any combination of ReflectionProperty::IS_STATIC, ReflectionProperty::IS_PUBLIC, ReflectionProperty::IS_PROTECTED, ReflectionProperty::IS_PRIVATE.
204
     *
205
     * @return \Benoth\StaticReflection\Reflection\ReflectionProperty[]
206
     */
207 207
    protected function filterProperties(array $properties, $filter)
208
    {
209 207
        if (!is_int($filter)) {
210 207
            return $properties;
211
        }
212
213 99
        return array_filter($properties, function (ReflectionProperty $property) use ($filter) {
214 96
            if (self::IS_PRIVATE === (self::IS_PRIVATE & $filter) && $property->isPrivate()) {
215 18
                return true;
216 96
            } elseif (self::IS_PROTECTED === (self::IS_PROTECTED & $filter) && $property->isProtected()) {
217 18
                return true;
218 96
            } elseif (self::IS_PUBLIC === (self::IS_PUBLIC & $filter) && $property->isPublic()) {
219 9
                return true;
220 96
            } elseif (self::IS_STATIC === (self::IS_STATIC & $filter) && $property->isStatic()) {
221 30
                return true;
222
            }
223
224 84
            return false;
225 99
        });
226
    }
227
}
228