flock() 是 PHP 實現輕量級諮詢式文件鎖的核心函數,適用於多進程環境下對同一文件的協同訪問控制。本文詳細解析參數、行為差異,並提供三個實戰場景代碼。
bool flock(resource $handle, int $operation [, int &$wouldblock ])
$handle:fopen() 返回的文件資源指標。$operation:
LOCK_SH:共享鎖(讀鎖),多進程可同時持有。LOCK_EX:獨占鎖(寫鎖),同一時間僅一進程持有。LOCK_UN:釋放鎖(共享/獨占通用)。LOCK_NB:非阻塞模式(Windows 不支援),鎖定失敗立即返回而非等待。$wouldblock:若傳入且鎖會阻塞,則設為 true(Windows 不支援)。返回:成功 true,失敗 false。
舊版本腳本結束或 fclose() 會自動釋放鎖;5.3.2 起必須顯式呼叫 flock($fp, LOCK_UN) 釋放,否則鎖可能殘留導致併發異常。
flock 直接操作文件的程式。flock 可靠性取決於底層實現,生產環境建議驗證或改用資料庫鎖/Redis 分佈式鎖。<?php
// writer.php 寫入端
$fp = fopen('data.txt', 'c+');
flock($fp, LOCK_EX);
ftruncate($fp, 0);
fwrite($fp, '新內容 ' . time());
flock($fp, LOCK_UN);
fclose($fp);
// reader.php 讀取端
function safeRead($path) {
$fp = fopen($path, 'r');
if (flock($fp, LOCK_SH)) { // 獲取共享鎖
$content = stream_get_contents($fp);
flock($fp, LOCK_UN);
fclose($fp);
return $content;
}
fclose($fp);
return false; // 非阻塞模式下獲取失敗
}
<?php
$fp = fopen('test.txt', 'a');
flock($fp, LOCK_SH); // 持有讀鎖
$written = fwrite($fp, 'data'); // 嘗試寫入
var_dump($written); // int(0) 寫入失敗,文件未變
fclose($fp);
持有 LOCK_SH 時嘗試寫入會失敗(返回 0),必須先釋放或升級為 LOCK_EX。
<?php
// 寫入:追加模式 + 獨占鎖
function T_put($file, $str) {
$fp = fopen($file, 'a');
if (flock($fp, LOCK_EX)) {
fwrite($fp, $str . PHP_EOL);
flock($fp, LOCK_UN);
}
fclose($fp);
}
// 讀取:讀模式 + 共享鎖
function T_get($file, $len = 8192) {
$fp = fopen($file, 'r');
$data = '';
if (flock($fp, LOCK_SH)) {
$data = fread($fp, $len);
flock($fp, LOCK_UN);
}
fclose($fp);
return $data;
}
此模式模擬「單寫多讀」併發,適合日誌記錄、簡易任務隊列等低頻場景。高併發或分佈式環境請改用 Redis/RabbitMQ 等專業中間件。