NOEMBLEM/エンブレムが設定されていません。

メールの詳細(トピック表示)

Iterator patterns in PHP4

投稿者:TAKAHASHI Masayoshiさん  2001/09/18 12:15  MLNo.1005   [メール表示]

高橋正義です。

イテレータのサンプルですが、PHP4版も作ってみました。
PHPは、arrayが順序つきHash(?)である、という何かがすごい言語で、
array自体はクラスではないため、継承ではなく委譲する使い方に
なります。
また、arrayにはnextという、要素を一つずつ取り出す関数がある
のですが、これは「arrayの要素がもうない時」と「要素がFALSE
だった時」の区別をしないらしいので、eachという関数が推奨
されているようです(「PHPマニュアル」より)。
each関数は、左辺が list($foo, $bar) となっていると、
$fooにキーが、$barに値が入ります(いや、だからarrayはハッシュ
なんです……)。そして、arrayの最後まで来たときにはeach関数は
FALSEを返します。


<?php
// Iterator Smaple
class Book {
var $name;
function Book($name) {$this->name = $name;}
}

class BookShelf {
var $books;
function BookShelf() {$this->books = array();}
function book_at($index) {return $this->books[$index];}
function append_book($book) {array_push($this->books, $book);}
function length() {return size($this->books);}
function iterator() {return new BookShelfIterator($this);}
}

class BookShelfIterator {
var $bookShelf;
function BookShelfIterator($bookShelf) {
$this->bookShelf = $bookShelf;
reset($this->bookShelf->books);
}
function next() {
return each($this->bookShelf->books);
}
}

// main
$bookShelf = new BookShelf();
$bookShelf->append_book(new Book("Around the World in 80 days"));
$bookShelf->append_book(new Book("Bible"));
$bookShelf->append_book(new Book("Cinderella"));
$bookShelf->append_book(new Book("Daddy-Long-Legs"));
$it = $bookShelf->iterator();
while (list($pos, $book) = $it->next()) {
print $book->name."<br>\n";
}

?>


また、PHP4にはarray_walkという、配列の要素一つずつに関数を適用して
くれる関数があります。これと匿名関数を使えば、以下のようにも
書けます。
BookShelfIterator の iterate というメソッドがイテレータを実行
するためのメソッドで、これの引数は匿名関数、またはユーザ関数の
関数名です。create_functionの引数は、一つ目が匿名関数の引数、
二つ目が匿名関数の定義(を文字列で表したもの)です。
このようにすれば、PHP4でインターナルイテレータを実装できます。


<?php
//Iterator Sample 2

// BookクラスとBookShelfクラスは上と同じなので省略

class BookShelfIterator {
var $bookShelf;
var $func;
function BookShelfIterator($bookShelf) {
$this->bookShelf = $bookShelf;
}
function iterate($func){
reset($this->bookShelf->books);
array_walk($this->bookShelf->books, $func);
}
}

// main
$bookShelf = new BookShelf();
$bookShelf->append_book(new Book("Around the World in 80 days"));
$bookShelf->append_book(new Book("Bible"));
$bookShelf->append_book(new Book("Cinderella"));
$bookShelf->append_book(new Book("Daddy-Long-Legs"));
$it = $bookShelf->iterator();
$it->iterate(create_function('$book','print $book->name."<br>\n";'));

?>


高橋征義 (TAKAHASHI Masayoshi) Email:maki@…


 読み込み中...

  • MLNo.1006   Hideto ISHIBASHIさん  (0) 2001/09/18 16:01  [メール表示する]
    石橋秀仁といいます。新参ものです。

    高橋さん、こちらのMLでもご活躍ですね。
    Rubyのサンプルコードを参考にさせていただいています。

    > PHPは、arrayが順序つきHash(?)である、という何かがすごい言語で、

    そうですね、CとPerlとオブジェクト指向の絶妙なバランスが、
    えもいわれぬ不快、おっと、深い味わいを醸し出しています。

    > また、arrayにはnextという、要素を一つずつ取り出す関数がある
    > のですが、これは「arrayの要素がもうない時」と「要素がFALSE
    > だった時」の区別をしないらしいので、eachという関数が推奨
    > されているようです(「PHPマニュアル」より)。

    ふつうの言語ならイテレータの指すところが「最後の要素の次」
    かを調べる関数(lastとでも名づけましょうか)があるのですが、
    無いので困っています。C++で外部イテレータを覚えた人は、
    PHPの外部イテレータには戸惑うことだと思います。

    # また、現在の場所を調べるcurrentという関数も、「最後」と「FALSE」
    # の区別をしないので、ほとんど役に立ちません。


    あと、私ならこういう風にするというコードを載せておきます。
    いえ、手元にPHP3しかないので、それで動くようにしただけです。
    このコードでの美しさは高橋さんのコードのほうが上です。

    function構文で、関数を関数として書けるという点では、
    匿名関数よりも読みやすくなります。行数が増えればメリットが
    あります。匿名関数の意味を考えれば本質的には同じことですが。
    匿名関数を使うのは、このコードの応用編と言えると思います。

    高橋さんの紹介された匿名関数によるコードは内部イテレータ
    と呼べると思います。これも同じ手法です。
    ただしPHP3には匿名関数が無いので、関数ポインタのような
    コールバック方法を用いています。
    # 手元のPHP3にはarray_pushがないので[]=で代用しました。
    # array_walkはPHP3にもあるようですね。

    *** iter2.orig.php Tue Sep 18 15:32:09 2001
    --- iter2.php Tue Sep 18 15:34:35 2001
    ***************
    *** 8,14 ****
    var $books;
    function BookShelf() {$this->books = array();}
    function book_at($index) {return $this->books[$index];}
    ! function append_book($book) {array_push($this->books, $book);}
    function length() {return size($this->books);}
    function iterator() {return new BookShelfIterator($this);}
    }
    --- 8,14 ----
    var $books;
    function BookShelf() {$this->books = array();}
    function book_at($index) {return $this->books[$index];}
    ! function append_book($book) {$this->books[] = $book;}
    function length() {return size($this->books);}
    function iterator() {return new BookShelfIterator($this);}
    }
    ***************
    *** 21,27 ****
    }
    function iterate($func){
    reset($this->bookShelf->books);
    ! array_walk($this->bookShelf->books, $func);
    }
    }

    --- 21,29 ----
    }
    function iterate($func){
    reset($this->bookShelf->books);
    ! while (list($pos, $book) = each($this->bookShelf->books)) {
    ! $func($pos, $book);
    ! }
    }
    }

    ***************
    *** 32,37 ****
    $bookShelf->append_book(new Book("Cinderella"));
    $bookShelf->append_book(new Book("Daddy-Long-Legs"));
    $it = $bookShelf->iterator();
    ! $it->iterate(create_function('$book','print $book->name."
    \n";'));

    ?>
    --- 34,40 ----
    $bookShelf->append_book(new Book("Cinderella"));
    $bookShelf->append_book(new Book("Daddy-Long-Legs"));
    $it = $bookShelf->iterator();
    ! function func($pos, $book) { print $book->name."
    \n"; }
    ! $it->iterate('func');

    ?>


    # このコードの差を見てPHPは進化していると言えるでしょうか?
    # C++のように肥大化の道をたどらなければよいのですが・・・

    --
    石橋秀仁 hideto-i@…




メールへの返信はMLのメンバーしかできません。
【PR】つぶやき日記掲示板で盛り上がろう無料の日記話題のブログ人気の日記
4LDK超ってこんなに広い?/SUUMO