2014年2月18日火曜日

PHPのタイプヒンティングは配列の参照渡しの時も有効

PHPのタイプヒンティングはバグの防止につながるので積極的に使っている。ちょっと気になったのが、配列の参照渡しの時には動作は変わらないのかということだった。

タイプヒンティングは、関数やクラスメソッドの引数が、特定のクラスに属するインスタンスであることや特定のインターフェースを実装していること、あるいは配列であることなどを強制する。たとえば、fooメソッドの引数$argが配列でなければならない時は、次のように書く。
protected function foo(array $arg) {
  ...
}

と、ここまでは公式リファレンスにも書いてある通りだ。で、僕が気になったのは、次のように引数を参照渡しにするときにも、同様にタイプヒンティングが有効なのかどうかだ。
protected function foo(array &$arg) {
  ...
}

では実際に試してみよう。次のような簡単なプログラムを用意する。testClassのメソッドfooの引数は配列を想定しており、ここでタイプヒンティングを使っている。
<?php
class testClass {
  public function foo(array $arg) {
    foreach ($arg as $key => $val) {
      print $val . "\n";
      $arg[$key] += 1;
    }
  }
}

$test = new testClass();
$arg = array(1, 2, 3);
echo "first\n";
$test->foo($arg);
echo "second\n";
$test->foo($arg);

$arg2 = 'string';
$test->foo($arg2);

これを実行すると、次のような結果が得られる。
first
1
2
3
second
1
2
3

Catchable fatal error: Argument 1 passed to testClass::foo() must be of the type array, string given, called in /path/to/phpfile/test.php on line 19 and defined in /path/to/phpfile/test.php on line 3

タイプヒンティングにより、配列以外の引数を与えたことでエラーとなった。
では次に、メソッドfooの引数を参照渡しにしてみる。(1行だけ変更)
<?php
class testClass {
  // public function foo(array $arg) { // 変更前
  public function foo(array &$arg) {
    foreach ($arg as $key => $val) {
      print $val . "\n";
      $arg[$key] += 1;
    }
  }
}

$test = new testClass();
$arg = array(1, 2, 3);
echo "first\n";
$test->foo($arg);
echo "second\n";
$test->foo($arg);

$arg2 = 'string';
$test->foo($arg2);

これを実行すると、次のような結果が得られた。
first
1
2
3
second
2
3
4

Catchable fatal error: Argument 1 passed to testClass::foo() must be of the type array, string given, called in /path/to/phpfile/test2.php on line 20 and defined in /path/to/phpfile/test2.php on line 4

参照渡しにしたことにより、引数として渡した元の配列の中身が変化し、先ほどと違ってメソッドを2回呼ぶと結果が変わっている。そして、参照渡しにしたときもタイプヒンティングは参照渡しにしない時と全く同様に動作した。

ということで、配列で参照渡しの時もタイプヒンティングは気にせず使って大丈夫。まあよく考えれば、オブジェクトのインスタンスを渡す時は参照渡しだから、それと同じ動作と考えれば当然か。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうそ。

0 件のコメント:

コメントを投稿