GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

PrototypeTrait   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
eloc 62
dl 0
loc 200
rs 10
c 6
b 0
f 0
wmc 22

8 Methods

Rating   Name   Duplication   Size   Complexity  
A get_prototype() 0 3 1
A accessor_set() 0 28 4
A has_property() 0 10 2
B accessor_get() 0 42 6
A last_chance_set() 0 3 1
A __call() 0 21 5
A last_chance_get() 0 5 1
A has_method() 0 9 2
1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie;
13
14
use ICanBoogie\Accessor\AccessorTrait;
15
use ICanBoogie\Prototype\MethodNotDefined;
16
use ICanBoogie\Prototype\MethodOutOfScope;
17
use ReflectionException;
18
19
use function array_unshift;
20
use function assert;
21
use function is_callable;
22
use function method_exists;
23
24
/**
25
 * A trait for classes wishing to implement prototype methods.
26
 *
27
 * @property Prototype $prototype The prototype associated with the class.
28
 */
29
trait PrototypeTrait
30
{
31
    use AccessorTrait {
32
        AccessorTrait::has_property as private accessor_has_property;
33
    }
34
35
    /**
36
     * @var Prototype|null
37
     */
38
    private $prototype;
39
40
    protected function get_prototype(): Prototype
41
    {
42
        return $this->prototype ?? $this->prototype = Prototype::from($this);
43
    }
44
45
    /**
46
     * If a property exists with the name specified by `$method` and holds an object which class
47
     * implements `__invoke` then the object is called with the arguments. Otherwise, calls are
48
     * forwarded to the {@link $prototype}.
49
     *
50
     * @param array<int, mixed> $arguments
51
     *
52
     * @return mixed
53
     */
54
    public function __call(string $method, array $arguments)
55
    {
56
        if (isset($this->$method) && is_callable([ $this->$method, '__invoke' ])) {
57
            return $this->$method(...$arguments);
58
        }
59
60
        array_unshift($arguments, $this);
61
62
        try {
63
            $prototype = $this->prototype ?? $this->get_prototype();
64
            $callable = $prototype[$method];
65
66
            assert(is_callable($callable));
67
68
            return $callable(...$arguments);
69
        } catch (MethodNotDefined $e) {
70
            if (method_exists($this, $method)) {
71
                throw new MethodOutOfScope($method, $this);
72
            }
73
74
            throw $e;
75
        }
76
    }
77
78
    /**
79
     * Checks if the object has the specified property.
80
     *
81
     * The difference with the `property_exists()` function is that this method also checks for
82
     * getters defined by the class or the prototype.
83
     *
84
     * @param string $property The property to check.
85
     *
86
     * @return bool `true` if the object has the property, `false` otherwise.
87
     */
88
    public function has_property(string $property): bool
89
    {
90
        if ($this->accessor_has_property($property)) {
91
            return true;
92
        }
93
94
        $success = false;
95
        $this->last_chance_get($property, $success);
96
97
        return $success;
98
    }
99
100
    /**
101
     * Checks whether this object supports the specified method.
102
     *
103
     * The method checks for methods defined by the class and the prototype.
104
     *
105
     * @param string $method Name of the method.
106
     *
107
     * @return bool `true` if the method is defined, `false` otherwise.
108
     */
109
    public function has_method(string $method): bool
110
    {
111
        if (method_exists($this, $method)) {
112
            return true;
113
        }
114
115
        $prototype = $this->prototype ?? $this->get_prototype();
116
117
        return isset($prototype[$method]);
118
    }
119
120
    /**
121
     * @return mixed|null
122
     */
123
    protected function accessor_get(string $property)
124
    {
125
        $method = 'get_' . $property;
126
127
        if (method_exists($this, $method)) {
128
            return $this->$method();
129
        }
130
131
        $method = 'lazy_get_' . $property;
132
133
        if (method_exists($this, $method)) {
134
            return $this->$property = $this->$method();
135
        }
136
137
        #
138
        # we didn't find a suitable method in the class, maybe the prototype has one.
139
        #
140
141
        $prototype = $this->prototype ?? $this->get_prototype();
142
143
        $method = 'get_' . $property;
144
145
        if (isset($prototype[$method])) {
146
            assert(is_callable($prototype[$method]));
147
            return $prototype[$method]($this, $property);
148
        }
149
150
        $method = 'lazy_get_' . $property;
151
152
        if (isset($prototype[$method])) {
153
            assert(is_callable($prototype[$method]));
154
            return $this->$property = $prototype[$method]($this, $property);
155
        }
156
157
        $success = false;
158
        $value = $this->last_chance_get($property, $success);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $value is correct as $this->last_chance_get($property, $success) targeting ICanBoogie\PrototypeTrait::last_chance_get() 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...
159
160
        if ($success) {
161
            return $value;
162
        }
163
164
        $this->assert_property_is_readable($property);
165
    }
166
167
    /**
168
     * @param mixed $value
169
     *
170
     * @throws ReflectionException
171
     */
172
    protected function accessor_set(string $property, $value): void
173
    {
174
        $method = 'set_' . $property;
175
176
        if ($this->has_method($method)) {
177
            $this->$method($value);
178
179
            return;
180
        }
181
182
        $method = 'lazy_set_' . $property;
183
184
        if ($this->has_method($method)) {
185
            $this->$property = $this->$method($value);
186
187
            return;
188
        }
189
190
        $success = false;
191
        $this->last_chance_set($property, $value, $success);
192
193
        if ($success) {
194
            return;
195
        }
196
197
        $this->assert_property_is_writable($property);
198
199
        $this->$property = $value;
200
    }
201
202
    /**
203
     * The method is invoked as a last chance to get a property,
204
     * just before an exception is thrown.
205
     *
206
     * @param string $property Property to get.
207
     * @param bool $success If the _last chance get_ was successful.
208
     *
209
     * @return mixed
210
     */
211
    protected function last_chance_get(string $property, bool &$success)
212
    {
213
        $success = false;
214
215
        return null;
216
    }
217
218
    /**
219
     * The method is invoked as a last chance to set a property,
220
     * just before an exception is thrown.
221
     *
222
     * @param string $property Property to set.
223
     * @param mixed $value Value of the property.
224
     * @param bool $success If the _last chance set_ was successful.
225
     */
226
    protected function last_chance_set(string $property, $value, bool &$success): void
227
    {
228
        $success = false;
229
    }
230
}
231