PHP
CakePHP
tips
cakephp3

CakePHP3で一つのクエリ結果をネストループさせるときに注意すること

CakePHP3で実装する際に、find()した結果をforeachでネストループさせる時に、

想定外の挙動をしてハマりましたので、tipsとして記録します。


背景

Usersテーブルに入っているユーザそれぞれに対して、

そのユーザとその他のユーザの類似度を計算したかった。

そのため、Usersテーブルの中身を2重ループするような実装をした。

$users = $this->Users->find()->all();

echo "*START\n";
foreach ($users as $outerUser) {
echo "OUTER: {$outerUser->id}\n";

foreach ($users as $innerUser) {
echo "INNER: {$innerUser->id}\n";
}
}
echo "*END\n";


問題となる結果

なぜか外側のループが最後まで回らず1回目で終了した。

*START

OUTER: 1
INNER: 1
INNER: 2
INNER: 3
INNER: 4
INNER: 5
*END


解決策

toArray()をつかって配列にすることで問題は起きなくなった。

が、ポピュラーで割とやりがちな実装だと思うので要注意だと思いました。

$users = $this->Users->find()->toArray();


ソース

issueを上げて確認したところ、そういった仕様という認識で良い模様。

https://github.com/cakephp/cakephp/issues/13021