自分がPHP Extensionを作ろうと思ったときに、
「とりあえず開いて書き方ぱくるためのページ」として、
これを書いておく。解説は他のサイトを確認する。
Zend API: PHPのコアをハックする
ここはあくまで、こうやって書いたら動いたってメモ。
※ 前提条件として、PHPをソースからコンパイルしてある事とする。
ソースのパス : /usr/local/share/php-5.3.8/
extension_dir: /usr/lib64/20090626
作成するextensionの名前: mywork
1、スケルトンの作成
cd /usr/local/share/php-5.3.8/ext/
./ext_skel --extname=mywork
cd mywork
2、とりあえずコンパイル
① config.m4を修正
inl 以下をコメントアウトからはずす。
PHP_ARG_WITH(eigen, for eigen support,
Make sure that the comment is aligned:
[ --with-eigen Include eigen support])
② コンパイル
# phpize
# ./configure
# make
これで、./modules内に、mywork.soが作成される。
されなかったらなんか間違ってる。
③ PHPにextensionを読み込ませる。
# ln -s /usr/local/share/php-5.3.8/ext/mywork/modules/mywork.so /usr/lib64/20090626/
加えて、php.iniに「extension=mywork.so」を記入しておく。
make installしても良いが、これから何度もコンパイルするたびにmake installするのがめんどくさいから、シンボリックリンクはる。
3、引数取得・戻値返却
こんなPHP extensionを書くためにやる事。
① php_mywork.h
// 関数名を定義
PHP_FUNCTION(MYWORK);
② mywork.c
/* zend_function_entry の中に、MYWORKの行を追記 */
const zend_function_entry kakasi_functions[] = {
PHP_FE(confirm_kakasi_compiled, NULL) /* For testing, remove later. */
PHP_FE(MYWORK, NULL)
PHP_FE_END /* Must be the last line in kakasi_functions[] */
};
~~~
PHP_FUNCTION(MYWORK){
// 値定義
int str_len;
char *str;
// 引数の取得
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
"s", &str, &str_len) == FAILURE) {
return;
}
// 戻り値作成(文字列)
RETURN_STRINGL(str,str_len,0);
}
これで、引数「引数」が戻される。
longやdoubleなどの返却は、同じようなマクロを使って返却する。詳しくは、以下を参照。
Zend API: PHPのコアをハックする
配列やオブジェクトの返却はチョットややこしい。
・配列を返却
PHP_FUNCTION(MYWORK){
~~~
// zvalの定義
zval *return_array;
char *separated_word
char words[1024];
words="test,test,test,test";
// 配列を表すzvalを作成
MAKE_STD_ZVAL(return_array);
if(array_init(return_array) != SUCCESS){}
// 文字の分割
separated_word = strtok( words, "," );
while( separated_word != NULL ){
// 配列に値を追加する。
add_next_index_stringl(return_array,separated_word,strlen(separated_word),1);
separated_word= strtok( NULL, "," ); /* 2回目以降 */
}
// 配列を返却
*return_value = *return_array;
zval_copy_ctor(return_value);
}
・オブジェクトを返却
PHP_FUNCTION(MYWORK){
~~~
// 返却オブジェクトの生成
zval *wordset;
MAKE_STD_ZVAL(wordset);
if(object_init(wordset) != SUCCESS){}
// プロパティを設定
add_property_stringl(wordset,"base",str,strlen(str), 1);
add_property_stringl(wordset,"hira",hira,strlen(hira),1);
add_property_stringl(wordset,"kata",kata,strlen(kata),1);
add_property_stringl(wordset,"alph",alph,strlen(alph),1);
// オブジェクトの返却
*return_value = *wordset;
zval_copy_ctor(return_value);
}
3、クラス作成
こんなPHP extensionを書くためにやる事。
member1;
$obj->member2;
$ret = $obj->method();
?>
① php_mywork.h
// 以下を追記する。
PHP_FUNCTION(mywork);
PHP_METHOD(mywork, method);
static zend_class_entry *mywork_ce;
② mywork.c
/* zend_function_entry の中に、MYWORKの行を追記 */
const zend_function_entry kakasi_functions[] = {
PHP_FE(confirm_kakasi_compiled, NULL) /* For testing, remove later. */
PHP_FE(MYWORK, NULL)
PHP_ME(MYWORK, method ,NULL)
PHP_FE_END /* Must be the last line in kakasi_functions[] */
};
~~~
/* PHP_MINIT_FUNCTION(mywork) の中に、MYWORKの行を追記 */
PHP_MINIT_FUNCTION(mywork)
{
/* If you have INI entries, uncomment these lines
REGISTER_INI_ENTRIES();
*/
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "", mywork_functions);
mywork_ce = zend_register_internal_class(&ce TSRMLS_CC);
zend_declare_property_string(mywork_ce,"member1", strlen("member1"),"初期値", ZEND_ACC_PUBLIC);
zend_declare_property_string(mywork_ce,"member2", strlen("member2"),"初期値", ZEND_ACC_PUBLIC);
return SUCCESS;
}
~~~
PHP_FUNCTION(mywork){
return;
}
PHP_METHOD(mywork, method){
// 定義
zval *obj, *member1, *member2;
// メンバ変数の取得
obj = getThis();
member1 = zend_read_property(Z_OBJCE_P(obj),obj, "member1",strlen("member1"), 1 TSRMLS_CC);
member2 = zend_read_property(Z_OBJCE_P(obj),obj, "member2",strlen("member2"), 1 TSRMLS_CC);
// 戻り値作成(文字列)
RETURN_STRINGL(member1,strlen(member1),0);
}
番外、C++を使いたい場合
CではなくC++を使いたい場合の今までと異なる点を上げる。
① config.m4
inl コンパイラの環境変数を設定
CC=/usr/bin/gcc
CFLAGS="-g -O2 -lstdc++"
CXX=/usr/bin/g++
CXXFLAGS=-fPIC
~~~
inl 拡張子をc→ccに変更する。
PHP_NEW_EXTENSION(eigen, eigen.cc, $ext_shared)
② ファイルの拡張子
mv mywork.c mywork.cc
③ mywork.cc
// #includeを extern "C"で囲む
extern "C"{
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_eigen.h"
}