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.. Loading history...
|
|||||||||||||||||||||
| 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. Loading history...
|
|||||||||||||||||||||
| 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.. Loading history...
|
|||||||||||||||||||||
| 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. Loading history...
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. Loading history...
|
|||||||||||||||||||||
| 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.. Loading history...
|
|||||||||||||||||||||
| 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. Loading history...
|
|||||||||||||||||||||
| 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. Loading history...
|
|||||||||||||||||||||
| 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. Loading history...
|
|||||||||||||||||||||
| 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
Loading history...
|
|||||||||||||||||||||
| 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.. Loading history...
|
|||||||||||||||||||||
| 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.. Loading history...
|
|||||||||||||||||||||
| 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
dieintroduces 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 withthrowat this point:These limitations lead to logical operators rarely being of use in current PHP code.