perlと違ってリファレンス渡しても、、、

perlは配列の配列を作るときには、配列リファレンスを使う。

@a = (0..1024*1024);
$b = [\@a,\@a,\@a,\@a];

foreach my $c ($b){
  print "OK\n";
}

$cに入るのもリファレンスだから、使用する時には意識して使う必要がある。
PHPの場合、リファレンスであってもPHP側で自動的に変換してしまう時があるので、注意が必要だ。

<?php
$a = range(0,1024*1024);
$b = array(&$a,&$a,&$a,&$a);
foreach($b as $c){
  echo "OK\n";
}
?>

こう書くと、$bは確かに$aの配列リファレンスを4つ格納した配列となるのだが、
実行してみると、

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 35 bytes) in /private/tmp/test.php on line 5

というエラーが発生する(Core2Duo2.4GHz 2GBメモリ PHP5.2.5)
phpは実行時に128MBしか使えないように設定されているので、それ以上の領域を使おうとすると上記のようなエラーが表示される。

perlのつもりでいると、PHPで使用した$cというのにはリファレンスが入りそうだし、foreach内で配列の処理をしている訳でもないのに、何故128MB消費したと言われるのか訳がわからない。

もしかして
foreachの中で$cに入れられるのはリファレンスではなく、その参照先の配列のコピーではないか

と考えると納得できる部分がある。

実際、以下のようにすると正常に完了する。

<?php
$a = range(0,1024*1024);
$b = array(&$a,&$a,&$a,&$a);
for($i=0;$i<count($b);$i++){
  echo "OK\n";
}
?>

また、foreach文中で配列の要素を使う場合は、リファレンスを使うようにしなければならない。
$c = $b[$i] とすると、ここでも配列のコピーが行われてしまうようだ。

<?php
$a = range(0,1024*1024);
$b = array(&$a,&$a,&$a,&$a);
for($i=0;$i<count($b);$i++){
  $c = &$b[$i]; # リファレンスを使う
  echo "OK\n";
}
?>

なので、配列の配列を使用する場合などでは、foreachでループしてしまうとメモリを無駄に消費してしまうので注意しよう。