Passed
Push — semantic ( 9e9f01 )
by Akihito
02:35
created

SpyCompiler::getAopInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Di;
6
7
use Ray\Aop\BindInterface;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Di\BindInterface. 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 Ray\Aop\CompilerInterface;
9
use Ray\Di\Bindings\AopInfo;
10
11
use function array_keys;
12
use function method_exists;
13
14
/**
15
 * @codeCoverageIgnore
16
 */
17
final class SpyCompiler implements CompilerInterface
18
{
19
    /**
20
     * {@inheritDoc}
21
     *
22
     * @psalm-suppress InvalidReturnType
23
     * @template T of object
24
     */
25
    public function newInstance(string $class, array $args, BindInterface $bind)
26
    {
27
        // never called  // @phpstan-ignore-line
28
    }
29
30
    /**
31
     * Return "logging" class name
32
     *
33
     * Dummy classes are used for logging and don't really exist.
34
     * So the code breaks the QA rules as shown below.
35
     * NOTE: psalm-suppress is acceptable here for dummy/logging infrastructure
36
     *
37
     * @psalm-suppress MoreSpecificReturnType
38
     * @psalm-suppress LessSpecificReturnStatement
39
     */
40
    public function compile(string $class, BindInterface $bind): string
41
    {
42
        if ($this->hasNoBinding($class, $bind)) {
43
            return $class;
44
        }
45
46
        $aopInfo = $this->getInterceptors($bind);
47
        return $class . (string) $aopInfo; // @phpstan-ignore-line
48
    }
49
50
    /**
51
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
52
     */
53
    private function hasNoBinding(string $class, BindInterface $bind): bool
54
    {
55
        $hasMethod = $this->hasBoundMethod($class, $bind);
56
57
        return ! $bind->getBindings() && ! $hasMethod;
58
    }
59
60
    /**
61
     * @param class-string $class
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
62
     */
63
    private function hasBoundMethod(string $class, BindInterface $bind): bool
64
    {
65
        $bindingMethods = array_keys($bind->getBindings());
0 ignored issues
show
Bug introduced by
$bind->getBindings() of type Ray\Aop\MethodBindings is incompatible with the type array expected by parameter $array of array_keys(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

65
        $bindingMethods = array_keys(/** @scrutinizer ignore-type */ $bind->getBindings());
Loading history...
66
        $hasMethod = false;
67
        foreach ($bindingMethods as $bindingMethod) {
68
            if (method_exists($class, $bindingMethod)) {
69
                $hasMethod = true;
70
            }
71
        }
72
73
        return $hasMethod;
74
    }
75
76
    public function getAopInfo(BindInterface $bind): AopInfo
77
    {
78
        $bindings = $bind->getBindings();
79
        return new AopInfo($bindings);
0 ignored issues
show
Bug introduced by
$bindings of type Ray\Aop\MethodBindings is incompatible with the type array expected by parameter $methodBindings of Ray\Di\Bindings\AopInfo::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

79
        return new AopInfo(/** @scrutinizer ignore-type */ $bindings);
Loading history...
80
    }
81
82
    private function getInterceptors(BindInterface $bind): AopInfo
83
    {
84
        return $this->getAopInfo($bind);
85
    }
86
}
87