読者です 読者をやめる 読者になる 読者になる

奇特なブログ

「殊勝に値する行いや心掛け」を意味する、奇特な人になる為のブログです

foreachの挙動

滝打ち1日目。

う〜ん、こいつはビックリだ。
いや、以下の記事のプログラムを、動かしてみて思ったんですけどね。

これなぁ…
http://d.hatena.ne.jp/gallu/20130201/p1

foraechって、思想として、
「配列の"全要素"を出力する」っていうのがあると思ってまして(どっかのページにも書いてたけど)、
「全要素」じゃない場合は、forでインデックスの範囲を指定しろって事なんじゃないかなぁと。
だから、foreachの中でunsetしようが何しようが、
「とにかく全要素出力するんだ!」とw
で、「配列をcopy」しているのではという仮説を検証する為に、以下の様なプログラムを。
PHPのVerは5.4.8。

-----------------------------------------------------------------------------------------

<?php

function diff_microtime($start, $end)
{
list($start_m, $start_t) = explode(' ', $start);
list($end_m, $end_t) = explode(' ', $end);
return ((float)$end_t + (float)$end_m) - ((float)$start_t + (float)$start_m);
}

var_dump(memory_get_usage(true));
var_dump(memory_get_peak_usage(true));

$awk = array();

for ($i = 0; $i < 100000; $i++)
{
$awk[] = $i + 1;
}

var_dump(memory_get_usage(true));
var_dump(memory_get_peak_usage(true));

$start = microtime();

foreach ($awk as $k => $v)
{
if (9 >= $k)
{
var_dump(memory_get_usage(true));
var_dump(memory_get_peak_usage(true));
}
}

$end = microtime();

var_dump(memory_get_usage(true));
var_dump(memory_get_peak_usage(true));

echo diff_microtime($start, $end) . "\n";

-----------------------------------------------------------------------------------------

実行結果。

$ php foreach_test.php
int(232408)
int(262144)
int(244544)
int(262144)
int(14881480)
int(15204352)
int(14883776)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14881904)
int(15204352)
int(14884160)
int(15204352)
int(14882088)
int(15204352)
int(14884344)
int(15204352)
0.016510009765625
$

あれ〜、foreachの実行を境にして、別にメモリが増えてはいないですね。
なぜだ・・・なぜだ・・・ちょっと分かりませんねぇ。
もう少し検証が必要そうですけど、それはまた後日に。

最後に、少し話変わりますけど、
上記の挙動なんかも考えると、繰り返し文(for、foreach、while)の使い分けについて、
規約を定めた方が良いんじゃないかなぁと、思い始めてきました。
数値添字配列なのか連想配列なのかによっても、変わってくると思いますし。
自分が知ってるのだと、pg_fetch_array()を使うと、
配列の中に数値添字と文字列添字のキーを両方持つので、メモリ食うんじゃね?とか。
あと、色々なページを見て検証した時に、
forよりforeachの方が(メモリはともかくとして)速度が速いというのも確かあったよなぁとか。

とまぁ、そんな事を一度整理してみたい所だなぁと、そう思ったわけです。