php ReflectionClass::invoke()で参照渡しの関数を使う
久しぶりにphpでハマっていたのでメモ。
phpunitでテストを書くときに、privateやprotectedをテストするときに、ReflectionMethodクラスを使う。
このときに実行する関数の引数が、参照渡しになっているときにエラーがでてハマった。
失敗例
まずは、こんな感じで書いていた。
<?php class Hello { public function checkCallByRef(array &$arr) { var_dump($arr); } } $arr = array(1,2,3); $Hello = new Hello(); $reflectionMethod = new ReflectionMethod($Hello, 'checkCallByRef'); echo $reflectionMethod->invoke($Hello, $arr);
実行すると、
Warning: Parameter 1 to Hello::checkCallByRef() expected to be a reference, value given in /tmp/test.php on line 12
汲み取ってくれ、と思ったけど、仕方がないので解決策を探す。 phpのドキュメントを見ると、
注意: 関数の引数の中に参照渡しを要するものがある場合は、 渡す引数の中でも参照にしておく必要があります。
とある。なるほど。
echo $reflectionMethod->invoke($Hello, &$arr);
つまりこういう事か。
Fatal error: Call-time pass-by-reference has been removed in /tmp/test.php on line 12
おい。さらに調べてみる。
注意: また、PHP 5.4.0 以降では call-time pass-by-reference 機能自体が削除されたので、 これを使おうとすると fatal エラーが発生します。
つかっているphpのバージョンは…5.6.6。 なんてこった。
成功例
ReflectionMethod::invokeArgs を使う。
<?php class Hello { public function checkCallByRef(array &$arr) { var_dump($arr); } } $arr = array(1,2,3); $Hello = new Hello(); $reflectionMethod = new ReflectionMethod($Hello, 'checkCallByRef'); echo $reflectionMethod->invokeArgs($Hello, array(&$arr));
配列の中で、値を参照で指定するという方法。
なんか気持ち悪い。invoke()対応して欲しいところ。
というか対応忘れなんじゃないかと思ってしまう。