ReflectiveMethodInvocation   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 12
Bugs 2 Features 0
Metric Value
wmc 10
eloc 34
c 12
b 2
f 0
dl 0
loc 100
ccs 32
cts 32
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getArguments() 0 3 1
A getThis() 0 3 1
A getNamedArguments() 0 14 3
A proceed() 0 8 2
A getMethod() 0 13 2
A __construct() 0 13 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Aop;
6
7
use ArrayObject;
8
use ReflectionClass;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Aop\ReflectionClass. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use ReflectionObject;
10
11
use function array_key_exists;
12
use function array_shift;
13
use function assert;
14
use function call_user_func_array;
15
use function class_exists;
16
use function is_callable;
17
18
final class ReflectiveMethodInvocation implements MethodInvocation
19
{
20
    /** @var object */
21
    private $object;
22
23
    /** @var ArrayObject<int, mixed> */
24
    private $arguments;
25
26
    /** @var string */
27
    private $method;
28
29
    /** @var MethodInterceptor[] */
30
    private $interceptors;
31
32
    /** @var callable */
33
    private $callable;
34
35
    /**
36
     * @param array<MethodInterceptor> $interceptors
37
     * @param array<int, mixed>        $arguments
38
     */
39
    public function __construct(
40
        object $object,
41
        string $method,
42
        array $arguments,
43
        array $interceptors = []
44 17
    ) {
45
        $this->object = $object;
46
        $this->method = $method;
47
        $callable = [$object, $method];
48
        assert(is_callable($callable));
49
        $this->callable = $callable;
50 17
        $this->arguments = new ArrayObject($arguments);
51 17
        $this->interceptors = $interceptors;
52 17
    }
53 17
54 17
    /**
55 17
     * {@inheritdoc}
56
     */
57
    public function getMethod(): ReflectionMethod
58
    {
59
        if ($this->object instanceof WeavedInterface) {
60 6
            $class = (new ReflectionObject($this->object))->getParentClass();
61
            assert($class instanceof ReflectionClass);
62 6
            assert(class_exists($class->name));
63 3
            $method = new ReflectionMethod($class->name, $this->method);
64 3
            $method->setObject($this->object, $method);
65
66
            return $method;
67 3
        }
68 3
69
        return new ReflectionMethod($this->object, $this->method);
70 3
    }
71
72
    /**
73 3
     * {@inheritdoc}
74
     */
75
    public function getArguments(): ArrayObject
76
    {
77
        return $this->arguments;
78
    }
79 3
80
    /**
81 3
     * {@inheritdoc}
82
     */
83 3
    public function getNamedArguments(): ArrayObject
84
    {
85
        $args = $this->getArguments();
86
        $params = $this->getMethod()->getParameters();
87
        $namedParams = [];
88
        foreach ($params as $param) {
89 1
            $pos = $param->getPosition();
90
            if (array_key_exists($pos, (array) $args)) {
91 1
                /** @psalm-suppress MixedAssignment */
92 1
                $namedParams[$param->getName()] = $args[$pos];
93 1
            }
94 1
        }
95 1
96
        return new ArrayObject($namedParams);
97
    }
98 1
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function proceed()
103
    {
104 11
        $interceptor = array_shift($this->interceptors);
105
        if ($interceptor instanceof MethodInterceptor) {
106 11
            return $interceptor->invoke($this);
107 9
        }
108
109 9
        return call_user_func_array($this->callable, (array) $this->arguments);
110 9
    }
111 8
112
    /**
113 1
     * {@inheritdoc}
114
     */
115
    public function getThis()
116
    {
117
        return $this->object;
118
    }
119
}
120