【PHP8.x】validメソッドの使い方

作成日: 更新日:

『validメソッドは、イテレータの現在の位置が有効かどうかを確認するメソッドです』 イテレータとは、配列やオブジェクトのようなデータの集合から、要素を一つずつ順番に取り出すための仕組みです。PHPのforeachループなどで繰り返し処理を行う際に、このvalidメソッドが内部的に呼び出されます。ループの各サイクルの開始時にこのメソッドが実行され、まだ処理すべき要素が存在するかどうかを判定します。もし現在の位置に有効な要素が存在する場合はtrueを返し、ループ内の処理が実行されます。一方、データの終端に達するなど、これ以上有効な要素が存在しない場合はfalseを返します。このfalseという結果を受け取ると、foreachループは終了します。このようにvalidメソッドは、イテレータを利用した繰り返し処理が、いつ終了すべきかを判断するための重要な役割を担っています。このメソッドはIteratorインターフェースで定義されており、InternalIteratorクラスもこれを実装しています。

基本的な使い方

構文(syntax)

1<?php
2
3// イテレータが現在の位置が有効かどうかをチェックします。
4public InternalIterator::valid(): bool

引数(parameters)

引数なし

引数はありません

戻り値(return)

bool

現在、イテレータが有効な要素を指しているかどうかを返します。trueであれば有効、falseであれば無効です。

サンプルコード

PHPでユーザーデータ検証を行う

1<?php
2
3/**
4 * 複数のユーザーデータをまとめて検証するクラス
5 *
6 * IteratorAggregateインターフェースを実装することで、このクラスのインスタンスを
7 * foreach文で直接ループ処理できるようになります。
8 */
9class UserDataValidator implements IteratorAggregate
10{
11    /**
12     * @var array バリデーション対象のユーザーデータ配列
13     */
14    private array $users;
15
16    /**
17     * コンストラクタでユーザーデータの配列を受け取ります。
18     *
19     * @param array $users
20     */
21    public function __construct(array $users)
22    {
23        $this->users = $users;
24    }
25
26    /**
27     * foreachループのためにIteratorオブジェクトを返します。
28     *
29     * ArrayIteratorはPHPの内部クラス(InternalIterator)の一つです。
30     * foreachは、このメソッドが返すイテレータの valid() メソッドを内部で呼び出し、
31     * trueが返る間だけループを継続します。
32     *
33     * @return ArrayIterator
34     */
35    public function getIterator(): ArrayIterator
36    {
37        return new ArrayIterator($this->users);
38    }
39
40    /**
41     * 個々のユーザーデータを検証(バリデーション)する静的メソッド
42     *
43     * @param array $user
44     * @return bool データが有効な場合はtrue、無効な場合はfalse
45     */
46    public static function isValidUser(array $user): bool
47    {
48        // nameが空でなく、ageが18以上の整数であるかを検証します。
49        return !empty($user['name']) && isset($user['age']) && filter_var($user['age'], FILTER_VALIDATE_INT) >= 18;
50    }
51}
52
53// 検証対象のデータセット
54$userDataList = [
55    ['name' => 'Alice', 'age' => 30],
56    ['name' => 'Bob', 'age' => 17],      // 年齢が18未満のため無効
57    ['name' => '', 'age' => 25],         // 名前が空のため無効
58    ['name' => 'Carol', 'age' => 42],
59    ['name' => 'David'],                 // ageキーが存在しないため無効
60];
61
62// バリデーションクラスのインスタンスを作成
63$validator = new UserDataValidator($userDataList);
64
65echo "ユーザーデータのバリデーションを開始します..." . PHP_EOL;
66
67// $validatorオブジェクトをforeachでループ処理します。
68// ループの各繰り返しで、内部的にイテレータのvalid()メソッドが呼び出され、
69// 処理すべきデータがまだ存在するかどうかを「検証」しています。
70// valid()がfalseを返した時点で、ループは終了します。
71foreach ($validator as $index => $user) {
72    if (UserDataValidator::isValidUser($user)) {
73        echo "[{$index}] 検証OK: {$user['name']} ({$user['age']}歳)" . PHP_EOL;
74    } else {
75        $name = $user['name'] ?? '(不明)';
76        $age = $user['age'] ?? '(不明)';
77        echo "[{$index}] 検証NG: name='{$name}', age='{$age}' は無効なデータです。" . PHP_EOL;
78    }
79}

このPHPサンプルコードは、IteratorAggregateインターフェースを利用して、オブジェクトを配列のようにforeachで反復処理し、複数のユーザーデータを一括で検証(バリデーション)する方法を示しています。

foreachループで$validatorオブジェクトの処理が開始されると、内部ではgetIterator()メソッドによってArrayIteratorオブジェクトが生成・利用されます。このイテレータオブジェクトが持つvalid()メソッドが、ループ処理を制御する上で重要な役割を果たします。

valid()メソッドは引数を取らず、イテレータが現在指している位置に有効な要素が存在するかどうかを示す真偽値(bool)を返します。foreachはループの各回の開始時にこのvalid()メソッドを呼び出します。その戻り値がtrueである限りループは継続され、すべての要素を処理し終えてfalseが返されると、ループは自動的に終了します。

このように、このコードはvalid()メソッドによる「ループを継続できるか」という形式的な検証と、isValidUser()メソッドによる「データの内容が要件を満たしているか」という具体的なバリデーションを組み合わせて、効率的なデータチェックを実現しています。

このコードには2種類の「検証」が登場します。foreachループが内部で呼び出すvalid()メソッドは「次に処理すべきデータがまだ存在するか」を検証し、ループを継続するかを決めます。これに対し、isValidUser()メソッドは「データの内容がルールに合っているか」というビジネスロジック上のバリデーションを行います。この2つの役割の違いを理解することが重要です。また、isValidUser()内のisset()や出力時の??(Null合体演算子)は、配列に特定のキーが存在しない場合にエラーが発生するのを防ぐための安全対策です。このような存在チェックは、信頼性の低いデータを扱う際に特に不可欠となります。

PHP Iterator::valid を使ったデータ検証

1<?php
2
3/**
4 * InternalIterator::valid メソッドは、PHPの内部的なイテレータ処理で使用される概念です。
5 * これは、現在のイテレータが有効な要素を指しているかどうかを判断するために、
6 * 主に foreach ループなどの内部で利用されます。
7 *
8 * 開発者は通常、直接 InternalIterator を実装するのではなく、
9 * Iterator インターフェース(InternalIterator を継承)を実装します。
10 *
11 * このサンプルコードでは、「数値かつ正の値」のデータのみを有効とみなす
12 * カスタムイテレータを作成し、valid() メソッドの動作と、
13 * 「validator(検証器)」としての役割を果たすイテレータの概念を示します。
14 */
15class PositiveNumberValidatorIterator implements Iterator
16{
17    private array $data;
18    private int $position = 0;
19
20    /**
21     * コンストラクタ。検証したいデータの配列を受け取ります。
22     * @param array $data 検証対象のデータ配列
23     */
24    public function __construct(array $data)
25    {
26        // キーをリセットして数値インデックスを保証します。
27        $this->data = array_values($data);
28    }
29
30    /**
31     * イテレータを最初の要素に巻き戻します。
32     * 最初の有効な要素が見つかるまでポインタを進めます。
33     */
34    public function rewind(): void
35    {
36        $this->position = 0;
37        $this->skipToNextValid();
38    }
39
40    /**
41     * 現在のイテレータが有効な要素を指しているかどうかを返します。
42     * ここでは、現在の位置がデータ配列の範囲内であるかを確認します。
43     *
44     * @return bool 現在の要素が有効な場合は true、それ以外は false
45     */
46    public function valid(): bool
47    {
48        return isset($this->data[$this->position]);
49    }
50
51    /**
52     * 現在の要素の値を返します。
53     *
54     * @return mixed 現在の要素の値
55     */
56    public function current(): mixed
57    {
58        return $this->data[$this->position];
59    }
60
61    /**
62     * 現在の要素のキーを返します。
63     *
64     * @return int 現在の要素のキー
65     */
66    public function key(): int
67    {
68        return $this->position;
69    }
70
71    /**
72     * イテレータを次の要素に進めます。
73     * 次の有効な要素が見つかるまでポインタを進めます。
74     */
75    public function next(): void
76    {
77        $this->position++;
78        $this->skipToNextValid();
79    }
80
81    /**
82     * 現在の要素が無効な場合、次の有効な要素が見つかるまでポインタをスキップするヘルパーメソッドです。
83     * ここでデータそのものの「バリデーション」が行われます。
84     */
85    private function skipToNextValid(): void
86    {
87        // 現在の位置が有効な範囲内であり、かつ現在の要素がデータとして有効でない間、
88        // ポインタを次の要素に進めます。
89        while ($this->valid() && !$this->isCurrentElementDataValid()) {
90            $this->position++;
91        }
92    }
93
94    /**
95     * 現在の要素が「有効なデータ」(数値で正の数)であるかをチェックします。
96     *
97     * @return bool データとして有効な場合は true、それ以外は false
98     */
99    private function isCurrentElementDataValid(): bool
100    {
101        $value = $this->data[$this->position] ?? null;
102        return is_numeric($value) && $value > 0;
103    }
104}
105
106// --- 使用例 ---
107
108// 検証したいデータ配列
109$dataToValidate = [10, -5, 3.14, 'hello', 0, 200, null, -1, 99];
110
111echo "--- 元のデータセット ---\n";
112print_r($dataToValidate);
113
114echo "\n--- PositiveNumberValidatorIterator を使用して検証・抽出 ---\n";
115$validatorIterator = new PositiveNumberValidatorIterator($dataToValidate);
116
117// foreach ループは内部的に valid() メソッドを呼び出し、イテレーションを制御します。
118foreach ($validatorIterator as $key => $value) {
119    echo "有効な要素: キー = {$key}, 値 = {$value}\n";
120}
121
122echo "\n--- valid() メソッドの直接的な動作例 ---\n";
123$directCheckIterator = new PositiveNumberValidatorIterator([1, -10, 2, 'abc', 3]);
124$directCheckIterator->rewind(); // rewind() でイテレータを初期化し、最初の有効な要素に移動します。
125
126// valid() が true を返す限りループを続けます。
127while ($directCheckIterator->valid()) {
128    echo "直接チェック - 現在の有効な要素: " . $directCheckIterator->current() . "\n";
129    $directCheckIterator->next(); // next() で次の有効な要素に移動します。
130}
131
132?>

このPHPサンプルコードは、InternalIteratorインターフェースが持つvalidメソッドの役割を解説するものです。validメソッドは、foreach文などの繰り返し処理が、次に処理すべき有効な要素がまだ存在するかどうかを内部的に確認するために使用されます。

このコードでは、PHP標準のIteratorインターフェースを実装したPositiveNumberValidatorIteratorというカスタムクラスを定義しています。このクラスは、与えられた配列データの中から「数値かつ正の値」という条件を満たす要素だけを抽出する「validator(検証器)」として機能します。

validメソッドは引数を取らず、イテレータが指す現在の位置がデータ配列の範囲内であればtrueを、範囲外であればfalseを返します。このbool型の戻り値によって、foreachループが処理を継続するか終了するかが決まります。

実際のデータ内容の検証はnextメソッドやrewindメソッドの内部で行われます。これらのメソッドが無効なデータ(負の数や文字列など)を自動的にスキップするため、foreachループでは常に検証済みの有効なデータだけが処理される仕組みです。結果として、元の配列から正の数値だけが効率的に取り出されます。

このコードの valid() メソッドは、ループ処理を継続できるか(ポインタが配列の範囲内か)を判定します。データの「内容」が正しいかを検証しているのは isCurrentElementDataValid() メソッドであり、この二つの役割は明確に区別されている点に注意が必要です。このイテレータがフィルタとして機能する仕組みは、rewind()next() の中で、条件に合わない要素を自動でスキップする処理が実装されているためです。foreach はこれらのメソッドを内部で呼び出すことで、検証済みのデータだけを簡潔に扱えます。また、コンストラクタで array_values() を使いキーをリセットすることで、連想配列などが渡された場合でも安定した動作を保証しています。

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