ありがとう。また会おう。

ゆるいかんじで。かたのちからぬいて。やってます。

foreachで回しながらデータを修正する

http://qwik.jp/mumu/recipe.html
より。このやり方、お、いいじゃん・・・って思ったんだけど。。。

<?php
    $sth = $dbh->prepare("SELECT name, colour FROM fruit");
    $sth->execute();
    $results = $sth->fetchAll(PDO::FETCH_ASSOC);
    for ($results as &$rec) {
        $rec['fullname'] = $rec['firstname'] . $rec['lastname'];
    }
?>

$rec の前の & がポイント。これで、PDOが返してきた配列の内容の追加や上書きをすることができます。

上記ソースで、for はたぶん foreach の typo だけど、そっか、参照使えばよかったのか。気づきそうなもんなのに気づかんかった。。。
いままで馬鹿丁寧に

<?php
for ($results as $key => $rec) {
  $results[$key]['fullname'] = $rec['firstname'] . $rec['lastname'];
}

とかやってた。。。


・・・ってエントリーで終わる予定だったんだけど、この方法、問題点が2つ発覚。

問題点1→仮変数の後始末をしないとちょっとやっかいなことに・・・

このやり方だと、ループで回した最後の配列要素がリファレンスで格納されてしまう。
なので、同じ仮変数名で再度 foreach を回すとおかしな挙動をしてしまう。

<?php
    $sth = $dbh->prepare('SELECT name, colour FROM fruit');     
    $sth->execute(); 
    $results = $sth->fetchAll(PDO::FETCH_ASSOC);
    foreach ($results as &$rec) {
        $rec['fullname'] = $rec['firstname'] . $rec['lastname']; 
    }
    //同じ変数名を再度使って、表示させようとすると、最後の1つが想定とは異なる値になる
    foreach ($results as $rec){
        echo $rec['fullname'] . '<br />';
    } 

なんでそうなるかは・・・説明ややこしいので省略。f(^^;;;
てか、100%理解しきれてないので、ちゃんと説明できるようになったら、あとで補足します。
一度目の foreach 回した後で、$results 配列を var_dump() してみるとよくわかります。
一番最後の要素がリファレンスになっているはず。これが悪さをしてるっぽい。


回避方法としては、同じ名前を使わないようにするか、ループを回した後、一時変数(ここでは $rec )をループを抜けた直後に unset() しておく。

<?php
    //前略
    foreach ($results as &$rec) {
        $rec['fullname'] = $rec['firstname'] . $rec['lastname']; 
    }
    //ここで一度ループで使った仮変数$recを初期化しておくと、問題はおきない。
    unset($rec);
    
    foreach ($results as $rec){
        echo $rec['fullname'] . '<br />';
    } 

問題点2→PHP4ではそもそも使えない。。。

PHP4だと文法エラーになります。PHP4.4.9で確認。
こっちの方がどちらかというと問題かも。。。まだまだ現場では使ってますからね。PHP4。

結論

確かに、すっきり書けるので、最初は引用サイトのようなリファレンス使った書き方もいいかなと思ったのですが、
PHP4で動かないという問題が大きく、現場では使わないことに確定。
あと、やっぱリファレンスの「&」って見落とすからね。
誤解を防ぐためにもちゃんと、上であげた「馬鹿丁寧な方法」の方がいいのかも。
念のため、再掲:

<?php
for ($results as $key => $rec) {
  $results[$key]['fullname'] = $rec['firstname'] . $rec['lastname'];
}

付記

引用サイトの本来の記事内容であるテンプレートエンジンMuMuは、使えるPHPバージョンの記載がWebページ上にないんだよね。。。
ダウンロードすればREADMEファイルとかにに書いてあるのかもしれないけど、こういう前提条件はWebサイトに記載すべきでは?
・・・まあ、たぶんPHP5なんだろうね、きっと。
・・・あ、「PDOで」って記述があるから、PHP5ですね。PHP4が視野に入ってるかは不明。