PHP 三大運行模式對比
| 模式 | 典型場景 | SAPI 名稱 | 特點 |
| Web 模組 | 網站、API | apache2handler, fpm-fcgi | 請求-響應、無狀態、超時限制 |
| CLI | 腳本、佇列、定時任務 | cli | 長運行、標準輸入輸出、無超時、進程控制 |
| 嵌入式 | 桌面應用 | embed | PHP-GTK、PHP-JS 等 |
CLI 基礎操作
# 版本信息
php -v
# 語法檢查
php -l script.php
# 交互模式 (REPL)
php -a
# 直接執行代碼
php -r 'echo "Hello " . $argv[1];' World
# 內建 Web 服務器 (開發測試)
php -S localhost:8000 -t public/
# 顯示配置
php -i | grep memory_limit
php --ini
參數處理:$argv / $argc 與 getopt()
<?php
// script.php
// 執行:php script.php -u admin -p secret --env=prod arg1 arg2
echo "argc: $argc\n"; // 參數個數(含腳本名)
print_r($argv);
/*
Array
(
[0] => script.php
[1] => -u
[2] => admin
[3] => -p
[4] => secret
[5] => --env=prod
[6] => arg1
[7] => arg2
)
*/
// 解析短選項/長選項
$options = getopt('u:p::', ['env:', 'debug::']);
/*
Array
(
[u] => admin
[p] => secret
[env] => prod
[debug] => false // 無值時為 false
)
*/
// 位置參數(非選項)
$positional = array_diff_key($argv, array_flip(array_keys($options)));
// 需手動過濾 -- 之後的參數
標準輸入/輸出/錯誤流
<?php
// 讀取 STDIN (管道/重定向)
$stdin = fopen('php://stdin', 'r');
while (($line = fgets($stdin)) !== false) {
echo strtoupper($line);
}
fclose($stdin);
// 寫入 STDOUT / STDERR
fwrite(STDOUT, "Normal output\n");
fwrite(STDERR, "Error message\n");
// 管道組合:cat data.txt | php process.php > result.txt 2> error.log
常見 CLI 腳本模式
1. 批量處理/數據遷移
<?php
declare(ticks=1); // 信號處理
$pdo = new PDO('mysql:host=localhost;dbname=app', 'user', 'pass');
$stmt = $pdo->query('SELECT id, data FROM large_table');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// 處理邏輯
$result = transform($row['data']);
$pdo->prepare('UPDATE large_table SET result=? WHERE id=?')
->execute([$result, $row['id']]);
// 進度顯示
if ($row['id'] % 1000 === 0) {
fwrite(STDERR, "Processed {$row['id']} rows\n");
}
}
2. 守護進程/佇列消費者
<?php
// worker.php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
pcntl_signal(SIGTERM, fn() => $shutdown = true);
pcntl_signal(SIGINT, fn() => $shutdown = true);
while (!$shutdown) {
$job = $redis->lpop('queue:jobs');
if ($job) {
processJob(json_decode($job, true));
} else {
sleep(1); // 空閒休眠
}
pcntl_signal_dispatch(); // 處理信號
}
3. 定時任務
# crontab -e
# 每分鐘執行
* * * * * /usr/bin/php /var/www/artisan schedule:run >> /dev/null 2>&1
# Laravel 任務調度 (app/Console/Kernel.php)
protected function schedule(Schedule $schedule)
{
$schedule->command('emails:send')->hourly();
$schedule->job(new CleanupJob)->dailyAt('02:00');
$schedule->exec('bash /scripts/backup.sh')->weekly();
}
進階技巧
- 顏色輸出:
echo "\033[32mSuccess\033[0m\n"; 或用 symfony/console 的 OutputInterface
- 進度條:
symfony/console ProgressBar
- 異步並發:
amphp/parallel、revolt/php-parallel、spatie/async
- 內存監控:
memory_get_peak_usage(true) 定期檢查
- 單例鎖:
flock(fopen('/tmp/script.lock', 'w'), LOCK_EX | LOCK_NB) 防重複運行