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でループしてしまうとメモリを無駄に消費してしまうので注意しよう。