如果在PHP中花费太长时间,有没有办法可以中止一段代码?也许是这样的:
//Set the max time to 2 seconds
$time = new TimeOut(2);
$time->startTime();
sleep(3)
$time->endTime();
if ($time->timeExpired()){
echo 'This function took too long to execute and was aborted.';
}
Run Code Online (Sandbox Code Playgroud)
它不一定完全像上面那样,但有没有任何本机PHP函数或类做这样的事情?
编辑:Ben Lee的答案pcnt_fork将是完美的解决方案,除了它不适用于Windows.有没有其他方法可以使用适用于Windows和Linux的PHP实现此目的,但不需要外部库?
编辑2:XzKto的解决方案可在某些情况下,但不是一致,我似乎无法捕获异常,不管我怎么努力.用例是检测单元测试的超时.如果测试超时,我想终止它,然后继续下一个测试.
Ben*_*Lee 11
您可以通过分叉进程,然后使用父进程监视子进程来执行此操作.pcntl_fork是一个分叉进程的方法,所以你在内存中有两个几乎相同的程序并行运行.唯一的区别是在一个进程中,父进程pcntl_fork返回一个正整数,它对应于子进程的进程id.而在另一个过程中,孩子pcntl_fork返回0.
这是一个例子:
$pid = pcntl_fork();
if ($pid == 0) {
// this is the child process
} else {
// this is the parent process, and we know the child process id is in $pid
}
Run Code Online (Sandbox Code Playgroud)
这是基本结构.下一步是添加进程到期.您的东西将在子进程中运行,父进程将仅负责监视子进程并对其进行计时.但是为了让一个进程(父进程)杀死另一个进程(子进程),需要有一个信号.信号是进程通信的方式,意味着"你应该立即结束"的信号是SIGKILL.您可以使用posix_kill发送此信号.所以父母应该等待2秒然后杀死孩子,如下:
$pid = pcntl_fork();
if ($pid == 0) {
// this is the child process
// run your potentially time-consuming method
} else {
// this is the parent process, and we know the child process id is in $pid
sleep(2); // wait 2 seconds
posix_kill($pid, SIGKILL); // then kill the child
}
Run Code Online (Sandbox Code Playgroud)
如果你在一个命令(例如sleep())上编写脚本暂停,除了分叉之外你不能真的这样做,但是对于特殊情况有很多解决方法:如果你编程暂停数据库查询就像异步查询一样,proc_open如果你程序暂停一些外部执行等.不幸的是它们都不同,所以没有通用的解决方案.
如果脚本等待一个很长的循环/多行代码,你可以做一个像这样的脏技巧:
declare(ticks=1);
class Timouter {
private static $start_time = false,
$timeout;
public static function start($timeout) {
self::$start_time = microtime(true);
self::$timeout = (float) $timeout;
register_tick_function(array('Timouter', 'tick'));
}
public static function end() {
unregister_tick_function(array('Timouter', 'tick'));
}
public static function tick() {
if ((microtime(true) - self::$start_time) > self::$timeout)
throw new Exception;
}
}
//Main code
try {
//Start timeout
Timouter::start(3);
//Some long code to execute that you want to set timeout for.
while (1);
} catch (Exception $e) {
Timouter::end();
echo "Timeouted!";
}
Run Code Online (Sandbox Code Playgroud)
但我认为这不是很好.如果您指定确切的情况,我认为我们可以帮助您更好.