Do You PHP はてブロ

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

PHPでネイティブ関数を含むコードのテスタビリティを上げるもう1つの方法

via. PHPでネイティブ関数を含むコードのテスタビリティを上げる2つの方法 - 絶品ゆどうふのタレ

こういう"PHPでどこまでできるか"ネタっていいですね。


また、PHP 5.4で盛り上がってるご時世にPHP 5.3な話をしちゃってて相変わらず空気読めてないけどそこはスルーで。

すみません。まだPHP5.2系です。。。

PECL:runkitを使う

なんでもありなrunkitに既存関数をオーバーライド(というか、関数の再定義)する関数があります。

ただし、ユーザー定義関数以外を再定義する場合、php.iniの設定に

runkit.internal_override=1

を追加する必要があります。
で、次のような感じでテストを書くことができます。今回使用したのは、PHP5.2.17+runkit1.0.0-devです。

<?php
class Foo
{
    public function load($file) {
        return file_get_contents($file);
    }
}

// ここからテストコード
runkit_function_redefine('file_get_contents', '$file', 'return "this is test result!!";');
$foo = new Foo;
var_dump($foo->load('http://www.example.com/'));  // string(21) "this is test result!!"

なお、関数を再定義してしまうとそれ以降の挙動も同様になってしまい、オリジナルの関数の機能が使えなくなってしまいますので、関数のバックアップを取るなどしておいたほうがいいかも。

<?php
class Foo
{
    public function load($file) {
        return file_get_contents($file);
    }
}

// ここからテストコード
runkit_function_copy('file_get_contents', 'file_get_contents_bak');
runkit_function_remove('file_get_contents');
runkit_function_add('file_get_contents', '$file', 'return "this is test result!!";');
$foo = new Foo;
var_dump($foo->load('http://www.example.com/'));  // string(21) "this is test result!!"

// テストが終わったらもとに戻す
runkit_function_remove('file_get_contents');
runkit_function_copy('file_get_contents_bak', 'file_get_contents');
var_dump($foo->load('http://www.example.com/'));  // html contents

ちなみに、


php-test-helpersとかは使わないのか

runkitに近い拡張モジュールであるtest_helpersもありますが、内部関数はrenameできないようです。

<?php
/**
 * PHP Warning:  rename_function(): "file_get_contents" is an internal function in ...
 */
rename_function('file_get_contents', 'file_get_contents_bak');

追記(2011/08/09 13:02)

ブクマコメント読むまで華麗にスルーしてましたが、runkitにも言及してましたね。すみません。


元々、PHPではこれらの問題に対処するために、コードそのものの抽象度を不必要に上げたり*2、無理矢理やるならrunkitのようなエクステンションでトリッキーな対応*3を行うことによって挙動を差し替える、等の対処法しかありませんでした。

まあ、実際にrunkit使う場合はこうなるよ、というということで捉えてもらえると有りがたいです。あと、id:Yudoufuさんのエントリを否定するものでもないです。念のため。
runkit、使われてないのかなぁ。。。

追記2(2011/08/09 13:09)


@shimooka 黒魔術な香りがするのでまだ手を出してないっす。

runkit怖くないよw