Bootstrap::getClassInheritance()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * This file is part of Properties package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace Serafim\Properties;
11
12
use Psr\SimpleCache\CacheInterface;
13
use Serafim\Properties\Attribute\AttributeInterface;
14
15
/**
16
 * Class Bootstrap
17
 */
18
final class Bootstrap
19
{
20
    /**
21
     * @var Bootstrap
22
     */
23
    private static $instance;
24
25
    /**
26
     * @var CacheInterface
27
     */
28
    private $cache;
29
30
    /**
31
     * @var Builder
32
     */
33
    private $builder;
34
35
    /**
36
     * @var array|string[]
37
     */
38
    private $inheritance = [];
39
40
    /**
41
     * @return Bootstrap
42
     */
43
    public static function getInstance(): self
44
    {
45
        return self::$instance ?? self::setInstance(new self());
46
    }
47
48
    /**
49
     * @param self|Bootstrap $instance
50
     * @return Bootstrap
51
     */
52
    public static function setInstance(?self $instance): self
53
    {
54
        return self::$instance = $instance;
55
    }
56
57
    /**
58
     * Bootstrap constructor.
59
     */
60
    private function __construct()
61
    {
62
        $this->cache = new ArrayCache();
63
        $this->builder = new Builder();
64
    }
65
66
    /**
67
     * @return array
68
     */
69
    public function getInvocationPosition(): array
70
    {
71
        $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)[2] ?? [];
72
73
        return [$trace['file'] ?? __FILE__, $trace['line'] ?? __LINE__];
74
    }
75
76
    /**
77
     * @param null|CacheInterface $cache
78
     */
79
    public function setCacheDriver(?CacheInterface $cache): void
80
    {
81
        $this->cache = $cache ?? new ArrayCache();
82
    }
83
84
    /**
85
     * @param string $class
86
     * @param string $name
87
     * @return AttributeInterface|null
88
     * @throws \Psr\SimpleCache\InvalidArgumentException
89
     */
90
    public function getAttribute(string $class, string $name): ?AttributeInterface
91
    {
92
        foreach ($this->getClassInheritance($class) as $child) {
93
            $result = $this->getAttributeOrBuild($child, $name, function () use ($child) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->getAttributeOrBui...> $attribute); } }) (which targets Serafim\Properties\Boots...::getAttributeOrBuild()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
94
                foreach ($this->builder->buildClass($child) as $attribute) {
95
                    yield $this->getCacheKey($child, $attribute->getName()) => $attribute;
96
                }
97
            });
98
99
            if ($result) {
100
                return $result;
101
            }
102
        }
103
104
        return null;
105
    }
106
107
    /**
108
     * @param string $class
109
     * @param string $name
110
     * @return bool
111
     * @throws \Psr\SimpleCache\InvalidArgumentException
112
     */
113
    public function hasAttribute(string $class, string $name): bool
114
    {
115
        return $this->getAttribute($class, $name) !== null;
116
    }
117
118
    /**
119
     * @param string $class
120
     * @return iterable|string[]
121
     */
122
    private function getClassInheritance(string $class): iterable
123
    {
124
        $inheritance = function() use ($class) {
125
            yield $class;
126
            yield from \array_keys(\class_parents($class));
127
            yield from \array_keys(\class_implements($class));
128
            yield from \array_keys(\class_uses($class));
129
        };
130
131
        if (! isset($this->inheritance[$class])) {
132
            $this->inheritance[$class] = \iterator_to_array($inheritance(), false);
133
        }
134
135
        return $this->inheritance[$class];
136
    }
137
138
    /**
139
     * @param string $class
140
     * @param string $name
141
     * @param \Closure $build
142
     * @return null|AttributeInterface
143
     * @throws \Psr\SimpleCache\InvalidArgumentException
144
     */
145
    private function getAttributeOrBuild(string $class, string $name, \Closure $build): ?AttributeInterface
146
    {
147
        $key = $this->getCacheKey($class, $name);
148
149
        if (! $this->cache->has($key)) {
150
            foreach ($build() as $inner => $attribute) {
151
                $this->cache->set($inner, $attribute);
152
            }
153
        }
154
155
        return $this->cache->get($key);
156
    }
157
158
    /**
159
     * @param string $class
160
     * @param string $name
161
     * @return string
162
     */
163
    private function getCacheKey(string $class, string $name): string
164
    {
165
        return \hash('md4', \implode(':', [$class, $name]));
166
    }
167
}
168