Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

spidermonkey拡張モジュール

SpiderMonkeyは、Cで書かれたGeckoJavaScriptエンジンで、Firefoxにも採用されています。
で、このSpiderMonkeyPHPバインディングが出てきました。PHP5.3以降が必要です。

PHPjavascriptを動かす」モジュールらしく、javascriptコードにPHPの関数や変数を引き渡して使えるっぽいとのこと。とりあえず試してみました。環境は

です。

まずはインストール。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