Errors   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 120
ccs 44
cts 44
cp 1
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 3

5 Methods

Rating   Name   Duplication   Size   Complexity  
A dispatchError() 0 14 4
A dispatchException() 0 15 4
A sendMessage() 0 6 2
A getErrorTypeByCode() 0 13 5
B isIgnored() 0 10 7
1
<?php
2
3
namespace PhpConsole\Dispatcher;
4
use PhpConsole\Dispatcher;
5
use PhpConsole\ErrorMessage;
6
use PhpConsole\Message;
7
8
/**
9
 * Sends system errors and exceptions to connector as client expected messages
10
 *
11
 * @package PhpConsole
12
 * @version 3.1
13
 * @link http://consle.com
14
 * @author Sergey Barbushin http://linkedin.com/in/barbushin
15
 * @copyright © Sergey Barbushin, 2011-2013. All rights reserved.
16
 * @license http://www.opensource.org/licenses/BSD-3-Clause "The BSD 3-Clause License"
17
 */
18
class Errors extends Dispatcher {
19
20
	/** @var array PHP errors constants values => names(will be initialized in first call) */
21
	protected static $errorsConstantsValues = array();
22
	/** @var array PHP errors constants names */
23
	protected static $errorsConstantsNames = array(
24
		'E_STRICT',
25
		'E_DEPRECATED',
26
		'E_RECOVERABLE_ERROR',
27
		'E_NOTICE',
28
		'E_WARNING',
29
		'E_ERROR',
30
		'E_PARSE',
31
		'E_USER_DEPRECATED',
32
		'E_USER_NOTICE',
33
		'E_USER_WARNING',
34
		'E_USER_ERROR',
35
		'E_CORE_WARNING',
36
		'E_CORE_ERROR',
37
		'E_COMPILE_ERROR',
38
		'E_COMPILE_WARNING',
39
	);
40
41
	/** @var bool Don't send errors messages with same file, line & class */
42
	public $ignoreRepeatedSource = true;
43
	/** @var bool Dispatch $exception->getPrevious() if not empty */
44
	public $dispatchPreviousExceptions = true;
45
46
	/** @var ErrorMessage[] */
47
	protected $sentMessages = array();
48
49
	/**
50
	 * Send error message to client
51
	 * @param null|integer $code
52
	 * @param null|string $text
53
	 * @param null|string $file
54
	 * @param null|integer $line
55
	 * @param int|array $ignoreTraceCalls Ignore tracing classes by name prefix `array('PhpConsole')` or fixed number of calls to ignore
56
	 */
57 18
	public function dispatchError($code = null, $text = null, $file = null, $line = null, $ignoreTraceCalls = 0) {
58 18
		if($this->isActive()) {
59 17
			$message = new ErrorMessage();
60 17
			$message->code = $code;
61 17
			$message->class = $this->getErrorTypeByCode($code);
62 17
			$message->data = $this->dumper->dump($text);
63 17
			$message->file = $file;
64 17
			$message->line = $line;
65 17
			if($ignoreTraceCalls !== null) {
66 17
				$message->trace = $this->fetchTrace(debug_backtrace(), $file, $line, is_array($ignoreTraceCalls) ? $ignoreTraceCalls : $ignoreTraceCalls + 1);
0 ignored issues
show
Bug introduced by
It seems like is_array($ignoreTraceCal...: $ignoreTraceCalls + 1 can also be of type array; however, PhpConsole\Dispatcher::fetchTrace() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
67
			}
68 17
			$this->sendMessage($message);
69
		}
70 18
	}
71
72
	/**
73
	 * Send exception message to client
74
	 * @param \Exception|\Throwable $exception
75
	 */
76 14
	public function dispatchException($exception) {
77 14
		if($this->isActive()) {
78 14
			if($this->dispatchPreviousExceptions && $exception->getPrevious()) {
79 1
				$this->dispatchException($exception->getPrevious());
80
			}
81 14
			$message = new ErrorMessage();
82 14
			$message->code = $exception->getCode();
83 14
			$message->class = get_class($exception);
84 14
			$message->data = $this->dumper->dump($exception->getMessage());
85 14
			$message->file = $exception->getFile();
86 14
			$message->line = $exception->getLine();
87 14
			$message->trace = self::fetchTrace($exception->getTrace(), $message->file, $message->line);
88 14
			$this->sendMessage($message);
89
		}
90 14
	}
91
92
	/**
93
	 * Send message to PHP Console connector
94
	 * @param Message $message
95
	 */
96 31
	protected function sendMessage(Message $message) {
97 31
		if(!$this->isIgnored($message)) {
0 ignored issues
show
Compatibility introduced by
$message of type object<PhpConsole\Message> is not a sub-type of object<PhpConsole\ErrorMessage>. It seems like you assume a child class of the class PhpConsole\Message to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
98 31
			parent::sendMessage($message);
99 31
			$this->sentMessages[] = $message;
100
		}
101 31
	}
102
103
	/**
104
	 * Get PHP error constant name by value
105
	 * @param int $code
106
	 * @return string
107
	 */
108 17
	protected function getErrorTypeByCode($code) {
109 17
		if(!static::$errorsConstantsValues) {
0 ignored issues
show
Bug Best Practice introduced by
The expression static::$errorsConstantsValues of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
110 17
			foreach(static::$errorsConstantsNames as $constantName) {
111 17
				if(defined($constantName)) {
112 17
					static::$errorsConstantsValues[constant($constantName)] = $constantName;
113
				}
114
			}
115
		}
116 17
		if(isset(static::$errorsConstantsValues[$code])) {
117 5
			return static::$errorsConstantsValues[$code];
118
		}
119 12
		return (string)$code;
120
	}
121
122
	/**
123
	 * Return true if message with same file, line & class was already sent
124
	 * @param ErrorMessage $message
125
	 * @return bool
126
	 */
127 31
	protected function isIgnored(ErrorMessage $message) {
128 31
		if($this->ignoreRepeatedSource && $message->file) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $message->file of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
129 18
			foreach($this->sentMessages as $sentMessage) {
130 4
				if($message->file == $sentMessage->file && $message->line == $sentMessage->line && $message->class == $sentMessage->class) {
131 4
					return true;
132
				}
133
			}
134
		}
135 31
		return false;
136
	}
137
}
138