mirror of
https://github.com/marcostoll/FF.git
synced 2025-03-21 15:40:00 +01:00
Merge branch 'release/0.3.0'
This commit is contained in:
commit
273338d36c
39
readme.md
39
readme.md
@ -18,6 +18,7 @@ to use.
|
||||
Currently **FF** is composed of the following features:
|
||||
1. Services and the Service Factory
|
||||
2. Events and the Event Broker
|
||||
3. Runtime event handlers
|
||||
|
||||
More features will follow (see the Road Map section below).
|
||||
|
||||
@ -268,9 +269,45 @@ thereof) to be found by the `EventsFactory`.
|
||||
}
|
||||
}
|
||||
|
||||
# Runtime event handlers
|
||||
|
||||
This feature introduces three different handler classes for registering as callbacks to one of the three runtime events
|
||||
of the php engine (error, exception, shutdown). The handlers translate php's core event information to **FF\Events**
|
||||
event instances using the `EventBroker`.
|
||||
|
||||
## Registering runtime event handlers
|
||||
|
||||
All handlers implement the `RuntimeEventHandlerInterface` which lets you `register()` them on demand.
|
||||
The `ErrorHandler` as well as the `ExceptionHandler` each are aware of any previous handlers that might have been
|
||||
registered to their runtime events and let you restore the previous state. When registering shutdown handlers no
|
||||
information regarding the previous state is provided by php.
|
||||
|
||||
## Subscribing to runtime events
|
||||
|
||||
The handlers fire their own events containing all available event data which makes it easy for you to handle them by
|
||||
subscribing to the `FF\Events\EventBroker`.
|
||||
|
||||
Example:
|
||||
|
||||
use FF\Events\Runtime\Error;
|
||||
use FF\Factories\SF;
|
||||
use FF\Services\Events\EventBroker;
|
||||
use FF\Services\Runtime\ErrorHandler;
|
||||
|
||||
// register the ErrorHandler
|
||||
(new ErrorHandler())->register();
|
||||
|
||||
/** @var EventBroker $eventBroker */
|
||||
$eventBroker = SF::i()->get('events\EventBroker');
|
||||
|
||||
// subscribe to the Runtime\Error event
|
||||
$eventBroker->subscribe('Runtime\Error', function (Error $event) {
|
||||
// handle the event data
|
||||
var_dump($event->getErroNo(), $event->getErrMsg());
|
||||
}};
|
||||
|
||||
# Road map
|
||||
|
||||
- Runtime
|
||||
- Controllers
|
||||
- Sessions
|
||||
- Security
|
||||
|
107
src/Events/Runtime/Error.php
Normal file
107
src/Events/Runtime/Error.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of Error
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Events\Runtime;
|
||||
|
||||
use FF\Events\AbstractEvent;
|
||||
|
||||
/**
|
||||
* Class Error
|
||||
*
|
||||
* @package FF\Events\Runtime
|
||||
*/
|
||||
class Error extends AbstractEvent
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $errNo;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $errMsg;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $errFile;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $errLine;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $errContext;
|
||||
|
||||
/**
|
||||
* @param int $errNo
|
||||
* @param string $errMsg
|
||||
* @param string $errFile
|
||||
* @param int $errLine
|
||||
* @param array $errContext
|
||||
*/
|
||||
public function __construct(
|
||||
int $errNo,
|
||||
string $errMsg,
|
||||
string $errFile = '',
|
||||
int $errLine = null,
|
||||
array $errContext = []
|
||||
) {
|
||||
$this->errNo = $errNo;
|
||||
$this->errMsg = $errMsg;
|
||||
$this->errFile = $errFile;
|
||||
$this->errLine = $errLine;
|
||||
$this->errContext = $errContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getErrNo(): int
|
||||
{
|
||||
return $this->errNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getErrMsg(): string
|
||||
{
|
||||
return $this->errMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getErrFile(): string
|
||||
{
|
||||
return $this->errFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getErrLine(): int
|
||||
{
|
||||
return $this->errLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getErrContext(): array
|
||||
{
|
||||
return $this->errContext;
|
||||
}
|
||||
}
|
42
src/Events/Runtime/Exception.php
Normal file
42
src/Events/Runtime/Exception.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of Exception
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Events\Runtime;
|
||||
|
||||
use FF\Events\AbstractEvent;
|
||||
|
||||
/**
|
||||
* Class Exception
|
||||
*
|
||||
* @package FF\Events\Runtime
|
||||
*/
|
||||
class Exception extends AbstractEvent
|
||||
{
|
||||
/**
|
||||
* @var \Throwable
|
||||
*/
|
||||
protected $exception;
|
||||
|
||||
/**
|
||||
* @param \Throwable $exception
|
||||
*/
|
||||
public function __construct(\Throwable $exception)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Throwable
|
||||
*/
|
||||
public function getException(): \Throwable
|
||||
{
|
||||
return $this->exception;
|
||||
}
|
||||
}
|
23
src/Events/Runtime/Shutdown.php
Normal file
23
src/Events/Runtime/Shutdown.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of Shutdown
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Events\Runtime;
|
||||
|
||||
use FF\Events\AbstractEvent;
|
||||
|
||||
/**
|
||||
* Class Shutdown
|
||||
*
|
||||
* @package FF\Events\Runtime
|
||||
*/
|
||||
class Shutdown extends AbstractEvent
|
||||
{
|
||||
|
||||
}
|
@ -88,7 +88,7 @@ class ServicesFactory extends AbstractSingletonFactory
|
||||
* Returns an array of service instances instead if two or more class identifiers were passed. The returned list
|
||||
* will ordered in the same way as the class identifier arguments have been passed.
|
||||
*
|
||||
* @param string ...$classIdentifiers
|
||||
* @param string[] $classIdentifiers
|
||||
* @return AbstractService|AbstractService[]
|
||||
* @throws ClassNotFoundException
|
||||
* @throws ConfigurationException
|
||||
|
153
src/Services/Runtime/ErrorHandler.php
Normal file
153
src/Services/Runtime/ErrorHandler.php
Normal file
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of ErrorHandler
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services\Runtime;
|
||||
|
||||
use FF\Services\AbstractService;
|
||||
|
||||
/**
|
||||
* Class ErrorHandler
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - error-types : int (default: E_ALL) - error type bit mask to trigger this handler
|
||||
* - bypass-php-error-handling . bool (default: false) - whether to suppress php's built-in error handling
|
||||
*
|
||||
* @package FF\Services\Runtime
|
||||
*/
|
||||
class ErrorHandler extends AbstractService implements RuntimeEventHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
protected $previousHandler;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $errorTypes;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $bypassPhpErrorHandling = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Replaces the currently registered error handler callback (if any).
|
||||
* Stores any previously registered error handler callback.
|
||||
*
|
||||
* @see http://php.net/set_error_handler
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->previousHandler = set_error_handler([$this, 'onError'], $this->errorTypes);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the previous error handler callback before registration (if any)
|
||||
*
|
||||
* If register() wasn't called yet or no previous error handler callback was registered, null will be returned.
|
||||
*
|
||||
* @return callable|null
|
||||
*/
|
||||
public function getPreviousHandler(): ?callable
|
||||
{
|
||||
return $this->previousHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the previous error handler (if any)
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function restorePreviousHandler()
|
||||
{
|
||||
if (!is_callable($this->previousHandler)) return $this;
|
||||
|
||||
set_error_handler($this->previousHandler);
|
||||
$this->previousHandler = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getErrorTypes(): int
|
||||
{
|
||||
return $this->errorTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $errorTypes
|
||||
* @return $this
|
||||
*/
|
||||
public function setErrorTypes(int $errorTypes)
|
||||
{
|
||||
$this->errorTypes = $errorTypes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getBypassPhpErrorHandling(): bool
|
||||
{
|
||||
return $this->bypassPhpErrorHandling;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bypassPhpErrorHandling
|
||||
* @return $this
|
||||
*/
|
||||
public function setBypassPhpErrorHandling(bool $bypassPhpErrorHandling)
|
||||
{
|
||||
$this->bypassPhpErrorHandling = $bypassPhpErrorHandling;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic error handler callback
|
||||
*
|
||||
* @param int $errNo
|
||||
* @param string $errMsg
|
||||
* @param string $errFile
|
||||
* @param int $errLine
|
||||
* @param array $errContext
|
||||
* @return boolean
|
||||
* @fires Runtime\Error
|
||||
* @see http://php.net/set_error_handler
|
||||
*/
|
||||
public function onError(
|
||||
int $errNo,
|
||||
string $errMsg,
|
||||
string $errFile = '',
|
||||
int $errLine = null,
|
||||
array $errContext = []
|
||||
): bool {
|
||||
$this->fire('Runtime\Error', $errNo, $errMsg, $errFile, $errLine, $errContext);
|
||||
|
||||
return $this->bypassPhpErrorHandling;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function initialize(array $options)
|
||||
{
|
||||
parent::initialize($options);
|
||||
|
||||
$this->errorTypes = $this->getOption('error-types', E_ALL);
|
||||
$this->bypassPhpErrorHandling = $this->getOption('bypass-php-error-handling', false);
|
||||
}
|
||||
}
|
85
src/Services/Runtime/ExceptionHandler.php
Normal file
85
src/Services/Runtime/ExceptionHandler.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of ExceptionHandler
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services\Runtime;
|
||||
|
||||
use FF\Services\AbstractService;
|
||||
|
||||
/**
|
||||
* Class ErrorHandler
|
||||
*
|
||||
* @package FF\Runtime
|
||||
*/
|
||||
class ExceptionHandler extends AbstractService implements RuntimeEventHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
protected $previousHandler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return $this
|
||||
* @see http://php.net/set_exception_handler
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->previousHandler = set_exception_handler([$this, 'onException']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the previous exception handler callback before registration (if any)
|
||||
*
|
||||
* If register() wasn't called yet or no previous exception handler callback was registered, null will be returned.
|
||||
*
|
||||
* @return callable|null
|
||||
*/
|
||||
public function getPreviousHandler(): ?callable
|
||||
{
|
||||
return $this->previousHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the previous exception handler (if any)
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function restorePreviousHandler()
|
||||
{
|
||||
if (!is_callable($this->previousHandler)) return $this;
|
||||
|
||||
set_exception_handler($this->previousHandler);
|
||||
$this->previousHandler = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic exception handler callback
|
||||
*
|
||||
* To prevent potential loops any unhandled exception thrown while processing the Exception event
|
||||
* is caught and discarded.
|
||||
*
|
||||
* @param \Throwable $e
|
||||
* @fires Runtime\Exception
|
||||
* @see http://php.net/set_exception_handler
|
||||
*/
|
||||
public function onException(\Throwable $e)
|
||||
{
|
||||
try {
|
||||
$this->fire('Runtime\Exception', $e);
|
||||
} catch (\Exception $e) {
|
||||
// do not handle exceptions thrown while
|
||||
// processing the Exception event
|
||||
}
|
||||
}
|
||||
}
|
26
src/Services/Runtime/RuntimeEventHandlerInterface.php
Normal file
26
src/Services/Runtime/RuntimeEventHandlerInterface.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of RuntimeEventHandlerInterface
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services\Runtime;
|
||||
|
||||
/**
|
||||
* Interface RuntimeEventHandlerInterface
|
||||
*
|
||||
* @package FF\Services\Runtime
|
||||
*/
|
||||
interface RuntimeEventHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Registers the handler to some runtime event
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function register();
|
||||
}
|
113
src/Services/Runtime/ShutdownHandler.php
Normal file
113
src/Services/Runtime/ShutdownHandler.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of ShutdownHandler
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Services\Runtime;
|
||||
|
||||
use FF\Services\AbstractService;
|
||||
|
||||
/**
|
||||
* Class ErrorHandler
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - force-exit : bool (default: false) - invoke exit() after firing Shutdown event
|
||||
*
|
||||
* @package FF\Services\Runtime
|
||||
*/
|
||||
class ShutdownHandler extends AbstractService implements RuntimeEventHandlerInterface
|
||||
{
|
||||
/**
|
||||
* List of codes indicating fatal errors
|
||||
*/
|
||||
const FATAL_ERRORS = [
|
||||
E_ERROR,
|
||||
E_PARSE,
|
||||
E_CORE_ERROR,
|
||||
E_COMPILE_ERROR,
|
||||
E_USER_ERROR,
|
||||
E_RECOVERABLE_ERROR
|
||||
];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $forceExit;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return $this
|
||||
* @see http://php.net/register_shutdown_function
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
register_shutdown_function([$this, 'onShutdown']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getForceExit(): bool
|
||||
{
|
||||
return $this->forceExit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $forceExit
|
||||
* @return $this
|
||||
*/
|
||||
public function setForceExit(bool $forceExit)
|
||||
{
|
||||
$this->forceExit = $forceExit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic shutdown handler callback
|
||||
*
|
||||
* Terminates further execution via exit() if configured to do so,
|
||||
* thus stopping any additional shutdown handlers from being called.
|
||||
*
|
||||
* Fires an additional OnError event, in case a fatal error is detected
|
||||
*
|
||||
* @fires Runtime\Shutdown
|
||||
* @fires Runtime\Error
|
||||
* @see http://php.net/register_shutdown_function
|
||||
* @see http://php.net/error_get_last
|
||||
*/
|
||||
public function onShutdown()
|
||||
{
|
||||
$error = error_get_last();
|
||||
if (!is_null($error) && in_array($error['type'], self::FATAL_ERRORS)) {
|
||||
$this->fire(
|
||||
'Runtime\Error',
|
||||
$error['type'],
|
||||
$error['message'],
|
||||
$error['file'],
|
||||
$error['line']
|
||||
);
|
||||
}
|
||||
|
||||
$this->fire('Runtime\Shutdown');
|
||||
|
||||
if ($this->forceExit) exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function initialize(array $options)
|
||||
{
|
||||
parent::initialize($options);
|
||||
|
||||
$this->forceExit = $this->getOption('force-exit', false);
|
||||
}
|
||||
}
|
192
tests/Services/Runtime/ErrorHandlerTest.php
Normal file
192
tests/Services/Runtime/ErrorHandlerTest.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of ErrorHandlerTest
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Tests\Services\Runtime;
|
||||
|
||||
use FF\Events\Runtime\Error;
|
||||
use FF\Factories\ServicesFactory;
|
||||
use FF\Factories\SF;
|
||||
use FF\Services\Events\EventBroker;
|
||||
use FF\Services\Runtime\ErrorHandler;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test ErrorHandlerTest
|
||||
*
|
||||
* @package FF\Tests
|
||||
*/
|
||||
class ErrorHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected static $currentHandler;
|
||||
|
||||
/**
|
||||
* @var ErrorHandler
|
||||
*/
|
||||
protected $uut;
|
||||
|
||||
/**
|
||||
* @var Error
|
||||
*/
|
||||
protected static $lastEvent;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
// store current handler
|
||||
self::$currentHandler = set_error_handler(null);
|
||||
|
||||
SF::setInstance(new ServicesFactory());
|
||||
|
||||
/** @var EventBroker $eventBroker */
|
||||
$eventBroker = SF::i()->get('Events\EventBroker');
|
||||
|
||||
// register test listener
|
||||
$eventBroker->subscribe([__CLASS__, 'listener'], 'Runtime\Error');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
// unregister all error handlers
|
||||
while (true) {
|
||||
if (is_null(set_error_handler(null))) break;
|
||||
}
|
||||
|
||||
$this->uut = new ErrorHandler();
|
||||
self::$lastEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function tearDownAfterClass(): void
|
||||
{
|
||||
// unregister all error handlers
|
||||
while (true) {
|
||||
if (is_null(set_error_handler(null))) break;
|
||||
}
|
||||
|
||||
// re-register original error handler (if any)
|
||||
set_error_handler(self::$currentHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Error $event
|
||||
*/
|
||||
public static function listener(Error $event)
|
||||
{
|
||||
self::$lastEvent = $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy callback
|
||||
*
|
||||
* @param int $errNo
|
||||
* @param string $errMsg
|
||||
* @param string $errFile
|
||||
* @param int $errLine
|
||||
* @param array $errContext
|
||||
* @return boolean
|
||||
*/
|
||||
public function dummyHandler(
|
||||
int $errNo,
|
||||
string $errMsg,
|
||||
string $errFile = '',
|
||||
int $errLine = null,
|
||||
array $errContext = []
|
||||
): bool {
|
||||
$this->fail('dummy handler should never be called [' . serialize(func_get_args()) . ']');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSetGetErrorTypes()
|
||||
{
|
||||
$value = E_ERROR;
|
||||
$same = $this->uut->setErrorTypes($value);
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertEquals($value, $this->uut->getErrorTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSetGetBypassPhpErrorHandling()
|
||||
{
|
||||
$same = $this->uut->setBypassPhpErrorHandling(false);
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertFalse($this->uut->getBypassPhpErrorHandling());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$same = $this->uut->register();
|
||||
$this->assertSame($this->uut, $same);
|
||||
|
||||
// register another error handler on top
|
||||
// uut error handler should be found as the previous one
|
||||
$uutHandler = set_error_handler([$this, 'dummyHandler']);
|
||||
$this->assertSame([$this->uut, 'onError'], $uutHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRegisterWithPrevious()
|
||||
{
|
||||
$callback = [$this, 'dummyHandler'];
|
||||
set_error_handler($callback);
|
||||
|
||||
$this->uut->register();
|
||||
$this->assertSame($callback, $this->uut->getPreviousHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRestorePreviousHandler()
|
||||
{
|
||||
$callback = [$this, 'dummyHandler'];
|
||||
set_error_handler($callback);
|
||||
|
||||
$same = $this->uut->register()->restorePreviousHandler();
|
||||
$this->assertSame($same, $this->uut);
|
||||
$this->assertNull($this->uut->getPreviousHandler());
|
||||
|
||||
$previous = set_error_handler(null);
|
||||
$this->assertSame($callback, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testTriggerErrorHandling()
|
||||
{
|
||||
$msg = 'testing ErrorHandler';
|
||||
$this->uut->register()
|
||||
->onError(E_NOTICE, $msg);
|
||||
|
||||
$this->assertNotNull(self::$lastEvent);
|
||||
$this->assertEquals(E_NOTICE, self::$lastEvent->getErrNo());
|
||||
$this->assertEquals($msg, self::$lastEvent->getErrMsg());
|
||||
}
|
||||
}
|
159
tests/Services/Runtime/ExceptionHandlerTest.php
Normal file
159
tests/Services/Runtime/ExceptionHandlerTest.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of ExceptionHandlerTest
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Tests\Runtime;
|
||||
|
||||
use FF\Events\Runtime\Exception;
|
||||
use FF\Factories\ServicesFactory;
|
||||
use FF\Factories\SF;
|
||||
use FF\Services\Events\EventBroker;
|
||||
use FF\Services\Runtime\ExceptionHandler;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test ExceptionHandlerTest
|
||||
*
|
||||
* @package FF\Tests
|
||||
*/
|
||||
class ExceptionHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected static $currentHandler;
|
||||
|
||||
/**
|
||||
* @var ExceptionHandler
|
||||
*/
|
||||
protected $uut;
|
||||
|
||||
/**
|
||||
* @var Exception
|
||||
*/
|
||||
protected static $lastEvent;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
// store current handler
|
||||
self::$currentHandler = set_exception_handler(null);
|
||||
|
||||
SF::setInstance(new ServicesFactory());
|
||||
|
||||
/** @var EventBroker $eventBroker */
|
||||
$eventBroker = SF::i()->get('Events\EventBroker');
|
||||
|
||||
// register test listener
|
||||
$eventBroker->subscribe([__CLASS__, 'listener'], 'Runtime\Exception');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
// unregister all error handlers
|
||||
while (true) {
|
||||
if (is_null(set_exception_handler(null))) break;
|
||||
}
|
||||
|
||||
$this->uut = new ExceptionHandler();
|
||||
self::$lastEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function tearDownAfterClass(): void
|
||||
{
|
||||
// unregister all error handlers
|
||||
while (true) {
|
||||
if (is_null(set_exception_handler(null))) break;
|
||||
}
|
||||
|
||||
// re-register original error handler (if any)
|
||||
set_exception_handler(self::$currentHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $event
|
||||
*/
|
||||
public static function listener(Exception $event)
|
||||
{
|
||||
self::$lastEvent = $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy handler callback
|
||||
*
|
||||
* @param \Throwable $e
|
||||
*/
|
||||
public function dummyHandler(\Throwable $e)
|
||||
{
|
||||
$this->fail('dummy handler should never be called [' . serialize(func_get_args()) . ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$same = $this->uut->register();
|
||||
$this->assertSame($this->uut, $same);
|
||||
|
||||
// register another error handler on top
|
||||
// uut error handler should be found as the previous one
|
||||
$uutHandler = set_exception_handler([$this, 'dummyHandler']);
|
||||
$this->assertSame([$this->uut, 'onException'], $uutHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRegisterWithPrevious()
|
||||
{
|
||||
$callback = [$this, 'dummyHandler'];
|
||||
set_exception_handler($callback);
|
||||
|
||||
$this->uut->register();
|
||||
$this->assertSame($callback, $this->uut->getPreviousHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testTriggerExceptionHandling()
|
||||
{
|
||||
$e = new \Exception('testing ExceptionHandler');
|
||||
$this->uut->register()
|
||||
->onException($e);
|
||||
|
||||
$this->assertNotNull(self::$lastEvent);
|
||||
$this->assertSame($e, self::$lastEvent->getException());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRestorePreviousHandler()
|
||||
{
|
||||
$callback = [$this, 'dummyHandler'];
|
||||
set_exception_handler($callback);
|
||||
|
||||
$same = $this->uut->register()->restorePreviousHandler();
|
||||
$this->assertSame($same, $this->uut);
|
||||
$this->assertNull($this->uut->getPreviousHandler());
|
||||
|
||||
$previous = set_exception_handler(null);
|
||||
$this->assertSame($callback, $previous);
|
||||
}
|
||||
}
|
105
tests/Services/Runtime/ShutdownHandlerTest.php
Normal file
105
tests/Services/Runtime/ShutdownHandlerTest.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* Definition of ShutdownHandlerTest
|
||||
*
|
||||
* @author Marco Stoll <marco@fast-forward-encoding.de>
|
||||
* @copyright 2019-forever Marco Stoll
|
||||
* @filesource
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FF\Tests\Services\Runtime;
|
||||
|
||||
use FF\Events\Runtime\Shutdown;
|
||||
use FF\Factories\ServicesFactory;
|
||||
use FF\Factories\SF;
|
||||
use FF\Services\Events\EventBroker;
|
||||
use FF\Services\Runtime\ShutdownHandler;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test ShutdownHandlerTest
|
||||
*
|
||||
* @package FF\Tests
|
||||
*/
|
||||
class ShutdownHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ShutdownHandler
|
||||
*/
|
||||
protected $uut;
|
||||
|
||||
/**
|
||||
* @var Shutdown
|
||||
*/
|
||||
protected static $lastEvent;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
SF::setInstance(new ServicesFactory());
|
||||
|
||||
/** @var EventBroker $eventBroker */
|
||||
$eventBroker = SF::i()->get('Events\EventBroker');
|
||||
|
||||
// register test listener
|
||||
$eventBroker->subscribe([__CLASS__, 'listener'], 'Runtime\Shutdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->uut = new ShutdownHandler();
|
||||
self::$lastEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Shutdown $event
|
||||
*/
|
||||
public static function listener(Shutdown $event)
|
||||
{
|
||||
self::$lastEvent = $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy callback
|
||||
*/
|
||||
public function dummyHandler()
|
||||
{
|
||||
$this->fail('dummy handler should never be called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testSetGetForceExit()
|
||||
{
|
||||
$same = $this->uut->setForceExit(false);
|
||||
$this->assertSame($this->uut, $same);
|
||||
$this->assertFalse($this->uut->getForceExit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$same = $this->uut->register();
|
||||
$this->assertSame($this->uut, $same);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the namesake method/feature
|
||||
*/
|
||||
public function testTriggerShutdownHandling()
|
||||
{
|
||||
$this->uut->register()
|
||||
->onShutdown();
|
||||
|
||||
$this->assertNotNull(self::$lastEvent);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user