Added ErrorHandler::call() method utility to turns any PHP warnings into \ErrorException
This commit is contained in:
parent
588890aea8
commit
0faa855b5e
@ -5,3 +5,4 @@ CHANGELOG
|
||||
-----
|
||||
|
||||
* added the component
|
||||
* added `ErrorHandler::call()` method utility to turn any PHP error into `\ErrorException`
|
||||
|
@ -153,6 +153,32 @@ class ErrorHandler
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a function and turns any PHP error into \ErrorException.
|
||||
*
|
||||
* @return mixed What $function(...$arguments) returns
|
||||
*
|
||||
* @throws \ErrorException When $function(...$arguments) triggers a PHP error
|
||||
*/
|
||||
public static function call(callable $function, ...$arguments)
|
||||
{
|
||||
set_error_handler(static function (int $type, string $message, string $file, int $line) {
|
||||
if (__FILE__ === $file) {
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
|
||||
$file = $trace[2]['file'] ?? $file;
|
||||
$line = $trace[2]['line'] ?? $line;
|
||||
}
|
||||
|
||||
throw new \ErrorException($message, 0, $type, $file, $line);
|
||||
});
|
||||
|
||||
try {
|
||||
return $function(...$arguments);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(BufferingLogger $bootstrappingLogger = null)
|
||||
{
|
||||
if ($bootstrappingLogger) {
|
||||
|
@ -123,11 +123,62 @@ class ErrorHandlerTest extends TestCase
|
||||
}
|
||||
|
||||
// dummy function to test trace in error handler.
|
||||
private static function triggerNotice($that)
|
||||
public static function triggerNotice($that)
|
||||
{
|
||||
$that->assertSame('', $foo.$foo.$bar);
|
||||
}
|
||||
|
||||
public function testFailureCall()
|
||||
{
|
||||
$this->expectException(\ErrorException::class);
|
||||
$this->expectExceptionMessage('fopen(unknown.txt): failed to open stream: No such file or directory');
|
||||
|
||||
ErrorHandler::call('fopen', 'unknown.txt', 'r');
|
||||
}
|
||||
|
||||
public function testCallRestoreErrorHandler()
|
||||
{
|
||||
$prev = set_error_handler('var_dump');
|
||||
try {
|
||||
ErrorHandler::call('fopen', 'unknown.txt', 'r');
|
||||
$this->fail('An \ErrorException should have been raised');
|
||||
} catch (\ErrorException $e) {
|
||||
$prev = set_error_handler($prev);
|
||||
restore_error_handler();
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
$this->assertSame('var_dump', $prev);
|
||||
}
|
||||
|
||||
public function testCallErrorExceptionInfo()
|
||||
{
|
||||
try {
|
||||
ErrorHandler::call([self::class, 'triggerNotice'], $this);
|
||||
$this->fail('An \ErrorException should have been raised');
|
||||
} catch (\ErrorException $e) {
|
||||
$trace = $e->getTrace();
|
||||
$this->assertSame(E_NOTICE, $e->getSeverity());
|
||||
$this->assertSame(__FILE__, $e->getFile());
|
||||
$this->assertSame('Undefined variable: foo', $e->getMessage());
|
||||
$this->assertSame(0, $e->getCode());
|
||||
$this->assertSame('Symfony\Component\ErrorHandler\{closure}', $trace[0]['function']);
|
||||
$this->assertSame(ErrorHandler::class, $trace[0]['class']);
|
||||
$this->assertSame('triggerNotice', $trace[1]['function']);
|
||||
$this->assertSame(__CLASS__, $trace[1]['class']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testSuccessCall()
|
||||
{
|
||||
touch($filename = tempnam(sys_get_temp_dir(), 'sf_error_handler_'));
|
||||
|
||||
self::assertIsResource(ErrorHandler::call('fopen', $filename, 'r'));
|
||||
|
||||
unlink($filename);
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
try {
|
||||
|
Reference in New Issue
Block a user