CodeGen_PECLとHaskellを使ってクラスを操作するExtensionを作る
http://d.hatena.ne.jp/n314/20090918/1253256703 の続き。
pear install -a CodeGen_PECL
作業ディレクトリ作成。
mkdir point cd point mkdir hs
cd hs emacs point.hs
module PhpPoint where import Foreign.C.Types foreign export ccall hsDistance :: CInt -> CInt -> IO CInt hsDistance :: CInt -> CInt -> IO CInt hsDistance x y = do return (x * y)
ghc -ffi -c point.hs cd ..
specファイルを書く。
emacs point.xml
<?xml version="1.0" ?> <extension name="point" version="1.1.2"> <function role="internal" name="MINIT"> <code> <?data hs_init(0, 0); ?> </code> </function> <function role="internal" name="MSHUTDOWN"> <code> <?data hs_exit(); ?> </code> </function> <class name="Point"> <summary>Point</summary> <description>Point class</description> <property name="x" access="public" type="int" value="0" /> <property name="y" access="public" type="int" value="0" /> <function name="__construct"> <proto>void __construct([int _x[, int _y]])</proto> <code> <?data PROP_SET_LONG(x, _x); PROP_SET_LONG(y, _y); ?> </code> </function> </class> <class name="Point_Result"> <summary>Point_Result</summary> <description>Point Result class</description> <property name="a" access="public" type="int" value="0" /> <function name="__construct"> <proto>void __construct([int _a])</proto> <code> <?data PROP_SET_LONG(a, _a); ?> </code> </function> </class> <class name="Point_Distance"> <summary>Point_Distance</summary> <description>Point Distance class</description> <function name="calc"> <proto>int calc(object Point p)</proto> <code> <?data zend_class_entry *ret_ce, *point_ce; long x, y, dist; Z_TYPE_P(return_value) = IS_OBJECT; object_init_ex(return_value, Point_Result_ce_ptr); ret_ce = Z_OBJCE_P(return_value); point_ce = Z_OBJCE_P(p); x = Z_LVAL_P(zend_read_property(point_ce, p, "x", strlen("x"), 1 TSRMLS_CC)); y = Z_LVAL_P(zend_read_property(point_ce, p, "y", strlen("y"), 1 TSRMLS_CC)); dist = hsDistance(x, y); zend_update_property_long(ret_ce, return_value, "a", strlen("a"), dist TSRMLS_CC ); ?> </code> </function> </class> </extension>
ビルド。
pecl-gen -f point.xml cd point ./configure --enable-point make cd .. ghc -optl-shared point/.lib/point.o hs/point.o hs/point_stub.o -optl-Wl,-soname \ -optl-Wl,point.so -o point.so cp point.so /usr/lib/php5/20060613+lfs/
テスト用のPHPファイルを書いて実行。
<?php dl('point.so'); $point = new Point(3, 4); var_dump($point); $distance = new Point_Distance(); var_dump($distance); $ret = $distance->calc($point); var_dump($ret);
% php test.php object(Point)#1 (2) { ["x"]=> int(3) ["y"]=> int(4) } object(Point_Distance)#2 (0) { } object(Point_Result)#3 (1) { ["a"]=> int(12) }
- 参考
- 作り方:http://www.doyouphp.jp/tips/tips_pear_codegen_pecl.shtml
- specファイル:http://cvs.php.net/viewvc.cgi/pear/CodeGen_PECL/docs/examples/?hideattic=0
- マニュアル:http://www.m-takagi.org/docs/php/CodeGen_PECL/manual.html
- 配列のチュートリアル的なもの:http://devlog.agektmr.com/wiki/index.php?cmd=read&page=PHP%2FExtension%20Writing%20Part%20II%20Parameters%2C%20Arrays%2C%20and%20ZVALs
Extensionの中でのクラス操作の仕方が全然分からない。
zend_*_property* 系の関数って、もっとシンプルなのがありそうな気がするけど検索しても全然ヒットしなくて困った。
説明が空のマニュアルが大量に引っかかるし…。
本当はHaskell側にクラスを渡したかったんだけど、zval を渡すわけにもいかないので取り敢えずここまで。
独自クラスを作ろうと思ったらzend_object_store_set_object、zend_object_store_get_object が関係する気がするが分からない。