Boost.PHP で SPL のイテレータを実装する
残念ながら所用で参加できなかった モダンPHP勉強会。SPL の発表を Ust 経由で聞いて楽しくなってきたので、Boost.PHP でインターフェイスを実装できるようにしてみた。
追記: Boost.PHP の導入については、id:Kiske さんが素敵なチュートリアルを書いているのでそちらをご覧あれ
m009.cpp:
#include "boost/php/module.hpp" #include "boost/php/function.hpp" #include "boost/php/klass.hpp" #include <boost/mpl/vector.hpp> #include <boost/shared_ptr.hpp> #include <Zend/zend_interfaces.h> using namespace boost; class RangeIterator { public: RangeIterator(int start, int end): cnt_(start), till_(end) {} int current() const { return cnt_; } int key() const { return cnt_; } void rewind() { cnt_ = 0; } bool valid() const { return cnt_ < till_; } void next() { ++cnt_; } private: int cnt_; const int till_; }; class m009_module : public php::module, public php::function_container<m009_module> { public: class handler : public php::module::handler { public: handler(m009_module* mod) : php::module::handler(mod) {} void __initialize(TSRMLS_D) { php::def_class<RangeIterator>("RangeIterator", boost::mpl::vector2<int, int>() TSRMLS_CC) .implements(::zend_ce_iterator) .defun("rewind", &RangeIterator::rewind) .defun("key", &RangeIterator::key) .defun("current", &RangeIterator::current) .defun("next", &RangeIterator::next) .defun("valid", &RangeIterator::valid) .fixup(); } }; public: m009_module(zend_module_entry* entry) : php::module(entry) { } }; #define BOOST_PHP_MODULE_NAME m009 #define BOOST_PHP_MODULE_CAPITALIZED_NAME M008 #define BOOST_PHP_MODULE_VERSION "0.1" #define BOOST_PHP_MODULE_CLASS_NAME m009_module #include "boost/php/module_def.hpp"
こんな感じで implements(...) の引数に zend_class_entry へのポインタを指定しておくと、そのインターフェイスを実装したクラスを作れるという仕様。
もちろん上の拡張モジュールをコンパイルすると、
<?php foreach(new RangeIterator(0, 5) as $i) { var_dump($i); } ?>
が
int(0) int(1) int(2) int(3) int(4)
という結果を返します!
Enjoy!