PHPでネイティブ関数を含むコードのテスタビリティを上げるもう1つの方法
via. PHPでネイティブ関数を含むコードのテスタビリティを上げる2つの方法 - 絶品ゆどうふのタレ
こういう"PHPでどこまでできるか"ネタっていいですね。
すみません。まだPHP5.2系です。。。
また、PHP 5.4で盛り上がってるご時世にPHP 5.3な話をしちゃってて相変わらず空気読めてないけどそこはスルーで。
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
ちなみに、
runkitに近い拡張モジュールであるtest_helpersもありますが、内部関数はrenameできないようです。
php-test-helpersとかは使わないのか
<?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にも言及してましたね。すみません。
まあ、実際にrunkit使う場合はこうなるよ、というということで捉えてもらえると有りがたいです。あと、id:Yudoufuさんのエントリを否定するものでもないです。念のため。
元々、PHPではこれらの問題に対処するために、コードそのものの抽象度を不必要に上げたり*2、無理矢理やるならrunkitのようなエクステンションでトリッキーな対応*3を行うことによって挙動を差し替える、等の対処法しかありませんでした。
runkit、使われてないのかなぁ。。。
追記2(2011/08/09 13:09)
runkit怖くないよw
@shimooka 黒魔術な香りがするのでまだ手を出してないっす。