忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

PHP クラス(オブジェクト)の反復処理について


配列の反復処理では foreach 命令を使って配列のデータを順次処理することができます。 この foreach 命令ですが、オブジェクトの反復処理にも使用することができます。

オブジェクトの反復処理に使用する場合、書式は以下の様になります。 書き方は配列の場合と何も変わったところはありません。
ただし、アクセスできる変数はアクセス権限のあるメンバー変数のみを取得できます。

foreach (オブジェクト変数 as メンバ変数名 => メンバ変数の値) { }


それでは、この反復処理を行う例を以下に示します。

<?php
// 反復処理テストクラス
class cEach
{
    // public プロパティ
    public $public_pub_para1 = "public_val1";
    public $public_param2 = "public_val2";
    public $public_param3 = "public_val3";
    // protected プロパティ
    protected $protected_param1 = "protected_val1";
    protected $protected_param2 = "protected_val2";
    // private プロパティ
    private $private_param1 = "private_val1";

    // 自分のクラス内の反復処理
    public function list_cEach() {
        echo "クラスの内での反復...<br>\n";
        foreach($this as $key => $value) {
            echo "$key => $value<br>\n";
        }
    }
}

// [cEach]クラスの生成
$insEach = new cEach();
// インスタンスから取得できる反復データ
echo "クラスの外からの反復...<br>\n";
foreach($insEach as $key => $value) {
    echo "$key => $value<br>\n";
}
// クラス内部で取得できる反復データ
$insEach->list_cEach();
?>


このプログラムを実行した時に、最初に「cEach」クラスを生成し、28行目の foreach 命令が実行されます。 「cEach」クラスのインスタンス「$insEach」からアクセスできるのは「cEach」クラスの public 属性を持った変数のみです。
その後で「cEach」クラスの list_cEach 関数をコールすることでクラス内のアクセス可能な変数を全て反復処理できます。 18行目の foreach 命令で行います。

これを実行するとブラウザに以下の様に表示されます。

クラスの外からの反復...
public_param1 => public_val1
public_param2 => public_val2
public_param3 => public_val3
クラスの内での反復...
public_param1 => public_val1
public_param2 => public_val2
public_param3 => public_val3
protected_param1 => protected_val1
protected_param2 => protected_val2
private_param1 => private_val1


foreach 命令はアクセス権限のあるメンバー変数のみを取得しますので、 クラスの外側では protected および private 属性の変数は取得できないことになります。

クラスのインスタンスに対する foreach 命令は public 変数を順次取得できるということです。
ただ、これ(public 変数を順次取得することが)が何に役立つのでしょうか?
このままでは前に進みませんので以下の例を示します。

<?php
// 反復処理テストクラス
class cEach
{
    // public プロパティ
    public $public_list = ["list1", "list2", "list3"];
}

// [cEach]クラスの生成
$insEach = new cEach();
// インスタンスから取得できる反復データ
foreach($insEach as $key => $value) {
    echo "$key => $value<br>\n";
}
?>


これを実行すると以下の様なエラーが表示されます。13行目で取得した「$value」は配列のデータなので文字列型への変換は注意!と表示されました。

 
Notice: Array to string conversion in C:\xampp\htdocs\_test\class15-each-2.php on line 13
public_list => Array
 


「$value」は配列データなので当たり前なので、以下の様にする必要があります。

<?php
// 反復処理テストクラス
class cEach
{
    // public プロパティ
    public $public_list = ["list1", "list2", "list3"];
}

// [cEach]クラスの生成
$insEach = new cEach();
// インスタンスから取得できる反復データ
foreach($insEach as $key => $value) {
    if (is_array($value)) {
		// 配列の場合は再度foreach
        foreach($value as $keyArr => $valueArr) {
            echo "$keyArr => $valueArr<br>\n";
        }
    } else {
        echo "$key => $value<br>\n";
    }
}
?>


一応結果は以下の様になります。

0 => list1
1 => list2
2 => list3


上記の方法では便宜的で一般性に欠けるので、クラスの方で仕掛けが必要になります。
PHP ではこの様な場合の反復処理が出来る様に Iterator インターフェースが実装されています。

interface Iterator extends Traversable {

	/* メソッド */
	public current(): mixed	// 現在の要素を返す(あらゆる型を返すことが可能です)
	public key(): mixed		// 現在の要素のキーを返す(成功した場合にスカラー型,失敗した場合にnullを返す)
	public next(): void		// 次の要素に進む
	public rewind(): void	// イテレータの最初の要素に巻き戻す
	public valid(): bool	// 現在位置が有効かどうかを調べる(成功した場合にtrueを,失敗した場合にfalseを返す)
}


Iterator インターフェースを利用して先ほどのクラスを変更します。 尚、5個のメソッドは必ず宣言する様です。

<?php
// Iterator インターフェースを利用した反復処理テストクラス
class cEach implements Iterator
{
    // 内部の配列とする
    private $list = ["list1", "list2", "list3", "list4", "list5"];

    // 配列の位置
    private $pos = 0;

    // コンストラクタ
    public function __construct() {
        $this->pos = 0;
    }

    // 巻き戻し(初期位置)
    public function rewind(): void {
        $this->pos = 0;
    }

    // 現在値
    public function current() {
        return $this->list[$this->pos];
    }

    // 現在キー
    public function key() {
        return $this->pos;
    }

    // 次の位置へ
    public function next(): void {
        ++$this->pos;
    }

    // 現在位置のデータ存在チェック
    public function valid(): bool {
        return isset($this->list[$this->pos]);
    }
}

// [cEach]クラスの生成
$insEach = new cEach();
// インスタンスから取得できる反復データ
foreach($insEach as $key => $value) {
    echo "$key => $value<br>\n";
}
?>


これを実行すると以下の様に表示されます。 Iterator インターフェースを利用したクラスの foreach ではちゃんと処理される様です。

0 => list1
1 => list2
2 => list3
3 => list4
4 => list5


これでもまだ改良の余地がありそうです。 このままではキー値が数値しか扱えませんし、クラスの生成時に外からリストを可変に設定したいとかいろいろ考えられます。
それらの件に付いてはまた別の記事で書いていこうと思います。












PR

コメント

コメントを書く