这是完全可重现的代码。
<?php
class console{
public static function log($msg, $arr=array()){
$str = vsprintf($msg, $arr);
fprintf(STDERR, "$str\n");
}
}
function cleanup(){
echo "cleaning up\n";
}
function signal_handler($signo){
console::log("Caught a signal %d", array($signo));
switch ($signo) {
case SIGTERM:
// handle shutdown tasks
cleanup();
break;
case SIGHUP:
// handle restart tasks
cleanup();
break;
default:
fprintf(STDERR, "Unknown signal ". $signo);
}
}
if(version_compare(PHP_VERSION, "5.3.0", '<')){
// tick use required as of PHP 4.3.0
declare(ticks = 1);
}
pcntl_signal(SIGTERM, "signal_handler");
pcntl_signal(SIGHUP, "signal_handler");
if(version_compare(PHP_VERSION, "5.3.0", '>=')){
pcntl_signal_dispatch();
console::log("Signal dispatched");
}
echo "Running an infinite loop\n";
while(true){
sleep(1);
echo date(DATE_ATOM). "\n";
}
当我运行它时,我会每秒看到日期值。现在,如果我按Ctrl + C cleanup
函数未被调用。实际上signal_handler
未被调用。
以下是示例输出。
$ php testsignal.php
Signal dispatched
Running an infinite loop
2012-10-04T13:54:22+06:00
2012-10-04T13:54:23+06:00
2012-10-04T13:54:24+06:00
2012-10-04T13:54:25+06:00
2012-10-04T13:54:26+06:00
2012-10-04T13:54:27+06:00
^C
答案 0 :(得分:9)
CTRL+C
触发SIGINT
,您尚未安装处理程序:
<?php
...
function signal_handler($signo){
...
case SIGINT:
// handle restart tasks
cleanup();
break;
...
}
...
pcntl_signal(SIGINT, "signal_handler");
...
现在可行:
$ php testsignal.php
Signal dispatched
Running an infinite loop
2012-10-08T09:57:51+02:00
2012-10-08T09:57:52+02:00
^CCaught a signal 2
cleaning up
2012-10-08T09:57:52+02:00
2012-10-08T09:57:53+02:00
^\Quit
答案 1 :(得分:4)
了解declare
的工作原理非常重要:http://www.php.net/manual/en/control-structures.declare.php
它需要包装它在“root”脚本中声明的影响(index.php或类似的东西)。
有趣的事实;declare(ticks = 1);
周围的IF检查无关紧要,如果删除这3行,脚本将停止工作,如果将检查更改为if (false)
它将起作用,则声明似乎在正常代码流程xD
答案 2 :(得分:0)
在Ruben de Vries修正编译时使用声明标记之后,原始代码有两个问题(除了缺少INT信号)。
正如鲁宾所说:
if(false) declare(ticks=1);
此DOES声明要处理的滴答声。试试吧! 文档继续说明如何不使用变量等。这是编译时的黑客攻击。
此外,使用pcntl_signal_dispatch()
不直接替换声明标记 - 它必须在代码执行期间调用 - 就像刻度自动执行一样。因此,在脚本头部调用一次只会处理当时等待的任何信号。
要使pcntl_signal_dispatch()像使用刻度线一样驱动它,你需要将它全部洒在你的代码上......具体取决于你希望中断生效的地点/时间。
至少:
while(true){
sleep(1);
echo date(DATE_ATOM). "\n";
pcntl_signal_dispatch();
}
因此,原始代码实际上对所有版本的PHP使用滴答,并且另外检查在初始启动过程中接收的一个信号(如果版本大于5.3)。不是OP想要的。
就我个人而言,我发现使用滴答声来驱动PCNTL发出巨大的麻烦。 &#34;循环&#34;在我的情况下是在第三方代码中,所以我不能添加一个调度方法,并且顶级的声明标记并不适用于生产,除非我将它添加到每个文件(某些自动加载,作用域或特定于PHP7版本)问题我认为。)