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

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

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

作成日: 更新日:

基本的な使い方

seekメソッドは、SeekableIteratorインターフェースを実装するクラスが、イテレータの内部ポインタを指定された任意のオフセット(位置)に直接移動させるために用いるメソッドです。

SeekableIteratorインターフェースは、通常のIteratorインターフェースが提供する順次アクセス機能に加えて、要素へ直接アクセスする機能を可能にするものであり、このseekメソッドはその主要な機能の一つです。

このメソッドは、引数として一つの整数値 $offset を受け取ります。$offset は、イテレータが指し示すべき要素のゼロベースのインデックスを表します。seekメソッドが実行されると、イテレータの内部状態が更新され、次の操作で指定された $offset にある要素からデータが取得できるようになります。

もし指定された $offset がイテレータが持つ要素の有効な範囲外である場合、通常は OutOfBoundsException がスローされ、エラーとして処理されます。

この機能により、イテレータの先頭から一つずつ要素を辿る必要がなく、データ構造内の特定の要素へ効率的に「ジャンプ」してアクセスすることが可能になります。これは、特に大きなデータセットや配列のようなコレクションの中から、特定のインデックスにある情報を直接取得したい場合に非常に有用です。このメソッドは値を返しません(void)。

構文(syntax)

1$seekableIteratorInstance->seek(0);

引数(parameters)

int $position

  • int $position: 移動先のオフセットを指定する整数

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHP SeekableIterator の seek() メソッドで特定位置へ移動する

1<?php
2
3/**
4 * MySeekableIterator クラスは、`Iterator` と `SeekableIterator` インターフェースを実装します。
5 * これにより、イテレータを通常の順次処理でなく、任意のインデックスに直接移動させることができます。
6 * システムエンジニアを目指す初心者の方にも、イテレータの基本的な動作と、
7 * `seek` メソッドによる柔軟な移動方法を理解してもらえるように設計しています。
8 */
9class MySeekableIterator implements Iterator, SeekableIterator
10{
11    /** @var array 繰り返し処理を行うデータ */
12    private array $data;
13
14    /** @var int 現在のイテレータの位置(インデックス) */
15    private int $position = 0;
16
17    /**
18     * コンストラクタ。繰り返し処理を行うデータを初期化します。
19     * 配列のインデックスを0から始まる連番に正規化します。
20     *
21     * @param array $data 繰り返し処理の対象となる配列
22     */
23    public function __construct(array $data)
24    {
25        $this->data = array_values($data);
26    }
27
28    /**
29     * 現在のイテレータの位置にある要素の値を返します。
30     *
31     * @return mixed 現在の要素の値
32     */
33    public function current(): mixed
34    {
35        return $this->data[$this->position];
36    }
37
38    /**
39     * 現在のイテレータの位置(キー)を返します。
40     *
41     * @return int 現在の要素のキー(インデックス)
42     */
43    public function key(): int
44    {
45        return $this->position;
46    }
47
48    /**
49     * イテレータを次の要素に進めます。
50     */
51    public function next(): void
52    {
53        ++$this->position;
54    }
55
56    /**
57     * イテレータを最初の位置(インデックス0)に巻き戻します。
58     * foreach ループの開始時などに自動的に呼び出されます。
59     */
60    public function rewind(): void
61    {
62        $this->position = 0;
63    }
64
65    /**
66     * 現在のイテレータの位置が有効なデータ範囲内にあるかチェックします。
67     *
68     * @return bool 位置が有効な場合は true、それ以外は false
69     */
70    public function valid(): bool
71    {
72        return isset($this->data[$this->position]);
73    }
74
75    /**
76     * `SeekableIterator` インターフェースの主要メソッド。
77     * イテレータを、指定された `$position` (インデックス) に直接移動させます。
78     * これにより、途中の要素をスキップして特定の要素にジャンプできます。
79     *
80     * @param int $position 移動したい要素のインデックス
81     * @throws OutOfBoundsException 指定された位置が無効な場合にスローされます
82     */
83    public function seek(int $position): void
84    {
85        if (!isset($this->data[$position])) {
86            throw new OutOfBoundsException("無効な位置: {$position}。有効な範囲は 0 から " . (count($this->data) - 1) . " です。");
87        }
88        $this->position = $position;
89    }
90}
91
92// --- MySeekableIterator の使用例 ---
93
94// サンプルデータを用意します。
95$sampleData = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
96
97// MySeekableIterator のインスタンスを作成します。
98$iterator = new MySeekableIterator($sampleData);
99
100echo "--- 通常のイテレーション (foreach ループ) ---\n";
101// `rewind()` -> `valid()` -> `current()` -> `key()` -> `next()` の順で呼び出されます。
102foreach ($iterator as $key => $value) {
103    echo "Key: {$key}, Value: {$value}\n";
104}
105echo "\n";
106
107echo "--- seek() メソッドによる特定位置への移動 ---\n";
108
109// イテレータをインデックス 2 ('Cherry') に移動させます。
110$iterator->seek(2);
111echo "seek(2) で移動後の現在値: " . $iterator->current() . " (Key: " . $iterator->key() . ")\n";
112
113// イテレータをインデックス 0 ('Apple') に移動させます。
114$iterator->seek(0);
115echo "seek(0) で移動後の現在値: " . $iterator->current() . " (Key: " . $iterator->key() . ")\n";
116
117// イテレータをインデックス 4 ('Elderberry') に移動させます。
118$iterator->seek(4);
119echo "seek(4) で移動後の現在値: " . $iterator->current() . " (Key: " . $iterator->key() . ")\n";
120echo "\n";
121
122echo "--- seek() で無効な位置にアクセスした場合の例 ---\n";
123try {
124    // データ範囲外のインデックスに seek しようとすると、例外が発生します。
125    $iterator->seek(99);
126} catch (OutOfBoundsException $e) {
127    echo "エラーが発生しました: " . $e->getMessage() . "\n";
128}
129
130?>

PHP 8のSeekableIteratorインターフェースは、Iteratorインターフェースの持つ順次的なデータアクセス機能に加え、イテレータの現在位置を任意に移動させる能力を提供します。このインターフェースの中核となるメソッドがseekです。

seekメソッドは、int $positionという引数を受け取ります。この$positionは、イテレータを直接移動させたい要素のインデックス(位置)を指定するためのものです。例えば、seek(2)と呼び出すことで、イテレータはデータの3番目の要素(インデックス2)に即座に移動し、その要素を現在の位置として設定します。これにより、データの途中の要素をスキップして特定のインデックスの要素に直接アクセスしたり、処理を再開したりすることが可能になります。

このメソッドは戻り値を持ちません(void)。これは、seekの主な役割がイテレータの内部状態、つまり現在の位置を変更することであり、何らかの処理結果の値を返すことではないためです。指定された$positionがデータの有効な範囲外である場合、OutOfBoundsExceptionなどの例外がスローされ、不正なアクセスを未然に防ぎます。seekメソッドを利用することで、柔軟かつ効率的なデータアクセスが実現でき、特定のデータに迅速にたどり着く必要がある場面で特に有効です。

seekメソッドは、SeekableIteratorインターフェースを実装したクラスでのみ利用できます。このメソッドは、イテレータの現在位置を指定したインデックスへ直接移動させるもので、通常のforeachループのように順次処理するのではなく、特定の要素へジャンプしたい場合に役立ちます。最も重要な注意点は、引数に指定するインデックスが必ずデータ範囲内にあるかを確認することです。範囲外のインデックスを指定すると、予期せぬエラーや問題が発生する可能性があるため、サンプルコードのようにOutOfBoundsExceptionなどで適切に処理し、安全に利用してください。

PHP SeekableIteratorで指定位置へ移動する

1<?php
2
3/**
4 * SeekableIterator インターフェースを実装したカスタムイテレータクラス。
5 * 内部配列の任意の位置にイテレータのポインタを移動させることができます。
6 */
7class MySeekableIterator implements SeekableIterator
8{
9    private array $data; // イテレータが扱うデータ配列
10    private int $position = 0; // 現在のイテレータの位置(ポインタ)
11
12    /**
13     * コンストラクタ
14     *
15     * @param array $data イテレータで処理するデータ
16     */
17    public function __construct(array $data)
18    {
19        $this->data = $data;
20    }
21
22    /**
23     * イテレータを巻き戻し、最初の要素にポインタをリセットします。
24     * Iterator::rewind() の実装。
25     */
26    public function rewind(): void
27    {
28        $this->position = 0;
29    }
30
31    /**
32     * 現在のポインタが指す要素を返します。
33     * Iterator::current() の実装。
34     *
35     * @return mixed 現在の要素の値
36     */
37    public function current(): mixed
38    {
39        return $this->data[$this->position];
40    }
41
42    /**
43     * 現在のポインタの位置(キー)を返します。
44     * Iterator::key() の実装。
45     *
46     * @return int 現在の要素のキー
47     */
48    public function key(): int
49    {
50        return $this->position;
51    }
52
53    /**
54     * ポインタを次の要素に進めます。
55     * Iterator::next() の実装。
56     */
57    public function next(): void
58    {
59        ++$this->position;
60    }
61
62    /**
63     * 現在のポインタの位置に要素が存在するかどうかをチェックします。
64     * Iterator::valid() の実装。
65     *
66     * @return bool 要素が存在すれば true、そうでなければ false
67     */
68    public function valid(): bool
69    {
70        return isset($this->data[$this->position]);
71    }
72
73    /**
74     * イテレータのポインタを指定された位置に移動させます。
75     * SeekableIterator::seek() の実装。
76     *
77     * @param int $position ポインタを移動させる0から始まるインデックス
78     * @throws OutOfBoundsException 指定された位置が無効な場合にスローされます
79     */
80    public function seek(int $position): void
81    {
82        if (!isset($this->data[$position])) {
83            throw new OutOfBoundsException("指定された位置 ($position) は無効です。");
84        }
85        $this->position = $position;
86    }
87}
88
89// --- サンプルコードの実行 ---
90
91// サンプルデータを作成
92$fruits = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry', 'Fig'];
93$iterator = new MySeekableIterator($fruits);
94
95echo "--- 通常のイテレーション (最初から最後まで) ---" . PHP_EOL;
96foreach ($iterator as $key => $value) {
97    echo "キー: $key, 値: $value" . PHP_EOL;
98}
99echo PHP_EOL;
100
101echo "--- 3番目の要素 (インデックス 2) にシーク ---" . PHP_EOL;
102try {
103    $iterator->seek(2); // 'Cherry' がインデックス 2
104    echo "現在の要素: " . $iterator->current() . PHP_EOL; // 出力: Cherry
105    echo "シーク後のイテレーション:" . PHP_EOL;
106    // シーク後もイテレーションを続けることができます
107    foreach ($iterator as $key => $value) {
108        echo "キー: $key, 値: $value" . PHP_EOL;
109    }
110} catch (OutOfBoundsException $e) {
111    echo "エラー: " . $e->getMessage() . PHP_EOL;
112}
113echo PHP_EOL;
114
115// キーワード "php seek_end" に関連して、最後尾の要素にシークする例
116echo "--- 最後尾の要素にシーク ---" . PHP_EOL;
117$lastPosition = count($fruits) - 1; // 配列の最後のインデックスを計算
118try {
119    $iterator->seek($lastPosition);
120    echo "最後尾の要素 (インデックス: $lastPosition): " . $iterator->current() . PHP_EOL; // 出力: Fig
121} catch (OutOfBoundsException $e) {
122    echo "エラー: " . $e->getMessage() . PHP_EOL;
123}
124echo PHP_EOL;
125
126echo "--- 不正な位置にシークを試みる ---" . PHP_EOL;
127try {
128    $iterator->seek(100); // 存在しないインデックス
129} catch (OutOfBoundsException $e) {
130    echo "エラー: " . $e->getMessage() . PHP_EOL; // 出力: 指定された位置 (100) は無効です。
131}
132
133?>

PHP 8のSeekableIteratorインターフェースが提供するseekメソッドは、イテレータの内部ポインタを指定した位置に移動させる機能です。通常のイテレータはforeachなどで先頭から順にしかデータを処理できませんが、seekメソッドを使うと、データの任意の場所から読み込みを開始したり、特定の要素に直接アクセスしたりできます。

このメソッドはint $positionという引数を一つ取ります。これは、イテレータのポインタを移動させたい要素の0から始まるインデックス(位置)を指定するものです。例えば、seek(2)と呼び出すと、データの3番目の要素にポインタが移動します。このメソッド自体は、処理結果として特別な値を返しません(void)。

サンプルコードでは、MySeekableIteratorクラスがSeekableIteratorを実装し、seekメソッドを具体的に定義しています。$iterator->seek(2);のように使うことで、データの3番目の要素である「Cherry」に直接アクセスし、そこからイテレーションを再開できます。また、キーワードphp seek_endに関連する例として、count($fruits) - 1で計算した最後のインデックスを指定すれば、データ配列の最後尾の要素「Fig」にポインタを移動させることも可能です。指定された位置が存在しない場合は、OutOfBoundsExceptionがスローされ、無効なアクセスを防ぐ堅牢な仕組みが提供されています。

seekメソッドは、イテレータのポインタを指定した位置に移動させる機能です。位置は0から始まるインデックスで指定するため、配列の要素数と混同しないように注意が必要です。指定する位置がデータの範囲外の場合、サンプルコードのようにOutOfBoundsExceptionなどの例外が発生し、プログラムが停止する可能性があります。そのため、常に有効な範囲内で指定し、不正な値への備えとしてtry-catchブロックで例外を適切に処理することが重要です。配列の最後の要素に移動するには、count($array) - 1でインデックスを計算します。seekメソッドはポインタを移動するだけで値を返さないため、移動後の要素はcurrent()メソッドで取得してください。

関連コンテンツ

【PHP8.x】SeekableIterator::seek()メソッドの使い方 | いっしー@Webエンジニア