fopen() 與 file_get_contents() 都是 PHP 內建的流操作函數,但設計初衷不同:
<?php
$file = 'large_log.txt';
$handle = fopen($file, 'r');
if (!$handle) {
throw new RuntimeException("無法開啟文件:{$file}");
}
while (($line = fgets($handle)) !== false) {
// 處理單行,如解析日誌、過濾關鍵字
if (str_contains($line, 'ERROR')) {
error_log($line);
}
}
if (!feof($handle)) {
error_log("讀取過程發生錯誤");
}
fclose($handle); // 必須釋放資源
?>
<?php
$content = @file_get_contents('config.json');
if ($content === false) {
throw new RuntimeException('讀取配置文件失敗');
}
$config = json_decode($content, true);
// 適用於小於記憶體限制的文件(預設 128MB)
?>
<?php
$url = 'https://api.example.com/large-export.csv';
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => "Authorization: Bearer YOUR_TOKEN\r\nAccept: text/csv",
'timeout' => 30,
],
'ssl' => [
'verify_peer' => true,
'verify_peer_name' => true,
],
]);
$handle = fopen($url, 'r', false, $context);
if (!$handle) {
throw new RuntimeException("遠端請求失敗:{$url}");
}
// 邊下載邊處理,避免佔滿記憶體
while (($row = fgetcsv($handle)) !== false) {
// 處理 CSV 每一行
processRow($row);
}
fclose($handle);
?>
<?php
$url = 'https://api.example.com/user/profile';
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => "Authorization: Bearer TOKEN\r\nAccept: application/json",
'timeout' => 10,
],
]);
$response = @file_get_contents($url, false, $context);
if ($response === false) {
throw new RuntimeException('API 請求失敗');
}
$data = json_decode($response, true);
?>
| 特性 | fopen() | file_get_contents() |
|---|---|---|
| 返回類型 | 資源控制代碼 | 字串 / false |
| 記憶體佔用 | 低(流式處理) | 高(整體載入) |
| 適用大小 | 任意大小(GB 級) | < memory_limit |
| 讀取控制 | 逐行、指標、二進制 | 僅整體 |
| 寫入支援 | 支援 (w, a, r+ 等) | 不支援(需 file_put_contents) |
| 鎖定機制 | flock() 共享/獨佔鎖 | 無 |
| 代碼複雜度 | 較高 | 極低 |
| 錯誤處理 | 需檢查資源與 feof | 檢查 === false |
許多開發者忽略 fclose(),以為腳本結束會自動釋放。實際上:
Too many open files。最佳實踐:總是配合 try-finally 或 register_shutdown_function 確保關閉。
對於複雜 HTTP 需求(POST、檔案上傳、重試、異步、介面驅動),建議使用 GuzzleHttp\Client 或原生 cURL:
<?php
// Guzzle 範例(需 composer require guzzlehttp/guzzle)
$client = new GuzzleHttp\Client(['timeout' => 10]);
$response = $client->get('https://api.example.com/data', [
'headers' => ['Authorization' => 'Bearer TOKEN'],
]);
$data = json_decode($response->getBody()->getContents(), true);
?>
file_get_contents()(最簡潔)fopen() + fgets()/fgetcsv()file_get_contents() 搭配 stream_context_create() 覆蓋大部分 GET 需求,但 POST 仍建議用 Guzzle。理解兩者的底層機制與適用邊界,能讓你在面對不同 IO 場景時寫出更健壯、高效的代碼。