1 <?php
2 /*
3  * This file is part of PHPUnit.
4  *
5  * (c) Sebastian Bergmann <sebastian@phpunit.de>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10 
11 // Workaround for http://bugs.php.net/bug.php?id=47987,
12 // see https://github.com/sebastianbergmann/phpunit/issues#issue/125 for details
13 // Use dirname(__DIR__) instead of using /../ because of https://github.com/facebook/hhvm/issues/5215
14 require_once dirname(__DIR__) . '/Framework/Error.php';
15 require_once dirname(__DIR__) . '/Framework/Error/Notice.php';
16 require_once dirname(__DIR__) . '/Framework/Error/Warning.php';
17 require_once dirname(__DIR__) . '/Framework/Error/Deprecated.php';
18 
19 /**
20  * Error handler that converts PHP errors and warnings to exceptions.
21  */
22 class PHPUnit_Util_ErrorHandler
23 {
24     protected static $errorStack = [];
25 
26     /**
27      * Returns the error stack.
28      *
29      * @return array
30      */
31     public static function getErrorStack()
32     {
33         return self::$errorStack;
34     }
35 
36     /**
37      * @param int    $errno
38      * @param string $errstr
39      * @param string $errfile
40      * @param int    $errline
41      *
42      * @throws PHPUnit_Framework_Error
43      */
44     public static function handleError($errno, $errstr, $errfile, $errline)
45     {
46         if (!($errno & error_reporting())) {
47             return false;
48         }
49 
50         self::$errorStack[] = [$errno, $errstr, $errfile, $errline];
51 
52         $trace = debug_backtrace(false);
53         array_shift($trace);
54 
55         foreach ($trace as $frame) {
56             if ($frame['function'] == '__toString') {
57                 return false;
58             }
59         }
60 
61         if ($errno == E_NOTICE || $errno == E_USER_NOTICE || $errno == E_STRICT) {
62             if (PHPUnit_Framework_Error_Notice::$enabled !== true) {
63                 return false;
64             }
65 
66             $exception = 'PHPUnit_Framework_Error_Notice';
67         } elseif ($errno == E_WARNING || $errno == E_USER_WARNING) {
68             if (PHPUnit_Framework_Error_Warning::$enabled !== true) {
69                 return false;
70             }
71 
72             $exception = 'PHPUnit_Framework_Error_Warning';
73         } elseif ($errno == E_DEPRECATED || $errno == E_USER_DEPRECATED) {
74             if (PHPUnit_Framework_Error_Deprecated::$enabled !== true) {
75                 return false;
76             }
77 
78             $exception = 'PHPUnit_Framework_Error_Deprecated';
79         } else {
80             $exception = 'PHPUnit_Framework_Error';
81         }
82 
83         throw new $exception($errstr, $errno, $errfile, $errline);
84     }
85 
86     /**
87      * Registers an error handler and returns a function that will restore
88      * the previous handler when invoked
89      *
90      * @param int $severity PHP predefined error constant
91      *
92      * @throws Exception if event of specified severity is emitted
93      */
94     public static function handleErrorOnce($severity = E_WARNING)
95     {
96         $terminator = function () {
97             static $expired = false;
98             if (!$expired) {
99                 $expired = true;
100                 // cleans temporary error handler
101                 return restore_error_handler();
102             }
103         };
104 
105         set_error_handler(function ($errno, $errstr) use ($severity) {
106             if ($errno === $severity) {
107                 return;
108             }
109 
110             return false;
111         });
112 
113         return $terminator;
114     }
115 }
116