Skip to content

Commit

Permalink
ErrorHandler refactoring API
Browse files Browse the repository at this point in the history
  • Loading branch information
rafsalvioni committed May 4, 2017
1 parent 026cf97 commit 973baee
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 112 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/nbproject/
/nbproject/
/vendor/
88 changes: 43 additions & 45 deletions src/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,78 @@
*
* @author Rafael M. Salvioni
*/
class ErrorHandler
abstract class ErrorHandler
{
/**
* Count opened instances
* Stack of started handlers
*
* @var int
* @var array
*/
private static $opened = 0;
private static $stack = [];

/**
* Stores the instances' config
* Checks if the ErrorHandler is started.
*
* @var array
* @return bool
*/
private static $config = [];

public static function isStarted()
{
return !empty(static::$stack);
}

/**
* Start the error's handler engine.
* Starting the ErrorHandler.
*
* @param bool $useSuppress Consider use of error operator?
* @param bool $useErrorLevel Consider current error reporting level?
* @param bool $errorTypes Custom error types to consider
* @param int $level
*/
public static function start(
$useSuppress = false, $useErrorLevel = false, $errorTypes = \E_ALL
) {
if (self::$opened++ == 0) {
\set_error_handler([__CLASS__, 'handle'], $errorTypes);
}
self::$config[] = [(bool)$useSuppress, (bool)$useErrorLevel];
public static function start($level = \E_ALL)
{
static::$stack[] = null;
\set_error_handler([__CLASS__, 'handle'], $level);
}

/**
* Stop handler engine.
* Stop the current ErrorHandler.
*
* @param bool $throw Throws a eventual exception?
* @return \ErrorException
*/
public static function stop()
public static function stop($throw = true)
{
if (self::$opened > 0) {
\array_pop(self::$config);

if (--self::$opened == 0) {
\restore_error_handler();
if (static::isStarted()) {
$exception = \array_pop(static::$stack);
\restore_error_handler();

if (($exception instanceof \ErrorException) && $throw) {
throw $exception;
}
return $exception;
}
return null;
}

/**
* Error's handler.
* Stop all handlers.
*
* If a exceptions was fired, the engine will be stopped automatically.
*/
public static function clean()
{
while (!empty(static::$stack)) {
static::stop(false);
}
}

/**
* Error handler callback.
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @throws \ErrorException
*/
public static function handle($errno, $errstr, $errfile, $errline)
{
if (self::$opened > 0) {
$config =& self::$config[self::$opened - 1];
$errorReporting = \error_reporting();

if ($errorReporting == 0) {
$throws = !$config[0];
}
else {
$throws = !$config[1] || ($errorReporting & $errno) > 0;
}

if ($throws) {
self::stop();
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
}
$stack =& static::$stack[\count(static::$stack) - 1];
$stack = new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
}
95 changes: 29 additions & 66 deletions test/ErrorHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,98 +13,61 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
/**
* @test
*/
public function startTest()
public function startStopTest()
{
try {
ErrorHandler::start();
\trigger_error("UserError", \E_USER_ERROR);
ErrorHandler::stop();
$this->assertTrue(false);
}
catch (\ErrorException $ex) {
$this->assertEquals($ex->getMessage(), "UserError");
}
ErrorHandler::stop();

try {
ErrorHandler::start(true);
@\trigger_error("UserError", \E_USER_ERROR);
$this->assertTrue(true);
}
catch (\ErrorException $ex) {
$this->assertTrue(false);
catch (\Exception $ex) {
$this->assertEquals("UserError", $ex->getMessage());
}
ErrorHandler::stop();

try {
ErrorHandler::start(false, true);
\error_reporting(E_USER_WARNING);
\trigger_error("UserError", \E_USER_ERROR);
ErrorHandler::start(\E_USER_WARNING);
\trigger_error("UserError", \E_USER_NOTICE);
ErrorHandler::stop();
$this->assertTrue(true);
}
catch (\ErrorException $ex) {
catch (\Exception $ex) {
$this->assertTrue(false);
}
ErrorHandler::stop();

try {
ErrorHandler::start(false, false, \E_USER_WARNING);
\trigger_error("UserError", \E_USER_WARNING);
$this->assertTrue(false);
}
catch (\ErrorException $ex) {
$this->assertTrue(true);
}
ErrorHandler::stop();
}

/**
* @test
* @depends startTest
* @depends startStopTest
*/
public function stopTest()
public function startedTest()
{
$called = false;
\set_error_handler(function ($errno, $errmsg) use (&$called) {
$called = true;
});

ErrorHandler::start();
$this->assertTrue(ErrorHandler::isStarted());
ErrorHandler::stop();

@\trigger_error('Notice', \E_USER_NOTICE);
$this->assertTrue($called);
}

/**
* @test
* @depends stopTest
*/
public function multipleStartTest()
{
$called = false;
\set_error_handler(function ($errno, $errmsg) use (&$called) {
$called = true;
});

$n = \mt_rand(5, 15);
$this->assertFalse(ErrorHandler::isStarted());
}

/**
* @test
* @depends startedTest
*/
public function cleanTest()
{
$n = \mt_rand(1, 20);
for ($i = 0; $i < $n; $i++) {
ErrorHandler::start();
}
ErrorHandler::clean();
$this->assertFalse(ErrorHandler::isStarted());

ErrorHandler::stop();
try {
@\trigger_error('Notice', \E_USER_NOTICE);
$this->assertFalse(true);
}
catch (\ErrorException $ex) {
$this->assertFalse($called);
}

$n -= 2;
for ($i = 0; $i < $n; $i++) {
\trigger_error("UserError", \E_USER_NOTICE);
ErrorHandler::stop();
$this->assertTrue(false);
}
catch (\PHPUnit_Framework_Error_Notice $ex) {
$this->assertTrue(true);
}
@\trigger_error('Notice', \E_USER_NOTICE);
$this->assertTrue($called);
}
}
}

0 comments on commit 973baee

Please sign in to comment.