MethodMatch   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 26
c 3
b 0
f 0
dl 0
loc 79
rs 10
wmc 11

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A __invoke() 0 19 4
A onionOrderMatch() 0 18 3
A annotatedMethodMatchBind() 0 15 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Aop;
6
7
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...
8
use ReflectionMethod;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Aop\ReflectionMethod. 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
10
use function array_key_exists;
11
use function get_class;
12
13
final class MethodMatch
14
{
15
    /** @var BindInterface */
16
    private $bind;
17
18
    public function __construct(BindInterface $bind)
19
    {
20
        $this->bind = $bind;
21
    }
22
23
    /**
24
     * @param ReflectionClass<object> $class
25
     * @param Pointcut[]              $pointcuts
26
     */
27
    public function __invoke(ReflectionClass $class, \Ray\Aop\ReflectionMethod $method, array $pointcuts): void
28
    {
29
        /** @var array<int, object> $annotations */
30
        $annotations = $method->getAnnotations();
31
        // priority bind
32
        foreach ($pointcuts as $key => $pointcut) {
33
            if (! ($pointcut instanceof PriorityPointcut)) {
34
                continue;
35
            }
36
37
            $this->annotatedMethodMatchBind($class, $method, $pointcut);
38
            unset($pointcuts[$key]);
39
        }
40
41
        $onion = $this->onionOrderMatch($class, $method, $pointcuts, $annotations);
42
43
        // default binding
44
        foreach ($onion as $pointcut) {
45
            $this->annotatedMethodMatchBind($class, $method, $pointcut);
46
        }
47
    }
48
49
    /** @param ReflectionClass<object> $class */
50
    private function annotatedMethodMatchBind(ReflectionClass $class, ReflectionMethod $method, Pointcut $pointCut): void
51
    {
52
        $isMethodMatch = $pointCut->methodMatcher->matchesMethod($method, $pointCut->methodMatcher->getArguments());
53
        if (! $isMethodMatch) {
54
            return;
55
        }
56
57
        $isClassMatch = $pointCut->classMatcher->matchesClass($class, $pointCut->classMatcher->getArguments());
58
        if (! $isClassMatch) {
59
            return;
60
        }
61
62
        /** @var MethodInterceptor[] $interceptors */
63
        $interceptors = $pointCut->interceptors;
64
        $this->bind->bindInterceptors($method->name, $interceptors);
65
    }
66
67
    /**
68
     * @param ReflectionClass<object> $class
69
     * @param Pointcut[]              $pointcuts
70
     * @param array<int, object>      $annotations
71
     *
72
     * @return Pointcut[]
73
     */
74
    private function onionOrderMatch(
75
        ReflectionClass $class,
76
        ReflectionMethod $method,
77
        array $pointcuts,
78
        array $annotations
79
    ): array {
80
        // method bind in annotation order
81
        foreach ($annotations as $annotation) {
82
            $annotationIndex = get_class($annotation);
83
            if (! array_key_exists($annotationIndex, $pointcuts)) {
84
                continue;
85
            }
86
87
            $this->annotatedMethodMatchBind($class, $method, $pointcuts[$annotationIndex]);
88
            unset($pointcuts[$annotationIndex]);
89
        }
90
91
        return $pointcuts;
92
    }
93
}
94