本文目录导读:

在 PHP 中,while(1) 或 while(true) 是一个无条件无限循环,如果不加防护,会导致脚本超时崩溃(通常是 30 秒默认限制)或服务器资源占满。
核心防御机制
1 设置执行时间限制
// 设置最大执行时间为 10 秒
set_time_limit(10);
$count = 0;
while(1) {
// 业务逻辑
$count++;
// 检查是否超时
if (connection_aborted()) {
break; // 客户端断开连接时退出
}
// 手工检查时间
if (microtime(true) - $start > 8) {
break; // 运行超过 8 秒退出
}
}
2 最大迭代次数限制
$max_iterations = 100000;
$count = 0;
while(1) {
// 业务逻辑
$count++;
// 达到最大迭代次数退出
if ($count >= $max_iterations) {
break;
}
// 其他退出条件
if (someCondition()) {
break;
}
}
完整防御示例
<?php
// 防御性无限循环
function safeInfiniteLoop() {
// 配置
$start_time = microtime(true);
$max_execution_time = 10; // 秒
$max_iterations = 100000;
$min_sleep = 100000; // 微秒 (0.1秒)
$iteration_count = 0;
while(1) {
$iteration_count++;
// 1. 时间限制检查
if (microtime(true) - $start_time > $max_execution_time) {
error_log("Loop exceeded time limit");
break;
}
// 2. 迭代次数限制
if ($iteration_count > $max_iterations) {
error_log("Loop exceeded iteration limit");
break;
}
// 3. 内存限制检查
if (memory_get_usage(true) > 100 * 1024 * 1024) { // 100MB
error_log("Memory limit exceeded");
break;
}
// 4. 客户端连接检查
if (connection_aborted()) {
error_log("Client disconnected");
break;
}
// 5. 自定义退出条件
if (shouldExit()) {
break;
}
// 6. 防止 CPU 100% - 加少量休眠
// 非必须操作时不要频繁循环
usleep($min_sleep);
// 执行业务逻辑
processData();
// 7. 反馈进度 (可选)
if ($iteration_count % 1000 == 0) {
echo "Processed: $iteration_count\n";
flush();
}
}
}
特定场景防御
1 长轮询/WebSocket
// 使用 PHP-FPM 的长轮询
$timeout = 30; // 30秒超时
$start = time();
while(time() - $start < $timeout) {
$new_data = checkForNewData();
if ($new_data) {
echo json_encode($new_data);
flush();
break;
}
// 每1秒检查一次
sleep(1);
}
2 后台守护进程
// 使用多进程或 Supervisor 管理
while(1) {
// 1. 检查进程是否存在
if (!file_exists('/tmp/daemon.pid')) {
break;
}
// 2. 检查信号
if (pcntl_signal_dispatch()) {
// 处理信号
}
// 3. 工作逻辑
processQueue();
sleep(1);
}
最佳实践建议
- 尽量避免
while(1)- 99% 的场景可以用其他方式实现 - 使用队列系统 - 如 Redis/RabbitMQ 替代无限循环
- 设置多重限制 - 时间、次数、内存、连接状态
- 使用进程管理工具 - Supervisor、systemd 管理长脚本
- 添加心跳检测 - 外部监控脚本检查进程存活
调试技巧
// 调试模式 - 打印循环状态
error_reporting(E_ALL);
ini_set('display_errors', 1);
$debug = true;
$count = 0;
while(1) {
$count++;
if ($debug && $count % 100 == 0) {
echo "Iteration: $count, Memory: " . memory_get_usage(true) . "\n";
}
// ... 业务代码
}
无限循环是最后的选择,优先考虑轮询、队列、事件驱动等模式。