For the general purpose of unit testing php_register_callback_function, this is my hack :
<?php
namespace PAG\Testing;
class BlackboxedScriptRunner
{
public static $php = "/usr/bin/php";
public static function fetchScriptStdout($script): string
{
return self::executeFile($script, ' 2>/dev/null');
}
private static function executeFile($script, $option): string
{
if (php_sapi_name() !== "cli")
throw new RuntimeException("Cannot use this function in this setting for security reasons");
return shell_exec(self::$php ." -f $script -- $option");
}
public static function fetchScriptStderr($script): string
{
return self::executeFile($script, ' 2>&1 > /dev/null');
}
}
and the test :
<?php
use PAG\Testing\BlackboxedScriptRunner;
use PHPUnit\Framework\TestCase;
class ShutdownEventHandlerTest extends TestCase
{
public function testRegisterShutdownHandler()
{
$output =
BlackboxedScriptRunner::fetchScriptStdout(__DIR__ . "/../ManualTesting/testRegisterShutdownHandler.php");
$this->assertEquals(
file_get_contents(__DIR__ . "/../ManualTesting/testRegisterShutdownHandler.txt"),
$output);
}
}
Now I'm not saying this is awesome, I am saying this is awesome, I am saying it allows you to check the output of a whole script.
Warning : this is worse than eval, do not use for other purposes than testing.
And I am in a joyful mood, so here is my so called RegisterShutdownHandler :
<?php
namespace PAG\Shutdown;
class ShutdownEventHandler
{
private static $shutdown;
private static $shutdown_error;
private static $initialized = false;
private static $context = [];
public static function registerShutdownHandler($identifier, $function)
{
self::ensureInitialization();
self::$shutdown[$identifier] = $function;
}
private static function ensureInitialization(): void
{
if (!self::$initialized) {
self::$initialized = true;
self::registerShutdown();
}
}
private static function registerShutdown(): void
{
register_shutdown_function(function () {
self::shutdown();
});
}
private static function shutdown()
{
if (!is_null($error = error_get_last())) {
self::runCallbacks(self::$shutdown_error, $error);
}
self::runCallbacks(self::$shutdown);
}
private static function runCallbacks($array, $arguments = []): void
{
foreach ($array as $function) {
call_user_func($function, self::$context, $arguments);
}
}
public static function registerErrorShutdownHandler($identifier, $function)
{
self::ensureInitialization();
self::$shutdown_error[$identifier] = $function;
}
public static function deleteShutdownHandler($identifier)
{
unset(self::$shutdown[$identifier]);
}
public static function deleteErrorShutdownHandler($identifier)
{
unset(self::$shutdown_error[$identifier]);
}
public static function setContext(array $context): void
{
self::$context = $context;
}
}
You can find more of that on github. Must be frank though, it still has poor coverage.