PHPプロ!TIPS+

PHPの「魔法の杖」runkitを使ってみよう

PHPのこの関数が、あともうちょっとこんな挙動をしてくれたらなぁ。。。
デバッグのために、一時的にここだけ動作を変更させたいんだけどなぁ。。。
そんな風に思うこと、ありませんか?

今回は、そんなかゆい所に手が届く一風変わったPHPエクステンション、「runkit」をご紹介します。

runkitは、PHPの定数や関数、クラス、メソッドを追加・変更・削除したり、独自のスーパーグローバル変数を定義したりできるPHPのエクステンションです。

基本的な関数などの追加・変更機能はPHP4と5の全てのバージョンで使用することができ、独自のスーパーグローバル変数定義はPHP4.2以上で使用可能となります。

加えて、PHP5以上では、「サンドボックス」という独自のPHP実行空間を持つスレッドを生成する機能も利用することができます。

このライブラリはPECL拡張モジュールとして提供されています。以下のようにpeclコマンド(もしくはpearコマンド)を使用しすることでインストールすることができます。 runkitは現在まだベータ版なので、モジュール名の指定には「-beta」表記をつけてください。

# pecl install runkit-beta

また、PHP5.2以上を利用している場合は現在リリース版として配布されているソース(執筆時点のバージョンは0.9)ではmake時にエラーが発生してしまうため、上記の方法ではインストールできません。

そのため、ソースをダウンロードした後、エラーの原因となるソースコードの修正を行ってからマニュアルでインストールをする必要があります。

$ wget http://pecl.php.net/get/runkit-0.9.tgz
$ tar xvzf
$ cd runkit-0.9

runkit_import.c 内で使用されているzend_unmangle_property_name()関数(バージョン0.9では230行目にあります)の引数を

zend_unmangle_property_name(key, &cname, &pname);

から

zend_unmangle_property_name(key, key_len, &cname, &pname);

に変更した上で、インストール作業を行ってください。

$ phpize
$ ./configure --enable-runkit --enable-maintainer-zts
$ make
$ sudo make install

あとは、extension=runkit.soの記述をphp.iniに追記してください。

※なお、この問題は既にCVSリポジトリ上のソースでは修正されているので、そちらをチェックアウトしてきて使用すれば修正の必要はありません。

では、早速使ってみましょう。

<?php

function test ($data){
  echo 
"foo $data \n";
}

test("bar");

runkit_function_redefine('test''$data, $data2 = "huni"'
                         
'echo "baz $data $data2 \n";');

test("hoge""huga");
test("hoge");
?>

結果:
foo bar 
baz hoge huga 
baz hoge huni 

上はもっとも単純な例ですが、runkitの関数を使用する前後で、test関数の挙動が変わっていることがわかります。。

runkit_function_redefine関数を使うと、既に定義済みの関数の内容を丸ごと再定義することができます。

第1引数に再定義したい関数名、第2引数にその関数で新たに与える引数定義、第3引数に実際のコードを、それぞれ指定します。

もちろんこの例だけだと「それ関数の定義書き換えれば。。。?」と思ってしまうかもしれません。

ですが実際の開発では、共通ライブラリで使用されているせいで勝手に変えられないけど、テストや拡張のために一時的にこの関数を変更したい。。。という要求が出ることがことがあります。

そういった場合などには、この関数を利用することで他の人には迷惑をかけずに共通関数の拡張が行えますので、ちょこっと便利です。 redefine以外にもrenamecopyなど色々な操作をする関数があり、また関数だけでなく定数やクラスのメソッドにも同様の操作が可能です。

また、上記の例ではユーザー定義関数を変更しましたが、runkitは強力な機能としてPHPの組み込み関数に対しても変更を加えることができます。

php.iniに

runkit.internal_override = On

という設定を加えてやる事でrunkitの機能が広がり、PHPの組み込み関数に対しても変更を加えられるようになります。例として、以下のようにstrlen関数を変更してみます。

test_runkit.php:
<?php
runkit_function_copy
('strlen''hoge');
runkit_function_remove('strlen');
runkit_function_add('strlen''$str''
echo $_SERVER["PHP_SELF"] . "\n";
return hoge($str);
'
);
?>

test.php:
<?php
$string 
"1234567";
include_once(
"test_runkit.php");
echo 
strlen($string) . "\n";
?>

結果:
test.php
7

strlen関数を文字列の長さを返すだけでなく、呼び出されたPHPのソースコード名も返すようにしてみました。

これを応用することで、PHPの組み込み関数の処理に対してLoggingを挟み込むことができ、デバッグやデータの流れを把握したい時などにもちょっと便利です。他にも、使い方はいろいろでしょう。

このように、runkitはPHPの各種挙動をダイナミックに変更することが出来ます。そういう意味では使い方を間違うと諸刃の剣にもなりますが、うまく使えばPHPをとても便利に拡張できます。

開発時のちょっとしたテストやデバッグなどであれば、「かゆい所に手が届く」使い方ができると思います。デフォルトのままだと色々細かいところで不便だな、と感じるところがある人は、一度試してみてはいかがでしょうか。

PECLパッケージ・runkit:http://pecl.php.net/package/runkit

マニュアル:http://www.phppro.jp/phpmanual/php/ref.runkit.html

バックナンバーについて

TIPS-MLは、毎週金曜日に更新され、新しい記事が掲載されます。

Tipsꗗy[W 

Pick Up Q&A

Q
ログファイルの中の空のデータ行を削除したい
 このエントリーをはてなブックマークに追加 
A
ログのデータ個数(列数)が固定で、空のログが"<><><>"だと既知であれば if ($line === "<><><>") { continue; } で読み飛ばしてもいいのでは? ...

>>続きを読む

まずは配列や文字列の扱いから、じっくり勉強して行きましょう。

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)