首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP feof() 函數深度解析:檔案讀取、Socket 陷阱與正確使用姿勢

     編輯:PHP 相關知識

feof() 用於判斷檔案指標是否到達 EOF(End Of File),是檔案讀取迴圈的核心條件。但其行為在 Socket、管道、無效指標等場景下極易踩坑。本文系統解析 feof() 機制、常見陷阱與最佳實踐。

一、基本語法與返回值

feof(resource $stream): bool
// TRUE  : 已到達 EOF 或發生錯誤(含 Socket 超時)
// FALSE : 未到達 EOF

二、標準檔案讀取範例

<?php
$file = fopen($_SERVER['DOCUMENT_ROOT'] . '/me/test.txt', 'r');
if (!$file) {
    die('無法開啟檔案');
}

while (!feof($file)) {
    $line = fgets($file);
    if ($line !== false) {
        echo $line . '<br />';
    }
}
fclose($file);

輸出:

Hello, this is a test file.
There are three lines here.
This is the last line.

三、核心陷阱與避坑指南

1. 無效指標導致無限迴圈

$file = @fopen('no_such_file', 'r'); // 返回 false
while (!feof($file)) { ... } // feof(false) 總返回 false → 無限迴圈

修正:迴圈前必須檢查指標有效性。

$file = @fopen('no_such_file', 'r');
if (!$file) { die('開啟失敗'); }
while (!feof($file)) { ... }

2. Socket/管道無 EOF 信號導致阻塞

fsockopen()、popen() 開啟的流,若遠端不關閉連線,feof() 會持續阻塞直到超時(預設 60 秒,可用 stream_set_timeout() 調整)。

$fp = fsockopen('example.com', 80);
stream_set_timeout($fp, 10); // 10 秒超時
fwrite($fp, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n");
while (!feof($fp)) {
    echo fgets($fp, 1024);
}
fclose($fp);

3. fgets() 返回 false 但非 EOF

讀取錯誤時 fgets() 也返回 false,若僅判斷 feof() 會漏掉錯誤。標準模式:

while (($line = fgets($file)) !== false) {
    // 處理 $line
}
// 迴圈結束後可檢查 feof() 區分正常結束 vs 錯誤
if (!feof($file)) {
    error_log('讀取發生錯誤');
}

四、feof() vs stream_get_meta_data()

$meta = stream_get_meta_data($fp);
$meta['eof']        // 等同 feof($fp)
$meta['timed_out']  // Socket 超時標記(feof 無法區分)
$meta['blocked']    // 是否阻塞模式
$meta['unread_bytes'] // 緩衝區未讀位元組數

Socket 编程建議使用 stream_get_meta_data() 綜合判斷。

五、最佳實踐總結

  1. 永遠先檢查 fopen 返回值,失敗直接處理,不進迴圈。
  2. 檔案讀取優先用 while (($line = fgets($fp)) !== false),無需額外 feof()。
  3. Socket/管道必設超時(stream_set_timeout),並檢查 stream_get_meta_data()['timed_out']。
  4. 大檔案分塊讀取:fread($fp, 8192) 配合 feof(),避免一次性載入記憶體。
  5. 資源釋放:fclose() 或 try-finally 確保關閉。

六、總結

feof() 看似簡單,實則隱藏 Socket 阻塞、無效指標無限迴圈、錯誤與 EOF 混淆等深坑。掌握「先驗證指標、優先用 fgets 返回值判斷、Socket 必設超時」三大原則,才能在檔案與網路流讀取中穩健落地。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved