Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】SplTempFileObject::fgetcsv()メソッドの使い方

fgetcsvメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

fgetcsvメソッドは、SplTempFileObjectクラスに属し、一時的なファイルとして動作するオブジェクトから、CSV (Comma Separated Values) 形式のデータを一行ずつ読み込み、解析を実行するメソッドです。

このメソッドは、一時ファイル内のCSVデータを、指定された区切り文字(デフォルトはカンマ)、囲み文字(デフォルトはダブルクォート)、エスケープ文字(デフォルトはバックスラッシュ)に基づいて複数のフィールドに分解し、それらを要素とする配列として返します。SplTempFileObjectはメモリ上やシステムの一時領域にファイルを扱うため、このfgetcsvメソッドを利用することで、物理ディスクに保存せずに一時的に生成されたCSVデータを効率的に処理することが可能です。

データの読み込みに成功した場合は解析された配列を返しますが、ファイルの終端に達した場合や読み込みエラーが発生した場合はfalseを返します。システムエンジニアを目指す方にとって、一時的なCSVデータを扱う場面で非常に有用な、基本的なファイル操作機能の一つです。

構文(syntax)

1<?php
2
3$file = new SplTempFileObject();
4
5$rowDefault = $file->fgetcsv();
6
7$rowCustom = $file->fgetcsv(';', '"', '\\');

引数(parameters)

?string $separator = ',', ?string $enclosure = '"', ?string $escape = '\'

  • string $separator = ',': CSVファイルで各フィールドを区切る文字を指定します。デフォルトはカンマ(,)です。
  • string $enclosure = '"': CSVファイルで各フィールドを囲む文字を指定します。デフォルトはダブルクォーテーション(")です。
  • string $escape = '\': CSVファイルでエスケープ文字を指定します。デフォルトはバックスラッシュ(\)です。

戻り値(return)

array|false

CSV形式の行を配列として返します。ファイルの終端に達するかエラーが発生した場合は false を返します。

サンプルコード

PHP SplTempFileObject::fgetcsv 空行処理

1<?php
2
3/**
4 * SplTempFileObject::fgetcsv を使用してCSVデータを読み込むサンプルコード。
5 *
6 * PHPの古いバージョンではfgetcsvが空行をfalseと返す「バグ」がありましたが、
7 * PHP 5.3.0以降、そして現在のPHP 8では、空行は array(null) として返されます。
8 * このコードは、その現在の挙動、特に空行の扱いを明確にするためのものです。
9 */
10function handleCsvEmptyLinesWithSplTempFileObject(): void
11{
12    // SplTempFileObject を使用してメモリ上に一時的なCSVファイルを作成します。
13    // php://temp はデフォルトでメモリを使用し、データ量に応じて自動で一時ファイルに切り替わります。
14    $tempFile = new SplTempFileObject();
15
16    // テスト用のCSVデータを書き込みます。
17    // 3行目に意図的に空行を含めます。
18    $tempFile->fwrite("ID,Name,Email\n");
19    $tempFile->fwrite("1,Alice,alice@example.com\n");
20    $tempFile->fwrite("\n"); // ここが空行
21    $tempFile->fwrite("2,Bob,bob@example.com\n");
22    $tempFile->fwrite("3,Charlie,charlie@example.com\n");
23
24    // ファイルポインタを先頭に戻します。fgetcsvは現在のポインタ位置から読み込みます。
25    $tempFile->rewind();
26
27    echo "--- CSVデータ処理開始 ---\n";
28    $lineNumber = 1;
29
30    // fgetcsv() が false を返すまで(ファイルの終端に達するか、読み込みエラーが発生するまで)ループします。
31    while (false !== ($data = $tempFile->fgetcsv())) {
32        echo "行 {$lineNumber}: ";
33
34        if ($data === [null]) {
35            // PHP 5.3.0以降では、空行は array(null) として返されます。
36            echo "[空行として検出 (array(null))]\n";
37        } elseif (is_array($data)) {
38            // 通常のデータ行の場合、配列の内容を表示します。
39            echo "[" . implode(', ', array_map(function ($item) {
40                return var_export($item, true); // null も 'NULL' として表示し、視認性を高めます
41            }, $data)) . "]\n";
42        } else {
43            // ここに到達することは稀ですが、fgetcsvが配列でもfalseでもない値を返した場合の処理です。
44            echo "[不明なデータ形式またはエラー]\n";
45        }
46        $lineNumber++;
47    }
48
49    echo "--- CSVデータ処理終了 (fgetcsvがfalseを返してループが終了しました) ---\n";
50}
51
52// 関数を実行して、SplTempFileObject::fgetcsv の動作を確認します。
53handleCsvEmptyLinesWithSplTempFileObject();

SplTempFileObject::fgetcsvメソッドは、CSV(カンマ区切り値)形式のファイルを1行ずつ読み込み、そのデータを配列として取得する際に使用する便利な機能です。このメソッドは、CSVの区切り文字(デフォルトはカンマ)、囲み文字(デフォルトはダブルクォーテーション)、エスケープ文字(デフォルトはバックスラッシュ)を引数として指定できます。読み込みに成功すると、CSVの各列のデータを要素とする配列を返しますが、ファイルの終端に達したり読み込みエラーが発生したりした場合はfalseを返します。

特に重要な点として、過去のPHPバージョンではfgetcsvが空行をfalseと誤って解釈する「バグ」がありましたが、PHP 5.3.0以降、そして現在のPHP 8ではこの挙動が修正されています。現在では空行はarray(null)という特殊な配列として正しく扱われるようになっています。

サンプルコードでは、SplTempFileObjectを用いてメモリ上に一時的なCSVデータを生成し、その中に意図的に空行を含めています。そして、rewind()でファイルポインタを先頭に戻した後、whileループでfgetcsv()falseを返すまで各行を読み込んでいます。これにより、空行がarray(null)として検出される現在のPHP 8での正しい動作を確認できます。このメソッドはCSVデータの効率的な処理に役立ちます。

PHP 8のfgetcsvでは、空行はarray(null)として返され、古いバージョンでfalseとされた「バグ」は解消されていますので、古い情報に惑わされないよう注意が必要です。データ処理のループでは、ファイルの終端や読み込みエラーを示すfalseと、空行を示すarray(null)を明確に区別し、適切に処理を分岐させてください。また、データを読み込む前にrewind()メソッドでファイルポインタを先頭に戻すことを忘れないでください。これをしないとデータが正しく読み込まれません。CSVファイルの区切り文字などがデフォルト値と異なる場合は、引数を適切に指定し、データの誤読を防ぎましょう。SplTempFileObjectはメモリ上で一時ファイルを扱うため、効率的なデータ処理に適しています。

PHP SplTempFileObject::fgetcsv文字コード変換

1<?php
2
3/**
4 * SplTempFileObject::fgetcsv を使用して、特定の文字コードのCSVファイルを処理する例。
5 *
6 * この関数は、Shift_JISでエンコードされたCSVデータを一時ファイルオブジェクトに書き込み、
7 * fgetcsv で読み込んだ後、UTF-8に変換して表示します。
8 *
9 * システムエンジニアを目指す初心者が、fgetcsvで読み込んだデータがUTF-8ではない場合に
10 * どのように文字コードを変換して扱うか、という一般的な課題に対応するコードです。
11 */
12function processCsvWithCharsetConversion(): void
13{
14    // Shift_JISでエンコードされたと想定する日本語を含むCSVデータ。
15    // まずUTF-8の文字列として定義し、後でShift_JISに変換して一時ファイルに書き込みます。
16    $originalUtf8CsvString =
17        "商品名,価格,説明\n" .
18        "りんご,100,青森県産\n" .
19        "みかん,80,愛媛県産";
20
21    // 上記UTF-8文字列をShift_JIS (SJIS-win) に変換
22    // これが「外部から読み込むShift_JISのCSVファイル」のデータと仮定します。
23    $sjisCsvData = mb_convert_encoding($originalUtf8CsvString, 'SJIS-win', 'UTF-8');
24
25    // SplTempFileObject のインスタンスを作成
26    // これはメモリ上の一時ファイルのように動作します。
27    $tempFile = new SplTempFileObject();
28
29    // Shift_JISでエンコードされたCSVデータを一時ファイルに書き込む
30    // SplTempFileObject はバイト列をそのまま受け取ります。
31    $tempFile->fwrite($sjisCsvData);
32
33    // ファイルポインタを先頭に戻す
34    // これにより、fgetcsv がファイルの最初から読み込みを開始できます。
35    $tempFile->rewind();
36
37    echo "--- Shift_JIS CSV Data Processed (Converted to UTF-8 for output) ---\n";
38
39    // fgetcsv で1行ずつデータを読み込む
40    // fgetcsv はストリームからバイト列を読み込み、配列として返します。
41    // ここで読み込んだデータは、元のファイルと同じShift_JISエンコーディングのままです。
42    while (($row = $tempFile->fgetcsv()) !== false) {
43        // 読み込んだ各フィールドがShift_JISであるため、UTF-8に変換します。
44        // これを怠ると、日本語文字が正しく表示されなかったり、文字化けしたりします。
45        $convertedRow = array_map(function ($field) {
46            return mb_convert_encoding($field, 'UTF-8', 'SJIS-win');
47        }, $row);
48
49        // 変換後のUTF-8データを表示
50        echo implode(', ', $convertedRow) . "\n";
51    }
52
53    echo "--- End of processing ---\n";
54}
55
56// 関数を実行してCSV処理の例を表示
57processCsvWithCharsetConversion();

SplTempFileObject::fgetcsvは、SplTempFileObjectオブジェクトが表す一時ファイルから、CSV形式の1行を読み込み、そのフィールドを配列として返すメソッドです。引数には、CSVデータの区切り文字として$separator(デフォルトはカンマ)、囲み文字として$enclosure(デフォルトはダブルクォート)、エスケープ文字として$escape(デフォルトはバックスラッシュ)を指定でき、これらは省略可能です。メソッドが成功すると文字列の配列を返し、ファイルの終端に達した場合やエラーが発生した場合はfalseを返します。

サンプルコードは、PHPで異なる文字コードのCSVデータを処理する具体的な方法を示しています。fgetcsvメソッドは、ストリームから読み込んだデータをそのままバイト列として返すため、元のCSVファイルの文字コード(この例ではShift_JIS)が維持されます。そのため、読み込んだデータ($row)がUTF-8ではない場合、その後の処理で文字化けを防ぐために、mb_convert_encoding関数を使って各フィールドを適切な文字コード(通常はUTF-8)に変換する必要があります。このコードは、SplTempFileObjectを利用して一時的にCSVデータを保持し、文字コードを意識して安全にデータを扱う一般的な手法を学ぶのに役立ちます。

SplTempFileObject::fgetcsvは、ファイルから読み込んだバイト列をそのまま配列として返します。このため、CSVファイルの文字コードがUTF-8以外の場合、サンプルコードのようにmb_convert_encodingを用いて読み込んだ各データを適切な文字コード(通常はUTF-8)へ変換する必要があります。この変換を忘れると、日本語などが文字化けして正しく扱えなくなりますので、特に注意が必要です。また、ファイルにデータを書き込んだ後、fgetcsvで読み込みを開始する前に、必ずrewind()メソッドでファイルポインタを先頭に戻してください。これを怠ると、ファイルの内容が正しく読み込まれません。SplTempFileObjectはメモリまたは一時ディレクトリを使用するため、大量のデータを処理する際はメモリ使用量にも留意してください。

関連コンテンツ