gabrielelana / graceful-death
一个允许您捕获致命错误的库
Requires
- php: >=5.4.0
- ext-pcntl: *
- ext-posix: *
Requires (Dev)
- phpunit/phpunit: ~4.0
README
如您所知,在PHP中捕获致命错误非常痛苦,几乎是不可能的。这是一个(部分)解决这个问题库的库
使用方法
<?php require __DIR__ . "/vendor/autoload.php"; // The output will be: // // Yes, I can ;-) GracefulDeath::around(function() { try { // Avoid to print the error in order to have clean output, don't try this at home :-) error_reporting(E_ALL ^ E_ERROR); // Creating an instance of an unknown class will cause a fatal error new UnknownClass(); } catch(Exception $e) { // A fatal error is uncatchable echo "You cannot catch this, AHAHAHAHA!!!\n"; } }) ->afterViolentDeath("Yes, I can ;-)\n") ->run();
场景
您有一段可能会引发致命错误的代码,并且希望能够在它之后进行清理或根据某些策略重新尝试。使用GracefulDeath
,您可以将这段代码放入闭包中,并将其作为参数传递给GracefulDeath::around
静态方法。这个静态方法返回一个构建器实例,让您配置GracefulDeath
的行为。使用afterViolentDeath
,您可以为每次触发致命错误时调用的处理程序进行配置。处理程序可以是:
- 一个整数:进程将以这个状态码退出
- 一个字符串:这个字符串将被打印到标准输出(如下例所示)
- 一个闭包:闭包将被执行,其返回值将被用作
run
方法的返回值。闭包的签名是function($status, $stdout, $stderr)
,其中$status
是传递给GracefulDeath::around
的代码的退出状态
还有一些其他方法可以用来配置GracefulDeath
-
afterNaturalDeath
:与afterViolentDeath
类似,但用于配置一个仅在未触发错误时调用的处理程序 -
afterDeath
:用于配置一个处理程序(如afterViolentDeath
和afterNaturalDeath
),在传递给GracefulDeath::around
的代码终止后调用 -
reanimationPolicy
:用于配置重新激活策略,即用于决定在致命错误之后是否应该再次执行传递给GracefulDeath::around
的代码的策略。重新激活策略可以是:- 一个布尔值:如果为true,则将无限重试,如果为false,则永远不会重试(默认值)
- 一个整数:代码将被执行的次数。如果代码没有错误终止或者执行次数超过了传递的参数,则代码将不会再次执行
- 一个闭包:如果闭包返回true,则代码将被再次执行。闭包的签名是
function($status, $attempts, $stdout, $stderr)
$status
:传递给GracefulDeath::around
的代码的退出状态$attempts
:代码已被执行的次数(想想之前的生命),从1
开始$stdout
:传递给GracefulDeath::around
的代码在stdout
上打印的内容$stderr
:传递给GracefulDeath::around
的代码在stderr
上打印的内容
有一些现成的重新激活策略可供使用
doNotReanimate
:这是默认行为,因此不太有用,但可用于文档或使代码更明确giveMeAnotherChance
:将只重新激活子进程一次liveForever
:将始终重新激活子进程。如果您使用此重新激活策略,请务必还使用avoidFutileMedicalCare
以避免不断重新激活一个破损的子进程
-
doNotCaptureOutput
:避免捕获stdout
和stderr
。请注意,如果没有捕获输出,则无法将其提供给reanimationPolicy
闭包 -
doNotEchoOutput
:丢弃(如果有)捕获的输出 -
avoidFutileMedicalCare($numberOfFailures, $inAmountOfTime)
:避免在短时间内($inAmountOfTime
默认为 60 秒)多次复活已经多次死亡的过程($numberOfFailures
默认为 6)
有关所有选项和方法,请参阅示例或测试 😄
使用案例
- 您有一个运行时间长的进程,该进程会泄露内存(参见
examples/memory_leak.php
) - 您可以使用
graceful-death
作为 supervisor,为此请使用->liveForever()
以便始终复活子进程,并且不要忘记使用->avoidFutileMedicalCare()
以避免不断复活一个损坏的子进程
它是如何工作的?
当调用 run
时,进程会进行分支,子进程将执行传递给 GracefulDeath::around
的代码,父进程将作为子进程的监督者。监督者将等待子进程死亡,并根据退出状态和给定配置采取相应行动。
注意事项
它只适用于有 pcntl_*
函数的地方。
自我推广
如果您喜欢这个项目,那么请考虑