ReflectionsIndex::getClasses()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
ccs 3
cts 3
cp 1
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Benoth\StaticReflection;
4
5
use Benoth\StaticReflection\Reflection\Reflection;
6
use Benoth\StaticReflection\Reflection\ReflectionClass;
7
use Benoth\StaticReflection\Reflection\ReflectionClassLike;
8
use Benoth\StaticReflection\Reflection\ReflectionFunction;
9
use Benoth\StaticReflection\Reflection\ReflectionInterface;
10
use Benoth\StaticReflection\Reflection\ReflectionTrait;
11
12
class ReflectionsIndex
13
{
14
    protected $reflections = [];
15
16 1101
    public function addReflection(Reflection $reflection)
17
    {
18 1101
        $reflection->setIndex($this);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Benoth\StaticReflection\Reflection\Reflection as the method setIndex() does only exist in the following sub-classes of Benoth\StaticReflection\Reflection\Reflection: Benoth\StaticReflection\Reflection\ReflectionClass, Benoth\StaticReflection\...ion\ReflectionClassLike, Benoth\StaticReflection\...tion\ReflectionFunction, Benoth\StaticReflection\...ion\ReflectionInterface, Benoth\StaticReflection\Reflection\ReflectionTrait. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
19
20 1101
        $this->reflections[] = $reflection;
21 1101
    }
22
23 12
    public function getReflections()
24
    {
25 12
        return $this->reflections;
26
    }
27
28 24
    public function getClassLikes()
29
    {
30
        return array_filter($this->reflections, function ($reflection) {
31 24
            return $reflection instanceof ReflectionClassLike;
32 24
        });
33
    }
34
35 960
    public function getClasses()
36
    {
37
        return array_filter($this->reflections, function ($reflection) {
38 960
            return $reflection instanceof ReflectionClass;
39 960
        });
40
    }
41
42 327
    public function getInterfaces()
43
    {
44
        return array_filter($this->reflections, function ($reflection) {
45 327
            return $reflection instanceof ReflectionInterface;
46 327
        });
47
    }
48
49 216
    public function getTraits()
50
    {
51
        return array_filter($this->reflections, function ($reflection) {
52 216
            return $reflection instanceof ReflectionTrait;
53 216
        });
54
    }
55
56 12
    public function getFunctionLikes()
57
    {
58
        $functions = array_filter($this->reflections, function ($reflection) {
59 12
            return $reflection instanceof ReflectionFunction;
60 12
        });
61
62 12
        foreach ($this->getClassLikes() as $reflection) {
63 9
            $functions = array_merge($functions, $reflection->getMethods());
64 12
        }
65
66 12
        return $functions;
67
    }
68
69
    public function getFunctions()
70
    {
71 30
        return array_filter($this->reflections, function ($reflection) {
72 30
            return $reflection instanceof ReflectionFunction;
73 30
        });
74
    }
75
76
    /**
77
     * Get a class by its Fully Qualified Name.
78
     *
79
     * @param string $className Fully Qualified Name
80
     *
81
     * @return ReflectionClass|null
82
     */
83 948
    public function getClass($className)
84
    {
85 948
        foreach ($this->getClasses() as $reflection) {
86 939
            if ($reflection->getName() === $className) {
87 939
                return $reflection;
88
            }
89 444
        }
90
91 12
        return;
92
    }
93
94
    /**
95
     * Get an interface by its Fully Qualified Name.
96
     *
97
     * @param string $interfaceName Fully Qualified Name
98
     *
99
     * @return ReflectionInterface|null
100
     */
101 315
    public function getInterface($interfaceName)
102
    {
103 315
        foreach ($this->getInterfaces() as $reflection) {
104 135
            if ($reflection->getName() === $interfaceName) {
105 135
                return $reflection;
106
            }
107 315
        }
108
109 183
        return;
110
    }
111
112
    /**
113
     * Get a trait by its Fully Qualified Name.
114
     *
115
     * @param string $traitName Fully Qualified Name
116
     *
117
     * @return ReflectionTrait|null
118
     */
119 204
    public function getTrait($traitName)
120
    {
121 204
        foreach ($this->getTraits() as $reflection) {
122 195
            if ($reflection->getName() === $traitName) {
123 195
                return $reflection;
124
            }
125 204
        }
126
127 12
        return;
128
    }
129
130 18
    public function getFunction($functionName)
131
    {
132 18
        foreach ($this->getFunctions() as $reflection) {
133 9
            if ($reflection->getName() === $functionName) {
134 9
                return $reflection;
135
            }
136 12
        }
137
138 12
        return;
139
    }
140
}
141