【PHP8.x】rewind関数の使い方

rewind関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

rewind関数は、オープンされたファイルのリソースに対して、ファイルポインタの位置をファイルの先頭に戻す処理を実行する関数です。ファイルポインタとは、ファイル内のデータを読み書きする際の現在の位置を示す目印のようなものです。例えば、あるファイルを読み進めて途中で別の処理を行い、その後にもう一度ファイルの最初から内容を読み直したい、といった状況でこのrewind関数が役立ちます。

この関数を使用する際は、事前にfopen()関数などを用いて開かれた有効なファイルリソースを引数として渡す必要があります。rewind関数が正常に実行され、ファイルポインタが先頭に移動できた場合にはtrueが返されます。一方、何らかの理由でファイルポインタを先頭に戻すことができなかった場合にはfalseが返されるため、戻り値を確認することで処理の成否を判断できます。

特に、ログファイルを繰り返し解析したり、設定ファイルを複数回読み込んだりするようなアプリケーション開発において、一度開いたファイルを効率的に再利用するための重要な機能の一つです。ただし、ネットワークストリームやパイプなど、シーク(位置指定)ができない一部のファイルリソースに対しては、rewind関数は期待通りに動作しない場合がある点にご注意ください。

構文(syntax)

1<?php
2$fileHandle = fopen('example.txt', 'r+');
3if ($fileHandle) {
4    rewind($fileHandle);
5    fclose($fileHandle);
6}
7?>

引数(parameters)

resource $stream

  • resource $stream: 操作対象のストリームリソースを指定します

戻り値(return)

bool

この関数は、イテレータの内部ポインタを先頭に移動させることに成功したかどうかを示す真偽値を返します。成功した場合は true を、失敗した場合は false を返します。

サンプルコード

PHP rewind: 巻き戻し可能なジェネレータ

1<?php
2
3/**
4 * このサンプルコードは、PHPの `rewind()` 関数を、
5 * 「巻き戻し可能なジェネレータ」(rewindable generator)の概念と組み合わせて示します。
6 *
7 * PHPのネイティブジェネレータは、一度イテレーションが完了すると、通常は巻き戻すことができません。
8 * しかし、ジェネレータが内部でファイルなどのストリームリソースを扱い、
9 * そのストリームリソースを再利用する場合、`rewind()` 関数を使用してストリームポインタをリセットできます。
10 *
11 * ここでは `IteratorAggregate` インターフェースを実装したクラス `RewindableStreamGenerator` を使用し、
12 * `rewind()` 関数がファイルストリームを巻き戻すことで、`foreach` ループが複数回実行されても、
13 * ジェネレータが「最初から」データを生成するように見える振る舞いを実現します。
14 */
15
16/**
17 * 一時的なデータファイルを作成するヘルパー関数。
18 *
19 * @param string $filename ファイルパス。
20 * @param array $lines ファイルに書き込む行の配列。
21 */
22function createTemporaryDataFile(string $filename, array $lines): void
23{
24    file_put_contents($filename, implode("\n", $lines));
25}
26
27/**
28 * ファイルストリームを巻き戻し可能なジェネレータとして機能させるクラス。
29 * `IteratorAggregate` を実装することで、`foreach` で複数回イテレーション可能になります。
30 */
31class RewindableStreamGenerator implements IteratorAggregate
32{
33    private string $filePath;
34    private ?resource $fileHandle = null; // ファイルリソースを保持
35
36    /**
37     * コンストラクタ。
38     *
39     * @param string $filePath 読み込むファイルのパス。
40     */
41    public function __construct(string $filePath)
42    {
43        $this->filePath = $filePath;
44    }
45
46    /**
47     * `IteratorAggregate` インターフェースの必須メソッド。
48     * このメソッドが呼び出されるたびに新しいジェネレータが作成されます。
49     * 内部でファイルストリームを開き直すか、既存のストリームを巻き戻します。
50     *
51     * @return Generator ファイルの各行を yield するジェネレータ。
52     * @throws RuntimeException ファイルのオープンに失敗した場合。
53     */
54    public function getIterator(): Generator
55    {
56        // ファイルハンドルがまだ開かれていない場合、または閉じられている場合に開く
57        if (!is_resource($this->fileHandle) || feof($this->fileHandle)) {
58            $this->fileHandle = fopen($this->filePath, 'r'); // 読み取りモードでファイルを開く
59            if (!$this->fileHandle) {
60                throw new RuntimeException("ファイルのオープンに失敗しました: " . $this->filePath);
61            }
62        } else {
63            // 既に開かれているファイルハンドルがある場合、それを巻き戻す
64            // ここで `rewind()` 関数が利用され、ファイルポインタが先頭に戻ります
65            rewind($this->fileHandle);
66        }
67
68        // ファイルから行を読み込み、yield(生成)する
69        while (!feof($this->fileHandle)) {
70            $line = trim(fgets($this->fileHandle));
71            if ($line !== '') {
72                yield $line;
73            }
74        }
75        // ここでファイルハンドルは閉じない。
76        // 同じファイルハンドルを次のイテレーションで再利用するため。
77        // ファイルハンドルはデストラクタで閉じられる。
78    }
79
80    /**
81     * クラスのインスタンスが破棄されるときに、開いているファイルハンドルを閉じます。
82     */
83    public function __destruct()
84    {
85        if (is_resource($this->fileHandle)) {
86            fclose($this->fileHandle);
87            $this->fileHandle = null; // リソースを解放
88        }
89    }
90}
91
92// --- サンプルコードの実行 ---
93
94// 一時ファイルのパスを定義
95$tempFilePath = 'temp_data_rewindable.txt';
96
97// サンプルデータを含む一時ファイルを作成
98createTemporaryDataFile($tempFilePath, [
99    'Line 1: Apple',
100    'Line 2: Banana',
101    'Line 3: Cherry',
102    'Line 4: Date'
103]);
104
105try {
106    // RewindableStreamGenerator のインスタンスを作成
107    $generatorWrapper = new RewindableStreamGenerator($tempFilePath);
108
109    echo "--- 1回目のイテレーション ---\n";
110    // 最初のイテレーション。ファイルが先頭から読み込まれる。
111    foreach ($generatorWrapper as $line) {
112        echo $line . "\n";
113    }
114
115    echo "\n--- 2回目のイテレーション(rewind() 後)---\n";
116    // 2回目のイテレーション。
117    // `foreach` が再度実行されると `getIterator()` メソッドが再度呼び出され、
118    // 内部で `rewind()` が適用されてファイルストリームが先頭に巻き戻される。
119    // そのため、再び最初からデータが読み込まれる。
120    foreach ($generatorWrapper as $line) {
121        echo $line . "\n";
122    }
123
124} catch (RuntimeException $e) {
125    echo "エラー: " . $e->getMessage() . "\n";
126} finally {
127    // 後処理: 作成した一時ファイルを削除
128    if (file_exists($tempFilePath)) {
129        unlink($tempFilePath);
130    }
131}

PHPのrewind()関数は、開かれたファイルやネットワーク接続などのストリームリソースの読み書きポインタを、そのストリームの先頭に戻すために使用されます。引数にはresource $streamとして操作対象のストリームリソースを指定し、処理が成功した場合はtrue、失敗した場合はfalseが戻り値として返されます。

このサンプルコードは、PHPのrewind()関数を活用して「巻き戻し可能なジェネレータ」という概念を示しています。PHPの通常のジェネレータは一度データを生成し終えると、通常は巻き戻して最初から再度生成することはできません。しかし、RewindableStreamGeneratorクラスはIteratorAggregateインターフェースを実装し、内部でファイルストリームを管理しています。foreachループが複数回実行され、getIterator()メソッドが呼び出されるたびに、rewind($this->fileHandle)が適用されます。これにより、既に開かれているファイルストリームの読み込みポインタがファイルの先頭にリセットされるため、ジェネレータは常に最初からファイルの内容を生成し直すことができます。これは、ファイルの内容を複数回にわたって処理したい場合に非常に有効な手法です。

rewind()関数は、開いているファイルなどのストリームリソースの読み取り位置を先頭に戻し、同じデータを複数回処理することを可能にします。この関数は、ジェネレータ自体を巻き戻すのではなく、ジェネレータが内部で利用しているファイルストリームを再利用するためのものです。全てのストリームが巻き戻し可能ではないため、ネットワークストリームなどでは機能しない点に注意が必要です。また、rewind()が成功したかどうかは戻り値で確認でき、ファイルリソースはfclose()で確実に閉じ、リソースリークを防ぐようにしましょう。サンプルでは__destructでその処理を行っています。

PHP rewind関数でファイルポインタを先頭に戻す

1<?php
2
3/**
4 * ファイルを作成し、内容を書き込み、rewind関数でファイルポインタを先頭に戻す例。
5 *
6 * rewind関数は、オープンされたファイルポインタをファイルの先頭にセットします。
7 * 主に、一度読み込んだファイルを再度最初から読み込みたい場合などに使用します。
8 */
9function demonstrateRewind(): void
10{
11    // 一時ファイル名を設定
12    $filename = 'example_rewind.txt';
13    $content = "Hello, PHP!\nThis is a test file.\n";
14
15    // ファイルを作成し、内容を書き込む
16    // 'w+' モードは、ファイルが存在すれば内容を空にし、存在しなければ作成します。
17    // そして、読み書き両方が可能です。
18    $handle = fopen($filename, 'w+');
19
20    if ($handle === false) {
21        echo "Error: Could not open or create file '{$filename}'.\n";
22        return;
23    }
24
25    // ファイルに内容を書き込む
26    fwrite($handle, $content);
27    echo "ファイルに内容を書き込みました。\n";
28    echo "ファイルポインタの位置: " . ftell($handle) . " バイト (ファイルの末尾近く)\n";
29
30    // ファイルポインタをファイルの先頭に戻す
31    if (rewind($handle)) {
32        echo "rewind関数を実行しました。ファイルポインタが先頭に戻りました。\n";
33        echo "ファイルポインタの位置: " . ftell($handle) . " バイト (ファイルの先頭)\n";
34
35        // ファイルの内容を最初から再度読み込む
36        // rewindでポインタが先頭に戻っているので、全ての内容が読み込める
37        fseek($handle, 0); // 念のためfseekでも先頭に移動させているが、rewindで十分
38        $readContent = fread($handle, filesize($filename));
39        echo "\nrewind後、ファイル先頭から再度読み込んだ内容:\n";
40        echo "----------------------------------------\n";
41        echo $readContent;
42        echo "----------------------------------------\n";
43    } else {
44        echo "Error: rewind関数が失敗しました。\n";
45    }
46
47    // ファイルリソースを閉じる
48    fclose($handle);
49    echo "ファイル '{$filename}' を閉じました。\n";
50
51    // 作成したファイルを削除(クリーンアップ)
52    if (file_exists($filename)) {
53        unlink($filename);
54        echo "ファイル '{$filename}' を削除しました。\n";
55    }
56}
57
58// 関数の実行
59demonstrateRewind();
60
61?>

PHPのrewind関数は、オープンされたファイルリソースのポインタを、そのファイルの先頭に戻すための関数です。

この関数は、引数として操作したいファイルリソース(resource $stream)を一つ受け取ります。例えば、fopen関数で開いたファイルハンドルなどが該当します。処理が成功した場合はtrueを、失敗した場合はfalseを戻り値(bool)として返します。

サンプルコードでは、まず一時的なファイルを作成し、内容を書き込んでいます。ファイルへの書き込みが完了すると、ファイルポインタは書き込んだ内容の末尾近くに移動します。この状態でrewind関数を実行すると、ファイルポインタはファイルの先頭(0バイト目)に瞬時に戻されます。これにより、一度書き込んだり読み込んだりしたファイルを、もう一度最初から読み込み直したい場合などに非常に役立ちます。

rewindが成功した後、サンプルコードでは再度ファイルの先頭から内容を読み込み、正常に全ての情報が取得できることを示しています。このように、ファイルへのアクセスを最初からやり直したいときにrewind関数は利用されます。

rewind関数は、fopenなどで開いたファイルリソース(resource型)のポインタをファイルの先頭に戻す機能です。引数にはファイルパスの文字列ではなく、必ずファイルリソース自体を渡す点に注意してください。関数の戻り値はbool型で、処理が成功したか失敗したかを示しますので、必ずその結果を確認し、適切なエラー処理を実装することが重要です。

この関数は、w+モードのように読み書き両用でファイルを開いた後、一度書き込んだ内容をファイルの先頭から再度読み込みたい場合に特に役立ちます。ファイル操作後は、rewindに限らず、必ずfcloseでリソースを閉じ、不要になった一時ファイルはunlinkで削除するなど、リソースの適切な管理を心がけましょう。fseek($handle, 0)もファイルの先頭にポインタを移動させますが、rewindは「先頭に戻す」という目的に特化しているため、より簡潔に記述できます。

関連コンテンツ

【PHP8.x】rewind関数の使い方 | いっしー@Webエンジニア