Completed
Push — master ( 5fca22...233410 )
by Emily
01:43
created

ReflectionMethodFactory   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 83.82%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 7
dl 0
loc 184
ccs 57
cts 68
cp 0.8382
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A fromName() 0 7 1
A __construct() 0 6 1
A initParams() 0 13 1
B addParamAnnotation() 0 31 3
A addParameter() 0 20 2
C build() 0 44 8
1
<?php
2
/**
3
 * This file is part of the Composite Utils package.
4
 *
5
 * (c) Emily Shepherd <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the
8
 * LICENSE.md file that was distributed with this source code.
9
 *
10
 * @package spaark/composite-utils
11
 * @author Emily Shepherd <[email protected]>
12
 * @license MIT
13
 */
14
15
namespace Spaark\CompositeUtils\Factory\Reflection;
16
17
use Spaark\CompositeUtils\Model\Reflection\ReflectionComposite;
18
use Spaark\CompositeUtils\Model\Reflection\ReflectionMethod;
19
use Spaark\CompositeUtils\Model\Reflection\ReflectionParameter;
20
use Spaark\CompositeUtils\Model\Type\ObjectType;
21
use Spaark\CompositeUtils\Service\RawPropertyAccessor;
22
use Spaark\CompositeUtils\Service\TypeComparator;
23
use Spaark\CompositeUtils\Model\Collection\ListCollection\FixedList;
24
use Spaark\CompositeUtils\Model\Collection\Map\HashMap;
25
use \ReflectionMethod as PHPNativeReflectionMethod;
26
use \ReflectionParameter as PHPNativeReflectionParameter;
27
use \Reflector as PHPNativeReflector;
28
29
/**
30
 * Builds a ReflectionMethod for a given method and optionally links
31
 * this to a parent ReflectionComposite
32
 */
33
class ReflectionMethodFactory extends ReflectorFactory
34
{
35
    const REFLECTION_OBJECT = ReflectionMethod::class;
36
37
    /**
38
     * @var PHPNativeReflectionMethod
39
     */
40
    protected $reflector;
41
42
    /**
43
     * @var ReflectionMethod
44
     */
45
    protected $object;
46
47
    /**
48
     * @var Hashmap
49
     */
50
    protected $parameters;
51
52
    /**
53
     * @var TypeParser
54
     */
55
    protected $typeParser;
56
57
    /**
58
     * Returns a new ReflectionMethodFactory using the given class and
59
     * method names
60
     *
61
     * @param string $class The classname of the method
62
     * @param string $method The method to reflect
63
     * @return ReflectionMethodFactory
64
     */
65
    public static function fromName(string $class, string $method)
66
    {
67
        return new static(new PHPNativeReflectionMethod
68
        (
69
            $class, $method
70
        ));
71
    }
72
73 21
    public function __construct(PHPNativeReflector $reflector)
74
    {
75 21
        parent::__construct($reflector);
76
77 21
        $this->parameters = new HashMap();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Spaark\CompositeUti...ollection\Map\HashMap() of type object<Spaark\CompositeU...Collection\Map\HashMap> is incompatible with the declared type object<Spaark\CompositeU...ory\Reflection\Hashmap> of property $parameters.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78 21
    }
79
80
    /**
81
     * Builds the ReflectionMethod from the provided parameters,
82
     * optionally linking to a parent ReflectionComposite
83
     *
84
     * @param ReflectionComposite $parent The reflector for the class
85
     *     this method belongs to
86
     * @return ReflectionMethod
87
     */
88 21
    public function build(?ReflectionComposite $parent = null)
89
    {
90 21
        $this->typeParser = new TypeParser($parent);
91 21
        $this->accessor->setRawValue('owner', $parent);
92 21
        $this->accessor->setRawValue
93
        (
94 21
            'name',
95 21
            $this->reflector->getName()
0 ignored issues
show
Bug introduced by
Consider using $this->reflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
96
        );
97
98 21
        $this->initParams();
99
100 21
        $this->accessor->setRawValue('visibility',
101 21
              ($this->reflector->isPublic() ? 'public'
102 2
            : ($this->reflector->isProtected() ? 'protected'
103
            : ($this->reflector->isPrivate() ? 'private'
104 21
            : (''))))
105
        );
106 21
        $this->accessor->setRawValue('scope',
107 21
            ($this->reflector->isStatic() ? 'static' : 'dynamic')
108
        );
109 21
        $this->accessor->setRawValue('final',
110 21
            $this->reflector->isFinal()
111
        );
112
113 21
        foreach ($this->reflector->getParameters() as $parameter)
114
        {
115 21
            $this->addParameter($parameter);
116
        }
117
118 21
        $type = $this->reflector->getReturnType();
119 21
        if ($type)
120
        {
121
            $this->accessor->setRawValue
122
            (
123
                'nativeReturnType',
124
                !$type->isBuiltin() ? '\\' . $type : (string)$type
125
            );
126
        }
127
128 21
        $this->parseDocComment(['param' => 'addParamAnnotation']);
129
130 21
        return $this->object;
131
    }
132
133
    /**
134
     * Creates the Method's parameter's property with a fixd list of
135
     * the appropriate size
136
     */
137 21
    protected function initParams()
138
    {
139 21
        $this->accessor->setRawValue
140
        (
141 21
            'parameters',
142 21
            new FixedList(count($this->reflector->getParameters()))
143
        );
144 21
        $this->accessor->setRawValue
145
        (
146 21
            'nativeParameters',
147 21
            new FixedList(count($this->reflector->getParameters()))
148
        );
149 21
    }
150
151
    /**
152
     * Processes a param docblock annotation and uses it to decorate
153
     * a method parameter
154
     *
155
     * @param string $name Unused. Should be 'param'
156
     * @param string $value The annotation value
157
     */
158 21
    protected function addParamAnnotation($name, $value) : void
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
159
    {
160 21
        $items = explode(' ', $value);
161 21
        $type = $items[0];
162 21
        $param = $items[1];
163
164 21
        if (!$this->parameters->containsKey($param))
165
        {
166
            throw new \Exception
167
            (
168
                  'Tried to set param annotation for non existant '
169
                . 'parameter: ' . $param
170
            );
171
        }
172
173 21
        $comparator = new TypeComparator();
174 21
        $type = $this->typeParser->parse($type);
175 21
        $param = $this->parameters[$param];
176 21
        $nativeType = $param->getRawValue('type');
177
178 21
        if (!$comparator->compatible($nativeType, $type))
179
        {
180
            throw new \Exception
181
            (
182
                  'Types are incompatible for: '
183
                . $this->reflector->getName() . '::' . $items[1]
0 ignored issues
show
Bug introduced by
Consider using $this->reflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
184
            );
185
        }
186
187 21
        $param->setRawValue('type', $type);
188 21
    }
189
190
    /**
191
     * Adds a parameter to the method, based on it's native
192
     * ReflectionParameter
193
     *
194
     * @param PHPNativeReflectionParameter $reflect
195
     */
196 21
    protected function addParameter
197
    (
198
        PHPNativeReflectionParameter $reflect
199
    )
200
    : void
201
    {
202 21
        $parameter = new ReflectionParameter();
203 21
        $accessor = new RawPropertyAccessor($parameter);
204 21
        $type = (new TypeParser())->parse((string)$reflect->getType());
205
206 21
        $this->parameters['$' . $reflect->getName()] = $accessor;
0 ignored issues
show
Bug introduced by
Consider using $reflect->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
207 21
        $this->accessor->rawAddToValue('parameters', $parameter);
0 ignored issues
show
Deprecated Code introduced by
The method Spaark\CompositeUtils\Se...cessor::rawAddToValue() has been deprecated.

This method has been deprecated.

Loading history...
208 21
        $this->accessor->rawAddToValue('nativeParameters',
0 ignored issues
show
Deprecated Code introduced by
The method Spaark\CompositeUtils\Se...cessor::rawAddToValue() has been deprecated.

This method has been deprecated.

Loading history...
209 21
            ($type instanceOf ObjectType ? '\\' : '') . (string)$type
0 ignored issues
show
Bug introduced by
The class Spaark\CompositeUtils\Model\Type\ObjectType does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
210
        );
211
212 21
        $accessor->setRawValue('owner', $this->object);
213 21
        $accessor->setRawValue('name', $reflect->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflect->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
214 21
        $accessor->setRawValue('type', $type);
215 21
    }
216
}
217
218