问题描述
是否有一种方法可以使PHP脚本在退出时自动重启,而不管它是否已正确退出,由于错误而终止,或内存使用率最大化等?
Is there a way I can automatically restart a PHP script whenever it exits, regardless of whether it has been exited properly, or has terminated due to an error, or maxed memory usage, etc.?
推荐答案
PHP脚本也可以使用PCNTL重新启动.
免责声明:本练习的目的仅在于证明PHP具有完全重新启动自身的能力并回答以下问题:
A PHP Script can also restart itself with PCNTL.
Disclaimer: the point of this exercise is only to prove that PHP is perfectly capable of restarting itself and to answer the question:
因此,我们不讨论有关Unix进程的任何详细信息,因此,我建议您从 PCNTL书或参考 php-pcntl 了解更多详细信息.
It is therefor beyond our scope to go into any detail about unix processes so I would suggest you start with the PCNTL book or refer to php-pcntl for more details.
在示例中,我们将假定它是一个PHP CLI脚本,该脚本在* nix环境中从使用半透明外壳的终端使用以下命令启动:
In the examples we will assume it is a PHP CLI script launched in a *nix environment from a terminal with a semi-decent shell using the command:
$ php i-can-restart-myself.php 0
我们传递了重启计数属性作为该进程已重启的指示符.
We pass a restart count attribute as indicator that the process was restarted.
<?php
echo ++$argv[1]; // count every restart
$_ = $_SERVER['_']; // or full path to php binary
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n========== end =========\n";
// restart myself
pcntl_exec($_, $argv);
不管它是否已正确终止?
是的,如果终止,我可以重新启动!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
register_shutdown_function(function () {
global $_, $argv; // note we need to reference globals inside a function
// restart myself
pcntl_exec($_, $argv);
});
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
还是由于错误而终止?
同上!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
register_shutdown_function(function () {
global $_, $argv;
// restart myself
pcntl_exec($_, $argv);
});
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
但是你知道我会想要更多的东西吗?
当然!我可以重新启动,甚至可以按Ctrl-C!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
$restartMyself = function () {
global $_, $argv;
pcntl_exec($_, $argv);
};
register_shutdown_function($restartMyself);
pcntl_signal(SIGTERM, $restartMyself); // kill
pcntl_signal(SIGHUP, $restartMyself); // kill -s HUP or kill -1
pcntl_signal(SIGINT, $restartMyself); // Ctrl-C
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
我现在如何终止它?
我不想看到所有这些错误,我也可以重新启动这些错误吗?
没问题,我也可以处理错误!
<?php
echo ++$argv[1];
$_ = $_SERVER['_'];
$restartMyself = function () {
global $_, $argv;
pcntl_exec($_, $argv);
};
register_shutdown_function($restartMyself);
pcntl_signal(SIGTERM, $restartMyself);
pcntl_signal(SIGHUP, $restartMyself);
pcntl_signal(SIGINT, $restartMyself);
set_error_handler($restartMyself , E_ALL); // Catch all errors
echo "\n======== start =========\n";
// do a lot of stuff
$cnt = 0;
while( $cnt++ < 10000000 ){}
echo $CAREFUL_NOW; // NOTICE: will also be caught
// we would normally still go here
echo "\n===== what if? =========\n";
require 'OOPS! I dont exist.'; // FATAL Error:
// we can't reach here
echo "\n========== end =========\n";
die; // exited properly
// we can't reach here
pcntl_exec($_, $argv);
尽管乍看之下似乎可以正常工作,但由于pcntl_exec在同一进程中运行,所以我们不会注意到事情完全错了.如果您想生成一个新进程并让旧进程死掉,这是一个非常可行的选择,请参阅下一篇文章,您会注意到每次迭代都启动了2个进程,因为由于共同的疏忽,我们触发了PHP NOTICE和ERROR .当然,可以通过确保在错误处理程序中对pcntl_exec的调用之后死去(die)或退出()来轻松纠正这一点,否则PHP会假定公差已被接受并继续.
Although this appears to be working fine at first glance, because pcntl_exec runs in the same process we do not notice that things are terribly wrong. If you wanted to spawn a new process and letting the old one die instead, which is a perfectly viable alternative see next post, you will notice 2 processes are started each iteration, because we trigger a PHP NOTICE and an ERROR due to a common oversight. Which of course can easily be rectified by ensuring we die() or exit() after the call to pcntl_exec in the error handler, otherwise PHP assumes tolerance were accepted and continues.
我要说的是,即使您能够重新启动失败的脚本,这也不是允许破坏代码的借口.尽管这种做法可能存在可行的用例,但 我强烈不同意将故障重启作为解决由于错误而导致脚本失败的解决方案! 这些示例无法确切知道失败的原因,因此我们无法确定它将从何处重新开始.寻求似乎快速运行的快速修复"解决方案,现在可能会比以前有更多的问题.
The point I am trying to make is that even if you are able to relaunch a script that failed this is not an excuse to allow broken code. Although there may exist viable use cases for this practice, I strongly disagree that restart on failure should be employed as a solution for scripts failing due to errors! As we can see from these examples there is no way of knowing exactly where it failed so we cant be sure where it will start from again. Going for the "quick fix" solution which could appear to be working fine may have more problems now then before.
我宁愿看到通过一些适当的单元测试解决的缺陷,这将有助于清除问题的根源,因此我们可以纠正问题.如果PHP内存不足,可以通过在使用后取消设置变量来保守使用资源,从而避免这种情况. (顺便说一句,对于相同的结果,分配空值要比使用unset快得多).但是,恐怕如果不解决,重新启动肯定会成为您已经拥有的蠕虫病毒最合适的开启者.
I would instead prefer to see the defect addressed with some proper unit tests which will help flush out the culprit so we may rectify the problem. If PHP runs out of memory it can be avoided through conservative use of resources by unsetting the variables after use. (btw. you will find assigning null is much quicker than using unset for the same result) I am afraid though, if left unresolved, restarting would most definitely serve as suitable opener to the can of worms you already have.
这篇关于退出时自动重新启动PHP脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!