spidermonkey拡張モジュール
SpiderMonkeyは、Cで書かれたGeckoのJavaScriptエンジンで、Firefoxにも採用されています。
で、このSpiderMonkeyのPHPバインディングが出てきました。PHP5.3以降が必要です。
「PHPでjavascriptを動かす」モジュールらしく、javascriptコードにPHPの関数や変数を引き渡して使えるっぽいとのこと。とりあえず試してみました。環境は
- PHP5.3.0β1
- spidermonkey 0.1.1
です。
まずはインストール。libjs 1.7.0以上が必要とのことで、こちらからインストール。。。。なんですが、Compiling and Installing SpiderMonkey 1.7.0 in Linux. « the DtTvB's Old Blogを参考に手動でインストール。
$ wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.7.0.tar.gz $ tar zxf js-1.7.0.tar.gz $ cd js/src/ $ make -f Makefile.ref $ sudo mkdir /usr/local/include/js $ cp *.{h,tbl} /usr/local/include/js/ $ sudo cp *.{h,tbl} /usr/local/include/js/ $ sudo cp Linux_All_DBG.OBJ/*.h /usr/local/include/js/ $
なぜ「js」ディレクトリにコピーしているかというと、spidermonkey拡張モジュールをインストールする際に参照されるディレクトリが、/usr/local/{include,lib}もしくは/usr/{include,lib}下にある
- js
- mozjs
ディレクトリのいずれかだからです。なので、「mozjs」ディレクトリを作ってインストールしても良いハズ。
で、spidermonkey拡張モジュールのインストール。こちらはpeclコマンド一発で入りました。まあ、一発でインストールできるまで試行錯誤したわけですが。。。
$ sudo pecl install -a spidermonkey-alpha
$
さて、まずは簡単なものから。「好きな関数といえばvar_dump」ということで、こいつから。
<?php /** * javascriptのコンテキストを生成 */ $context = new JSContext(); /** * PHPのvar_dump関数をjavascript側のvar_dump関数として登録。 * * 第1引数しかない場合、同名の関数として登録されるので、 * $context->registerFunction('var_dump'); * と書いてもOK */ $context->registerFunction('var_dump', 'var_dump'); /** * 実行するjavascriptコード */ $script =<<< EOD var arr = [1,2,3,4,5]; var_dump(arr); EOD; /** * javascriptコードを評価(実行) */ $context->evaluateScript($script);
これを実行すると、
$ /usr/local/lib/php53/bin/php -dextension=spidermonkey.so var_dump.php object(stdClass)#2 (5) { ["0"]=> int(1) ["1"]=> int(2) ["2"]=> int(3) ["3"]=> int(4) ["4"]=> int(5) } $
のようになります。そうか、javascriptの配列って、オブジェクトなのか。。。
また、ファイルハンドラのようなストリームを扱う関数も使えます。
<?php $context = new JSContext(); $context->registerFunction('fopen'); $context->registerFunction('fread'); $context->registerFunction('fclose'); $context->registerFunction('filesize'); $context->registerFunction('var_dump'); $script =<<< EOD var filename = "somefile.txt"; var handle = fopen(filename, "r"); var contents = fread(handle, filesize(filename)); fclose(handle); var_dump(contents); EOD; $context->evaluateScript($script);
"hoge"と書かれたsomefile.txtを作成して、上のスクリプトを実行すると、次のようになります。
$ cat somefile.txt hoge $ /usr/local/lib/php53/bin/php -dextension=spidermonkey.so file.php string(5) "hoge " $
PHPのクラスを登録する場合は、JSContext#registerClassメソッド。次のサンプルで、javascriptコード内でDateTimeオブジェクトを使っているのが分かりますかね?
<?php $context = new JSContext(); $context->registerFunction('printf'); /** * PHP側のクラス"DateTime"を登録 * registerFunctionと同じで第2引数を省略できる */ $context->registerClass('DateTime'); $script =<<< EOD now = new DateTime(); printf("%s\\n", now.modify('15 years ago').format('Y/m/d H:i:s')) EOD; $context->evaluateScript($script);
実行すると次のようになります。
$ date 2009年 3月 9日 月曜日 14:46:14 JST $ /usr/local/lib/php53/bin/php -dextension=spidermonkey.so datetime.php 1994/03/09 14:46:15 $
変数を割り当てる場合は、JSContext#assignメソッドを使います。次のサンプルでは、PHP側で作成したDirectoryオブジェクトを変数名「dir」として割り当てています。javascriptコードはPHPマニュアルのdir関数のサンプルから持ってきてます。
<?php $context = new JSContext(); $context->registerFunction('printf'); /** * PHP側の変数"$dir"をjavascriptの変数"dir"に割り当てる */ $dir = dir('/usr/local/lib/php53/bin'); $context->assign('dir', $dir); /** * "\n"のエスケープに疲れたのでNowdoc */ $script =<<< 'EOD' printf("Handle: %s\n", dir.handle); printf("Path: %s\n", dir.path); var entry; while (false != (entry = dir.read())) { printf("%s\n", entry); } dir.close(); EOD; $context->evaluateScript($script);
これを実行すると、こんな感じ。
$ /usr/local/lib/php53/bin/php -dextension=spidermonkey.so dir.php Handle: Resource id #5 Path: /usr/local/lib/php53/bin pecl phar pear phpize php-config .. phar.phar . peardev php $
ほうほう。それなりに動作する模様。
あとは、使い道なんですが。。。全然思い浮かばないw