Failed Conditions
Push — master ( 63ec91...ac34b9 )
by Arnold
03:24
created

HandleUncaughtError::handleError()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 18
ccs 12
cts 12
cp 1
rs 8.8571
cc 6
eloc 10
nc 7
nop 5
crap 6
1
<?php
2
3
namespace Jasny\ErrorHandler;
4
5
/**
6
 * Trait for handling uncaught errors using PHP's error handler
7
 */
8
trait HandleUncaughtError
9
{
10
    /**
11
     * @var callable|false
12
     */
13
    protected $chainedErrorHandler;
14
15
    /**
16
     * Convert fatal errors to exceptions
17
     * @var boolean
18
     */
19
    protected $convertFatalErrors = false;
20
    
21
    /**
22
     * Log the following error types (in addition to caugth errors)
23
     * @var int
24
     */
25
    protected $logErrorTypes = 0;
26
    
27
28
    /**
29
     * Run the fatal error callback
30
     * 
31
     * @param \Exception|\Error $error
32
     */
33
    abstract protected function callOnFatalError($error);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
34
35
    /**
36
     * Wrapper method for `error_reporting`
37
     * 
38
     * @return int
39
     */
40
    abstract protected function errorReporting();
41
42
    /**
43
     * Wrapper method for `set_error_handler`
44
     * 
45
     * @param callable $callback
46
     * @param int      $error_types
47
     * @return callable|null
48
     */
49
    abstract protected function setErrorHandler($callback, $error_types = E_ALL);
50
51
    /**
52
     * Register the shutdown function
53
     */
54
    abstract protected function initShutdownFunction();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
55
56
    /**
57
     * Log an error or exception
58
     * 
59
     * @param \Exception|\Error $error
60
     */
61
    abstract public function log($error);
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
62
63
64
    /**
65
     * Get the error handler that has been replaced.
66
     * 
67
     * @return callable|false|null
68
     */
69 2
    public function getChainedErrorHandler()
70
    {
71 2
        return $this->chainedErrorHandler;
72
    }
73
    
74
    /**
75
     * Get the types of errors that will be logged
76
     * 
77
     * @return int  Binary set of E_* constants
78
     */
79 22
    public function getLoggedErrorTypes()
80
    {
81 22
        return $this->logErrorTypes;
82
    }
83
84
    /**
85
     * Log these types of errors or exceptions
86
     * 
87
     * @param int $type  E_* contants as binary set
88
     */
89 66
    protected function logUncaughtErrors($type)
90
    {
91 66
        $this->logErrorTypes |= $type;
92
93 66
        $unhandled = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR;
94
95 66
        if ($type & ~$unhandled) {
96 56
            $this->initErrorHandler();
97 28
        }
98
99 66
        if ($type & $unhandled) {
100 32
            $this->initShutdownFunction();
101 16
        }
102 66
    }
103
104
    
105
    /**
106
     * Use the global error handler to convert E_USER_ERROR and E_RECOVERABLE_ERROR to an ErrorException
107
     */
108 28
    public function converErrorsToExceptions()
109
    {
110 28
        $this->convertFatalErrors = true;
111 28
        $this->initErrorHandler();
112 28
    }
113
    
114
115
    /**
116
     * Use the global error handler
117
     */
118 84
    protected function initErrorHandler()
119
    {
120 84
        if (!isset($this->chainedErrorHandler)) {
121 84
            $this->chainedErrorHandler = $this->setErrorHandler([$this, 'handleError']) ?: false;
122 42
        }
123 84
    }
124
    
125
    /**
126
     * Uncaught error handler
127
     * @ignore
128
     * 
129
     * @param int    $type
130
     * @param string $message
131
     * @param string $file
132
     * @param int    $line
133
     * @param array  $context
134
     */
135 52
    public function handleError($type, $message, $file, $line, $context)
136
    {
137 52
        if ($this->errorReporting() & $type) {
138 52
            $error = new \ErrorException($message, 0, $type, $file, $line);
139
140 52
            if ($this->convertFatalErrors && ($type & (E_RECOVERABLE_ERROR | E_USER_ERROR))) {
141 8
                throw $error;
142
            }
143
144 44
            if ($this->logErrorTypes & $type) {
145 12
                $this->log($error);
146 6
            }
147 22
        }
148
        
149 44
        return $this->chainedErrorHandler
150 22
            ? call_user_func($this->chainedErrorHandler, $type, $message, $file, $line, $context)
151 44
            : false;
152
    }
153
}
154
155