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
14require_once dirname(__DIR__) . '/Framework/Error.php';
15require_once dirname(__DIR__) . '/Framework/Error/Notice.php';
16require_once dirname(__DIR__) . '/Framework/Error/Warning.php';
17require_once dirname(__DIR__) . '/Framework/Error/Deprecated.php';
18
19/**
20 * Error handler that converts PHP errors and warnings to exceptions.
21 */
22class 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