You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP如何实现网页脚本与常驻命令行脚本的变量共享

可行实现方案

方案1:APCu扩展(最优轻量方案)

这个是PHP官方提供的用户空间共享缓存扩展,支持跨CLI/FPM进程共享数据,读写性能接近内存操作,无额外依赖负担。

前置配置

  1. 安装扩展:Debian/Ubuntu执行apt install php-apcu,CentOS执行yum install php-pecl-apcu
  2. 修改php.ini配置,新增/修改配置项apc.enable_cli = On,重启PHP服务和常驻脚本生效

代码示例

webpage_script.php

// 写入触发标记
if ($something_happens) {
    apcu_store('db_update_flag', true);
}

常驻运行脚本

while (true) {
    // 读取标记,读取成功后直接删除标记避免重复执行
    $needUpdate = apcu_fetch('db_update_flag', $success);
    if ($success && $needUpdate) {
        apcu_delete('db_update_flag');
        // 这里写你的DB检查、更新逻辑
    }
    // 无更新时休眠100毫秒,几乎不占用系统资源,响应延迟最高100ms可接受
    usleep(100000);
}

方案2:标记文件+文件锁(零扩展兼容方案)

不需要安装任何扩展,靠本地文件做标记,配合文件锁避免读写冲突,兼容性最高。

代码示例

webpage_script.php

$flagFile = '/tmp/db_update.flag';
if ($something_happens) {
    // 加独占锁写标记,避免并发写入异常
    $fp = fopen($flagFile, 'c');
    if (flock($fp, LOCK_EX)) {
        fwrite($fp, '1');
        flock($fp, LOCK_UN);
    }
    fclose($fp);
}

常驻运行脚本

$flagFile = '/tmp/db_update.flag';
while (true) {
    if (file_exists($flagFile)) {
        // 加锁读取并删除标记
        $fp = fopen($flagFile, 'r+');
        if (flock($fp, LOCK_EX)) {
            // 这里写你的DB检查、更新逻辑
            
            // 处理完删除标记文件
            unlink($flagFile);
            flock($fp, LOCK_UN);
        }
        fclose($fp);
    }
    usleep(100000);
}

进阶零轮询优化(适合低频率变更场景)

如果变更频率极低(几小时一次),可以安装inotify扩展监听标记文件的创建事件,完全不需要轮询,无更新时进程零负载,有变更立即触发:

$inotify = inotify_init();
// 监听/tmp目录下的文件创建事件
inotify_add_watch($inotify, '/tmp', IN_CREATE);
while (true) {
    // 阻塞等待事件,无事件时进程完全休眠不占用资源
    $events = inotify_read($inotify);
    foreach ($events as $event) {
        if ($event['name'] == 'db_update.flag') {
            // 这里写你的DB检查、更新逻辑
            unlink('/tmp/db_update.flag');
        }
    }
}

方案3:Redis(可扩展分布式方案)

如果后续需要跨多服务器部署,或者已经在使用Redis,可以用Redis做标记存储:

代码示例

webpage_script.php

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
if ($something_happens) {
    $redis->set('db_update_flag', '1');
}

常驻运行脚本

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
while (true) {
    if ($redis->exists('db_update_flag')) {
        $redis->del('db_update_flag');
        // 这里写你的DB检查、更新逻辑
    }
    usleep(100000);
}

原session方案失效原因

PHP默认会话会加独占锁,只要有进程在读取/写入会话,其他请求同一会话的进程会被阻塞直到锁释放,你的常驻脚本一直持有会话锁,所以web端请求会一直卡住,不适合用会话做跨进程共享标记。

内容的提问来源于stack exchange,提问作者Láďa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 15:48:03