55 lines
1.6 KiB
PHP
55 lines
1.6 KiB
PHP
<?php
|
|
/**
|
|
* Guard - wraps every hook callback so a Throwable can never white-screen the
|
|
* site or admin (requirement #5). The error is logged and surfaced, then the
|
|
* call fails safe.
|
|
*
|
|
* @package ESP\Instanda
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace ESP\Instanda;
|
|
|
|
final class Guard {
|
|
|
|
/**
|
|
* Wrap a callback so any Throwable is caught, reported, and swallowed.
|
|
*
|
|
* Fail-safe return: the first argument unchanged. For filters (gform_validation,
|
|
* gform_confirmation, gform_entry_meta, ...) this passes the filtered value
|
|
* through untouched, so a bug in our code never corrupts another plugin's data
|
|
* or blocks a submission. For actions the value is simply ignored.
|
|
*/
|
|
public static function wrap(callable $callback): callable {
|
|
return static function (mixed ...$args) use ($callback): mixed {
|
|
try {
|
|
return $callback(...$args);
|
|
} catch (\Throwable $e) {
|
|
self::report($e);
|
|
return $args[0] ?? null;
|
|
}
|
|
};
|
|
}
|
|
|
|
/** Log a Throwable with full context and fan it out to the failure surface (wired in M9). */
|
|
public static function report(\Throwable $e): void {
|
|
$message = sprintf(
|
|
'ESP INSTANDA: %s in %s:%d',
|
|
$e->getMessage(),
|
|
$e->getFile(),
|
|
$e->getLine()
|
|
);
|
|
|
|
if (class_exists('\GFCommon')) {
|
|
\GFCommon::log_error($message);
|
|
} elseif (function_exists('error_log')) {
|
|
error_log($message);
|
|
}
|
|
|
|
if (function_exists('do_action')) {
|
|
do_action('esp_instanda_throwable', $e);
|
|
}
|
|
}
|
|
}
|