takafumi blog

日々の勉強メモ

php ReflectionClass::invoke()で参照渡しの関数を使う

環境   CentOS 7.0 PHP 5.6

久しぶりに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のドキュメントを見ると、

ReflectionMethod::invoke

注意: 関数の引数の中に参照渡しを要するものがある場合は、 渡す引数の中でも参照にしておく必要があります。

とある。なるほど。

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()対応して欲しいところ。
というか対応忘れなんじゃないかと思ってしまう。