This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace nyx\diagnostics\debug\handlers; |
||||||||||||||||||||
2 | |||||||||||||||||||||
3 | // Internal dependencies |
||||||||||||||||||||
4 | use nyx\diagnostics\debug\exceptions; |
||||||||||||||||||||
5 | use nyx\diagnostics\debug\interfaces; |
||||||||||||||||||||
6 | use nyx\diagnostics\debug; |
||||||||||||||||||||
7 | use nyx\diagnostics\definitions; |
||||||||||||||||||||
8 | |||||||||||||||||||||
9 | /** |
||||||||||||||||||||
10 | * Exception Handler |
||||||||||||||||||||
11 | * |
||||||||||||||||||||
12 | * Responsible for handling Exceptions that have not get caught. Inspects them and provides its analyses to |
||||||||||||||||||||
13 | * registered Delegates {@see interfaces\Delegate}, which could be logging facilities, full page error displays |
||||||||||||||||||||
14 | * and the likes. All collection-like methods (add, remove, all etc.) manage the delegates and are named this way |
||||||||||||||||||||
15 | * for simplicity's sake. |
||||||||||||||||||||
16 | * |
||||||||||||||||||||
17 | * Delegates (both callables and actual Delegate instances) can be named and referred to by the set name for |
||||||||||||||||||||
18 | * white-and-black-listing and removal. Check {@see self::add()} and {@see self::set()} for information on the |
||||||||||||||||||||
19 | * naming behaviour. |
||||||||||||||||||||
20 | * |
||||||||||||||||||||
21 | * @package Nyx\Diagnostics\Debug |
||||||||||||||||||||
22 | * @version 0.0.5 |
||||||||||||||||||||
23 | * @author Michal Chojnacki <[email protected]> |
||||||||||||||||||||
24 | * @copyright 2012-2016 Nyx Dev Team |
||||||||||||||||||||
25 | * @link http://docs.muyo.io/nyx/diagnostics/debug.html |
||||||||||||||||||||
26 | * @todo Buffer the output of delegates within self::handle() and optionally return it instead of sending? |
||||||||||||||||||||
27 | * @todo Optional adding of Delegates upon Handler construction? |
||||||||||||||||||||
28 | */ |
||||||||||||||||||||
29 | class Exception extends debug\Handler implements interfaces\handlers\Exception |
||||||||||||||||||||
30 | { |
||||||||||||||||||||
31 | /** |
||||||||||||||||||||
32 | * @var array An array of registered interfaces\Delegate and callables. Each value in the array is an array |
||||||||||||||||||||
33 | * containing two key => value pairs: The 'delegate' (callable | interfaces\Delegate) itself, |
||||||||||||||||||||
34 | * and the 'priority' (int). |
||||||||||||||||||||
35 | */ |
||||||||||||||||||||
36 | private $delegates = []; |
||||||||||||||||||||
37 | |||||||||||||||||||||
38 | /** |
||||||||||||||||||||
39 | * @var array The (cached) delegates applicable for the next call to self::handle(). |
||||||||||||||||||||
40 | */ |
||||||||||||||||||||
41 | private $applicable; |
||||||||||||||||||||
42 | |||||||||||||||||||||
43 | /** |
||||||||||||||||||||
44 | * @var array A list of Delegate *names* not allowed to handle the exception currently being handled. |
||||||||||||||||||||
45 | */ |
||||||||||||||||||||
46 | private $blacklist = []; |
||||||||||||||||||||
47 | |||||||||||||||||||||
48 | /** |
||||||||||||||||||||
49 | * @var array A list of Delegate *names* allowed to handle the exception currently being handled. |
||||||||||||||||||||
50 | */ |
||||||||||||||||||||
51 | private $whitelist = []; |
||||||||||||||||||||
52 | |||||||||||||||||||||
53 | /** |
||||||||||||||||||||
54 | * @var bool Whether the blacklist overrides the whitelist. Ie. when a given Delegate name is present in |
||||||||||||||||||||
55 | * both arrays it will be treated as blacklisted. |
||||||||||||||||||||
56 | */ |
||||||||||||||||||||
57 | private $prioritizeBlacklist = true; |
||||||||||||||||||||
58 | |||||||||||||||||||||
59 | /** |
||||||||||||||||||||
60 | * @var int The currently highest priority assigned to any Delegate/callable. |
||||||||||||||||||||
61 | */ |
||||||||||||||||||||
62 | private $highestPriority = 0; |
||||||||||||||||||||
63 | |||||||||||||||||||||
64 | /** |
||||||||||||||||||||
65 | * Registers the given or this Exception Handler with PHP. |
||||||||||||||||||||
66 | * |
||||||||||||||||||||
67 | * @param interfaces\handlers\Exception $handler An optional, already instantiated Exception Handler |
||||||||||||||||||||
68 | * instance. If none is given, a new one will be |
||||||||||||||||||||
69 | * instantiated. |
||||||||||||||||||||
70 | * @return Exception An instance of the Exception Handler which got registered. |
||||||||||||||||||||
71 | * Either the same as the given one or if none was given, |
||||||||||||||||||||
72 | * a new instance. |
||||||||||||||||||||
73 | */ |
||||||||||||||||||||
74 | public static function register(interfaces\handlers\Exception $handler = null) : Exception |
||||||||||||||||||||
75 | { |
||||||||||||||||||||
76 | set_exception_handler([$handler ?: $handler = new static, 'handle']); |
||||||||||||||||||||
77 | |||||||||||||||||||||
78 | return $handler; |
||||||||||||||||||||
79 | } |
||||||||||||||||||||
80 | |||||||||||||||||||||
81 | /** |
||||||||||||||||||||
82 | * {@inheritDoc} |
||||||||||||||||||||
83 | * |
||||||||||||||||||||
84 | * Walks through all stacked Delegates in the order of their priority and passes the inspected Exception to |
||||||||||||||||||||
85 | * them until one of them returns a STOP or QUIT signal as defined in definitions\Signals or no more Delegates |
||||||||||||||||||||
86 | * are left. |
||||||||||||||||||||
87 | * |
||||||||||||||||||||
88 | * @param \Throwable $exception |
||||||||||||||||||||
89 | */ |
||||||||||||||||||||
90 | public function handle(\Throwable $exception) |
||||||||||||||||||||
91 | { |
||||||||||||||||||||
92 | // Being Emitter Aware we are bound to comply to the Events Definition. |
||||||||||||||||||||
93 | // self::emitDebugEvent() will return null when no Emitter is present. Otherwise we'll get the Exception |
||||||||||||||||||||
94 | // after it's been processed by Event Listeners so we need to overwrite it here. |
||||||||||||||||||||
95 | if (null !== $response = $this->emitDebugEvent(definitions\Events::DEBUG_EXCEPTION_BEFORE, $exception)) { |
||||||||||||||||||||
96 | $exception = $response; |
||||||||||||||||||||
97 | } |
||||||||||||||||||||
98 | |||||||||||||||||||||
99 | // First of all run all Conditions. The method will return true if we are to prevent further execution. |
||||||||||||||||||||
100 | if ($this->runConditions($exception)) { |
||||||||||||||||||||
101 | return; |
||||||||||||||||||||
102 | } |
||||||||||||||||||||
103 | |||||||||||||||||||||
104 | // Whether we will quit after the loop. Set to true when one of the Delegates returns a QUIT signal. |
||||||||||||||||||||
105 | $quit = false; |
||||||||||||||||||||
106 | |||||||||||||||||||||
107 | // Get the applicable Delegates. |
||||||||||||||||||||
108 | $delegates = array_intersect_key($this->delegates, array_flip($this->getApplicable())); |
||||||||||||||||||||
109 | |||||||||||||||||||||
110 | // If we've got anything to call later on, proceed. |
||||||||||||||||||||
111 | if (!empty($delegates)) { |
||||||||||||||||||||
112 | // Sort the Delegates by their priority. |
||||||||||||||||||||
113 | $this->sort($delegates); |
||||||||||||||||||||
114 | |||||||||||||||||||||
115 | // Inspect the Exception we got, which will give us an Inspector instance we can pass along. |
||||||||||||||||||||
116 | $inspector = $this->inspect($exception); |
||||||||||||||||||||
117 | |||||||||||||||||||||
118 | // Walk through all applicable Delegates and let them handle the Exception until done or one of them |
||||||||||||||||||||
119 | // returns a STOP/QUIT signal. |
||||||||||||||||||||
120 | foreach ($delegates as $v) { |
||||||||||||||||||||
121 | // If we're dealing with a Delegate instance, call its handle() method. If it's a casual callable, |
||||||||||||||||||||
122 | // call it and pass the Inspector as the only argument. |
||||||||||||||||||||
123 | $response = $v['delegate'] instanceof interfaces\Delegate |
||||||||||||||||||||
124 | ? $v['delegate']->handle($inspector) |
||||||||||||||||||||
125 | : call_user_func($v['delegate'], $inspector); |
||||||||||||||||||||
126 | |||||||||||||||||||||
127 | // Make it easier for inheriting children to act upon the response if it's not a signal. |
||||||||||||||||||||
128 | $response = $this->handleDelegateResponse($response, $inspector); |
||||||||||||||||||||
129 | |||||||||||||||||||||
130 | // Let's check if we've got a signal as response. If it's QUIT, we'll set a flag and handle it |
||||||||||||||||||||
131 | // after the loop. |
||||||||||||||||||||
132 | if (($response & definitions\Signals::QUIT) === definitions\Signals::QUIT) { |
||||||||||||||||||||
133 | $quit = true; |
||||||||||||||||||||
134 | } |
||||||||||||||||||||
135 | |||||||||||||||||||||
136 | // QUIT includes STOP so this will catch both situations. |
||||||||||||||||||||
137 | if (($response & definitions\Signals::STOP) === definitions\Signals::STOP) { |
||||||||||||||||||||
138 | break; |
||||||||||||||||||||
139 | } |
||||||||||||||||||||
140 | } |
||||||||||||||||||||
141 | } |
||||||||||||||||||||
142 | |||||||||||||||||||||
143 | // Now that we are done looping, time to attempt to emit the appropriate Event. |
||||||||||||||||||||
144 | $this->emitDebugEvent(definitions\Events::DEBUG_EXCEPTION_AFTER, $exception); |
||||||||||||||||||||
145 | |||||||||||||||||||||
146 | // If we were told to quit and the Handler allows this, do eet. |
||||||||||||||||||||
147 | if ($quit and $this->doesAllowQuit()) { |
||||||||||||||||||||
0 ignored issues
–
show
|
|||||||||||||||||||||
148 | exit; |
||||||||||||||||||||
149 | } |
||||||||||||||||||||
150 | |||||||||||||||||||||
151 | // Clear all lists. See the notes for {@see self::whitelist()} and {@see self::blacklist()} why Delegates |
||||||||||||||||||||
152 | // should be listed, for consistency, by Conditions *only*. |
||||||||||||||||||||
153 | $this->applicable = null; |
||||||||||||||||||||
0 ignored issues
–
show
It seems like
null of type null is incompatible with the declared type array of property $applicable .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||||||||||||||||||
154 | $this->whitelist = $this->blacklist = []; |
||||||||||||||||||||
155 | } |
||||||||||||||||||||
156 | |||||||||||||||||||||
157 | /** |
||||||||||||||||||||
158 | * Similar to {@see self::add()} but uses a different argument order - the name is required (as it is used |
||||||||||||||||||||
159 | * as a key) and the method will overwrite the given key (name) if it is already set. The usage of add() |
||||||||||||||||||||
160 | * instead is recommended. |
||||||||||||||||||||
161 | * |
||||||||||||||||||||
162 | * @param string $name The name of the Delegate. |
||||||||||||||||||||
163 | * @param interfaces\Delegate|callable $delegate The Delegate to be inserted into the stack. |
||||||||||||||||||||
164 | * @param int $priority The priority at which the Delegate should be invoked |
||||||||||||||||||||
165 | * when an exception gets handled. |
||||||||||||||||||||
166 | * Also {@see self::getHighestPriority()}. |
||||||||||||||||||||
167 | * @return $this |
||||||||||||||||||||
168 | * @throws \InvalidArgumentException When the argument passed is neither a callable nor |
||||||||||||||||||||
169 | * a Delegate. |
||||||||||||||||||||
170 | * @throws \InvalidArgumentException When the name contains invalid characters. Only letters, |
||||||||||||||||||||
171 | * digits and backslashes are allowed. |
||||||||||||||||||||
172 | */ |
||||||||||||||||||||
173 | public function set(string $name, $delegate, int $priority = 0) : self |
||||||||||||||||||||
174 | { |
||||||||||||||||||||
175 | // Make sure we've got a type we can work with. |
||||||||||||||||||||
176 | if (!$delegate instanceof interfaces\Delegate and !is_callable($delegate)) { |
||||||||||||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
|||||||||||||||||||||
177 | throw new \InvalidArgumentException("Exception handling delegates must be callables or instances of nyx\\diagnostics\\interfaces\\Delegate."); |
||||||||||||||||||||
178 | } |
||||||||||||||||||||
179 | |||||||||||||||||||||
180 | // Perform a little check to make sure we'll be able to black/whitelist with a regexp afterwards. |
||||||||||||||||||||
181 | if (!preg_match('/^[\\\d\w]+$/', $name)) { |
||||||||||||||||||||
182 | throw new \InvalidArgumentException("Delegate names may only contain letters, digits and backslashes, [$name] given."); |
||||||||||||||||||||
183 | } |
||||||||||||||||||||
184 | |||||||||||||||||||||
185 | $this->delegates[$name] = ['delegate' => $delegate, 'priority' => $priority]; |
||||||||||||||||||||
186 | $this->applicable = null; |
||||||||||||||||||||
0 ignored issues
–
show
It seems like
null of type null is incompatible with the declared type array of property $applicable .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||||||||||||||||||
187 | |||||||||||||||||||||
188 | // Keep track of the highest priority currently assigned. |
||||||||||||||||||||
189 | if ($priority > $this->highestPriority) { |
||||||||||||||||||||
190 | $this->highestPriority = $priority; |
||||||||||||||||||||
191 | } |
||||||||||||||||||||
192 | |||||||||||||||||||||
193 | return $this; |
||||||||||||||||||||
194 | } |
||||||||||||||||||||
195 | |||||||||||||||||||||
196 | /** |
||||||||||||||||||||
197 | * Adds the given Delegate with the given optional priority to the stack. |
||||||||||||||||||||
198 | * |
||||||||||||||||||||
199 | * @param interfaces\Delegate|callable $delegate The Delegate to be inserted into the stack. |
||||||||||||||||||||
200 | * @param string $name The name of the Delegate. Has to be unique. If none is |
||||||||||||||||||||
201 | * given, the full (ie. with namespace) classname will be |
||||||||||||||||||||
202 | * be for Delegates and "c\{mt_rand()}" for callables. |
||||||||||||||||||||
203 | * *Also* has to be unique. In other words - If you add an |
||||||||||||||||||||
204 | * instance of the same class (or even the same instance) |
||||||||||||||||||||
205 | * multiple times, assign different names. |
||||||||||||||||||||
206 | * @param int $priority The priority at which the Delegate should be invoked |
||||||||||||||||||||
207 | * when an exception gets handled. |
||||||||||||||||||||
208 | * Also {@see self::getHighestPriority()}. |
||||||||||||||||||||
209 | * @return $this |
||||||||||||||||||||
210 | * @throws \OverflowException When the given name (or when not given, the class name) |
||||||||||||||||||||
211 | * is already set. |
||||||||||||||||||||
212 | */ |
||||||||||||||||||||
213 | public function add($delegate, string $name = null, int $priority = 0) : self |
||||||||||||||||||||
214 | { |
||||||||||||||||||||
215 | // Which name should we use? |
||||||||||||||||||||
216 | // Micro-optimization note: mt_rand() turned out to be several times faster than uniqid and somewhat |
||||||||||||||||||||
217 | // faster than counting the current number of delegates. |
||||||||||||||||||||
218 | $name = $name ?: ($delegate instanceof interfaces\Delegate ? get_class($delegate) : 'c\\'.mt_rand()); |
||||||||||||||||||||
219 | |||||||||||||||||||||
220 | if (isset($this->delegates[$name])) { |
||||||||||||||||||||
221 | throw new \OverflowException("A Delegate with the given name [$name] is already set."); |
||||||||||||||||||||
222 | } |
||||||||||||||||||||
223 | |||||||||||||||||||||
224 | return $this->set($name, $delegate, $priority); |
||||||||||||||||||||
225 | } |
||||||||||||||||||||
226 | |||||||||||||||||||||
227 | /** |
||||||||||||||||||||
228 | * Removes a specific Delegate or callable from the stack. |
||||||||||||||||||||
229 | * |
||||||||||||||||||||
230 | * Important note: This will remove all *instances* of the given Delegate if it passes the strict match unless |
||||||||||||||||||||
231 | * $all is set to false *or* a name is used instead of an instance as the first argument to this method, since |
||||||||||||||||||||
232 | * Delegate names are unique within this Handler. |
||||||||||||||||||||
233 | * |
||||||||||||||||||||
234 | * @param string|interfaces\Delegate|callable $delegate Either the name of the Delegate/callable or |
||||||||||||||||||||
235 | * an actual instance to search for. |
||||||||||||||||||||
236 | * @param bool $all Whether to search for all matches (true) or stop |
||||||||||||||||||||
237 | * after the first match (false). |
||||||||||||||||||||
238 | * @return $this |
||||||||||||||||||||
239 | */ |
||||||||||||||||||||
240 | public function remove($delegate, bool $all = true) : self |
||||||||||||||||||||
241 | { |
||||||||||||||||||||
242 | // When a string was passed, we will need to distinguish what to compare within our search. |
||||||||||||||||||||
243 | $name = is_string($delegate) ? $delegate : null; |
||||||||||||||||||||
244 | |||||||||||||||||||||
245 | foreach ($this->delegates as $k => $v) { |
||||||||||||||||||||
246 | if (($name and $k === $name) or (!$name and $v['delegate'] === $delegate)) { |
||||||||||||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() Comprehensibility
Best Practice
introduced
by
Using logical operators such as
or instead of || is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
|||||||||||||||||||||
247 | unset($this->delegates[$k]); |
||||||||||||||||||||
248 | $this->applicable = null; |
||||||||||||||||||||
0 ignored issues
–
show
It seems like
null of type null is incompatible with the declared type array of property $applicable .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||||||||||||||||||
249 | |||||||||||||||||||||
250 | if ($name or false === $all) { |
||||||||||||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
or instead of || is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
|||||||||||||||||||||
251 | break; |
||||||||||||||||||||
252 | } |
||||||||||||||||||||
253 | } |
||||||||||||||||||||
254 | } |
||||||||||||||||||||
255 | |||||||||||||||||||||
256 | return $this; |
||||||||||||||||||||
257 | } |
||||||||||||||||||||
258 | |||||||||||||||||||||
259 | /** |
||||||||||||||||||||
260 | * Adds the given Delegate name to the blacklist. |
||||||||||||||||||||
261 | * |
||||||||||||||||||||
262 | * Note: Blacklisting *should* be performed within Conditions as the blacklist will be cleared after each |
||||||||||||||||||||
263 | * handle() call and therefore the blacklist only applies to the very next call. Normally this shouldn't be |
||||||||||||||||||||
264 | * an issue as the default assumption is that the Exception Handler only gets invoked for uncaught exceptions, |
||||||||||||||||||||
265 | * but... well, you catch the drift. |
||||||||||||||||||||
266 | * |
||||||||||||||||||||
267 | * @param string|array $name A regex of the Delegates to blacklist or an array of REs. The regex must |
||||||||||||||||||||
268 | * be provided *without* the delimiters as they will be added automatically |
||||||||||||||||||||
269 | * (therefore - no special flags etc.). |
||||||||||||||||||||
270 | * @return $this |
||||||||||||||||||||
271 | */ |
||||||||||||||||||||
272 | public function blacklist($name) : self |
||||||||||||||||||||
273 | { |
||||||||||||||||||||
274 | return $this->pushToList($this->blacklist, $name); |
||||||||||||||||||||
275 | } |
||||||||||||||||||||
276 | |||||||||||||||||||||
277 | /** |
||||||||||||||||||||
278 | * Adds the given Delegate name to the whitelist. |
||||||||||||||||||||
279 | * |
||||||||||||||||||||
280 | * Note: Whitelisting *should* be performed within Conditions as the whitelist will be cleared after each |
||||||||||||||||||||
281 | * handle() call and therefore the whitelist only applies to the very next call. Normally this shouldn't be |
||||||||||||||||||||
282 | * an issue as the default assumption is that the Exception Handler only gets invoked for uncaught exceptions, |
||||||||||||||||||||
283 | * but... well, you catch the drift. |
||||||||||||||||||||
284 | * |
||||||||||||||||||||
285 | * @param string|array $name A regex of the Delegates to whitelist or an array of REs. The regex must |
||||||||||||||||||||
286 | * be provided *without* the delimiters as they will be added automatically |
||||||||||||||||||||
287 | * (therefore - no special flags etc.). |
||||||||||||||||||||
288 | * @return $this |
||||||||||||||||||||
289 | */ |
||||||||||||||||||||
290 | public function whitelist($name) : self |
||||||||||||||||||||
291 | { |
||||||||||||||||||||
292 | return $this->pushToList($this->whitelist, $name); |
||||||||||||||||||||
293 | } |
||||||||||||||||||||
294 | |||||||||||||||||||||
295 | /** |
||||||||||||||||||||
296 | * Returns all registered Delegates, in the order they were added. See {@see self::$delegates} for more info |
||||||||||||||||||||
297 | * on the structure. |
||||||||||||||||||||
298 | * |
||||||||||||||||||||
299 | * @return array |
||||||||||||||||||||
300 | */ |
||||||||||||||||||||
301 | public function all() : array |
||||||||||||||||||||
302 | { |
||||||||||||||||||||
303 | return $this->delegates; |
||||||||||||||||||||
304 | } |
||||||||||||||||||||
305 | |||||||||||||||||||||
306 | /** |
||||||||||||||||||||
307 | * Returns an array containing the names of all Delegates which are applicable for the next call to |
||||||||||||||||||||
308 | * self::handle(), ie. after computing which of them are black-or-whitelisted. |
||||||||||||||||||||
309 | * |
||||||||||||||||||||
310 | * @return array |
||||||||||||||||||||
311 | */ |
||||||||||||||||||||
312 | public function getApplicable() : array |
||||||||||||||||||||
313 | { |
||||||||||||||||||||
314 | // If we've already compiled the list and nothing changed, return it. |
||||||||||||||||||||
315 | if (null !== $this->applicable) { |
||||||||||||||||||||
316 | return $this->applicable; |
||||||||||||||||||||
317 | } |
||||||||||||||||||||
318 | |||||||||||||||||||||
319 | $delegates = array_keys($this->delegates); |
||||||||||||||||||||
320 | |||||||||||||||||||||
321 | // No need for any fancy magic if we've got no black/whitelist. |
||||||||||||||||||||
322 | if (empty($this->whitelist) and empty($this->blacklist)) { |
||||||||||||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
|||||||||||||||||||||
323 | return $this->applicable = $delegates; |
||||||||||||||||||||
324 | } |
||||||||||||||||||||
325 | |||||||||||||||||||||
326 | // Compile the lists by performing regex matches over the existing Delegate names. |
||||||||||||||||||||
327 | if (!empty($this->whitelist)) { |
||||||||||||||||||||
328 | $whitelist = $this->compileList($this->whitelist, $delegates); |
||||||||||||||||||||
329 | } |
||||||||||||||||||||
330 | |||||||||||||||||||||
331 | if (!empty($this->blacklist)) { |
||||||||||||||||||||
332 | $blacklist = $this->compileList($this->blacklist, $delegates); |
||||||||||||||||||||
333 | } |
||||||||||||||||||||
334 | |||||||||||||||||||||
335 | // No need to proceed further if we didn't actually black/whitelist any currently added Delegates. |
||||||||||||||||||||
336 | if (empty($whitelist) and empty($blacklist)) { |
||||||||||||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
|||||||||||||||||||||
337 | return $this->applicable = $delegates; |
||||||||||||||||||||
338 | } |
||||||||||||||||||||
339 | |||||||||||||||||||||
340 | // Further checks. |
||||||||||||||||||||
341 | if (empty($whitelist)) { |
||||||||||||||||||||
342 | return $this->applicable = array_diff($delegates, $blacklist); |
||||||||||||||||||||
0 ignored issues
–
show
The variable
$blacklist does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||||||||||||||||||||
343 | } |
||||||||||||||||||||
344 | |||||||||||||||||||||
345 | if (empty($blacklist)) { |
||||||||||||||||||||
346 | return $this->applicable = $whitelist; |
||||||||||||||||||||
347 | } |
||||||||||||||||||||
348 | |||||||||||||||||||||
349 | // Well, seems neither of the lists is empty, so time for a little magic. |
||||||||||||||||||||
350 | return $this->applicable = $this->prioritizeBlacklist |
||||||||||||||||||||
351 | ? array_diff($whitelist, $blacklist) |
||||||||||||||||||||
352 | : array_intersect($whitelist, $blacklist); |
||||||||||||||||||||
353 | } |
||||||||||||||||||||
354 | |||||||||||||||||||||
355 | /** |
||||||||||||||||||||
356 | * Removes all Delegates from the stack. |
||||||||||||||||||||
357 | * |
||||||||||||||||||||
358 | * @return $this |
||||||||||||||||||||
359 | */ |
||||||||||||||||||||
360 | |||||||||||||||||||||
361 | public function flush() |
||||||||||||||||||||
362 | { |
||||||||||||||||||||
363 | $this->delegates = []; |
||||||||||||||||||||
364 | $this->applicable = null; |
||||||||||||||||||||
0 ignored issues
–
show
It seems like
null of type null is incompatible with the declared type array of property $applicable .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||||||||||||||||||
365 | |||||||||||||||||||||
366 | return $this; |
||||||||||||||||||||
367 | } |
||||||||||||||||||||
368 | |||||||||||||||||||||
369 | /** |
||||||||||||||||||||
370 | * Sets whether the blacklist overrides the whitelist. Ie. when a given Delegate name is present in both arrays |
||||||||||||||||||||
371 | * it will be treated as blacklisted. |
||||||||||||||||||||
372 | * |
||||||||||||||||||||
373 | * @param bool $bool True to have the blacklist override the whitelist, false otherwise. |
||||||||||||||||||||
374 | */ |
||||||||||||||||||||
375 | |||||||||||||||||||||
376 | public function setPrioritizeBlacklist($bool) |
||||||||||||||||||||
377 | { |
||||||||||||||||||||
378 | $this->prioritizeBlacklist = (bool) $bool; |
||||||||||||||||||||
379 | } |
||||||||||||||||||||
380 | |||||||||||||||||||||
381 | /** |
||||||||||||||||||||
382 | * Checks whether the blacklist overrides the whitelist. Ie. when a given Delegate name is present in both |
||||||||||||||||||||
383 | * arrays it will be treated as blacklisted. |
||||||||||||||||||||
384 | * |
||||||||||||||||||||
385 | * @return bool True when the blacklist overrides the whitelist, false otherwise. |
||||||||||||||||||||
386 | */ |
||||||||||||||||||||
387 | |||||||||||||||||||||
388 | public function doesPrioritizeBlacklist() |
||||||||||||||||||||
389 | { |
||||||||||||||||||||
390 | return $this->prioritizeBlacklist; |
||||||||||||||||||||
391 | } |
||||||||||||||||||||
392 | |||||||||||||||||||||
393 | /** |
||||||||||||||||||||
394 | * Returns the highest priority currently assigned to any Delegate/callable. |
||||||||||||||||||||
395 | * |
||||||||||||||||||||
396 | * Could be used to provide sane priorities when adding Delegates, if you want to ensure that at the given |
||||||||||||||||||||
397 | * runtime moment the given Delegate takes top-priority but assume that something even more important might |
||||||||||||||||||||
398 | * get registered and therefore don't want to use some ridiculously high int like max_int. |
||||||||||||||||||||
399 | * |
||||||||||||||||||||
400 | * @return int |
||||||||||||||||||||
401 | */ |
||||||||||||||||||||
402 | |||||||||||||||||||||
403 | public function getHighestPriority() |
||||||||||||||||||||
404 | { |
||||||||||||||||||||
405 | return $this->highestPriority; |
||||||||||||||||||||
406 | } |
||||||||||||||||||||
407 | |||||||||||||||||||||
408 | /** |
||||||||||||||||||||
409 | * Sorts the given Delegates by their priority, highest first. |
||||||||||||||||||||
410 | * |
||||||||||||||||||||
411 | * @param array &$delegates The Delegates to sort. |
||||||||||||||||||||
412 | * @return $this |
||||||||||||||||||||
413 | */ |
||||||||||||||||||||
414 | protected function sort(array &$delegates) : self |
||||||||||||||||||||
415 | { |
||||||||||||||||||||
416 | uasort($delegates, function($a, $b) { |
||||||||||||||||||||
417 | return $b['priority'] - $a['priority']; |
||||||||||||||||||||
418 | }); |
||||||||||||||||||||
419 | |||||||||||||||||||||
420 | return $this; |
||||||||||||||||||||
421 | } |
||||||||||||||||||||
422 | |||||||||||||||||||||
423 | /** |
||||||||||||||||||||
424 | * Pushes the given values to either the black-or-white-list. |
||||||||||||||||||||
425 | * |
||||||||||||||||||||
426 | * @param array &$list Either $this->blacklist or $this->whitelist. |
||||||||||||||||||||
427 | * @param string|array $name {@see self::blacklist()} or {@see self::whitelist()} |
||||||||||||||||||||
428 | * @return $this |
||||||||||||||||||||
429 | */ |
||||||||||||||||||||
430 | protected function pushToList(array &$list, $name) : self |
||||||||||||||||||||
431 | { |
||||||||||||||||||||
432 | // Handle arrays (recursively). |
||||||||||||||||||||
433 | if (is_array($name)) { |
||||||||||||||||||||
434 | foreach ($name as $single) { |
||||||||||||||||||||
435 | $this->pushToList($list, $single); |
||||||||||||||||||||
436 | } |
||||||||||||||||||||
437 | return $this; |
||||||||||||||||||||
438 | } |
||||||||||||||||||||
439 | |||||||||||||||||||||
440 | $list[] = $name; |
||||||||||||||||||||
441 | |||||||||||||||||||||
442 | // Reset the applicable Delegates as we will need to recompile the list. |
||||||||||||||||||||
443 | $this->applicable = null; |
||||||||||||||||||||
0 ignored issues
–
show
It seems like
null of type null is incompatible with the declared type array of property $applicable .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||||||||||||||||||
444 | |||||||||||||||||||||
445 | return $this; |
||||||||||||||||||||
446 | } |
||||||||||||||||||||
447 | |||||||||||||||||||||
448 | /** |
||||||||||||||||||||
449 | * Compiles the given black-or-white-list based on the given Delegate names, ie. run regex matches against |
||||||||||||||||||||
450 | * the Delegate names. |
||||||||||||||||||||
451 | * |
||||||||||||||||||||
452 | * @param array &$list Either $this->blacklist or $this->whitelist. |
||||||||||||||||||||
453 | * @param array $delegates An array of Delegate names that should be considered. |
||||||||||||||||||||
454 | * @return array The compiled List. |
||||||||||||||||||||
455 | */ |
||||||||||||||||||||
456 | protected function compileList(array &$list, array $delegates) |
||||||||||||||||||||
457 | { |
||||||||||||||||||||
458 | $return = []; |
||||||||||||||||||||
459 | |||||||||||||||||||||
460 | foreach ($list as $name) { |
||||||||||||||||||||
461 | $return[] = preg_grep('/'.$name.'/', $delegates); |
||||||||||||||||||||
462 | } |
||||||||||||||||||||
463 | |||||||||||||||||||||
464 | return call_user_func_array('array_merge', $return); |
||||||||||||||||||||
465 | } |
||||||||||||||||||||
466 | |||||||||||||||||||||
467 | /** |
||||||||||||||||||||
468 | * Returns an Inspector instance for the given exception. Kept separately from self::handle() in case you |
||||||||||||||||||||
469 | * intend to use a custom Inspector. |
||||||||||||||||||||
470 | * |
||||||||||||||||||||
471 | * @param \Exception $exception The exception which is to be inspected. |
||||||||||||||||||||
472 | * @return debug\Inspector An exception Inspector instance. |
||||||||||||||||||||
473 | */ |
||||||||||||||||||||
474 | protected function inspect(\Exception $exception) : debug\Inspector |
||||||||||||||||||||
475 | { |
||||||||||||||||||||
476 | return new debug\Inspector($exception, $this); |
||||||||||||||||||||
477 | } |
||||||||||||||||||||
478 | |||||||||||||||||||||
479 | /** |
||||||||||||||||||||
480 | * Handles a Delegate's response before the handle() method resolves the return signal. Allows to override |
||||||||||||||||||||
481 | * the signal by the Handler or act upon responses that are not signals. |
||||||||||||||||||||
482 | * |
||||||||||||||||||||
483 | * You might use this method to, for example, intercept delegate responses, generate a HTTP Response from |
||||||||||||||||||||
484 | * them and stop further delegation by returning a STOP signal yourself. |
||||||||||||||||||||
485 | * |
||||||||||||||||||||
486 | * @param mixed $response The response of the last Delegate. |
||||||||||||||||||||
487 | * @param debug\Inspector $inspector The Inspector handling the Exception. |
||||||||||||||||||||
488 | * @return mixed |
||||||||||||||||||||
489 | */ |
||||||||||||||||||||
490 | protected function handleDelegateResponse($response, debug\Inspector $inspector) |
||||||||||||||||||||
491 | { |
||||||||||||||||||||
492 | return $response; |
||||||||||||||||||||
493 | } |
||||||||||||||||||||
494 | } |
||||||||||||||||||||
495 |
PHP has two types of connecting operators (logical operators, and boolean operators):
and
&&
or
||
The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like
&&
, or||
.Let’s take a look at a few examples:
Logical Operators are used for Control-Flow
One case where you explicitly want to use logical operators is for control-flow such as this:
Since
die
introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined withthrow
at this point:These limitations lead to logical operators rarely being of use in current PHP code.