4

这是完整的可重现代码。

<?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+Ccleanup函数不会被调用。其实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
4

3 回答 3

11

您尚未安装处理程序的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
于 2012-10-08T08:02:14.620 回答
4

了解其declare工作原理很重要:http ://www.php.net/manual/en/control-structures.declare.php

它要么需要包装它在“根”脚本(index.php 或类似的东西)中声明的任何影响。

有趣的事实; IF 检查declare(ticks = 1);无关紧要,如果删除这 3 行脚本将停止工作,如果将检查更改为if (false)它将起作用,声明似乎是在正常代码流之外评估的 xD

于 2014-05-08T08:15:48.990 回答
0

在 Ruben de Vries 更正了声明刻度的编译时使用之后,原始代码有两处错误(除了缺少 INT 信号)。

正如鲁本所说:

if(false) declare(ticks=1);

这确实声明要处理的刻度。尝试一下!文档继续说您如何不能使用变量等。这是一个编译时黑客。

此外,使用pcntl_signal_dispatch()不能直接替代声明滴答——它必须在代码执行期间调用——就像滴答自动做的那样。因此,像这样在脚本头部调用一次只会处理当时待处理的任何信号。

要使 pcntl_signal_dispatch() 像使用滴答声来驱动它一样运行,您需要将它洒在您的代码中......这取决于您希望中断生效的确切位置/时间。

至少:

while(true){
    sleep(1);
    echo date(DATE_ATOM). "\n";
    pcntl_signal_dispatch();
}

因此,原始代码实际上对所有版本的 PHP 都使用了刻度,并且如果版本大于 5.3 ,则另外检查在初始启动过程中接收到的一个信号。不是OP的意图。

Personally I find the use of ticks to drive PCNTL signals a huge messy pain. The "loop" in my case is in third party code, so I cannot add a dispatch method, and it the declare ticks at the top level doesn't work on production unless I add it to every file (some autoload, scoping or PHP7 version specific issue I think).

于 2017-08-13T08:44:36.907 回答