2017-10-18 5 views
2

私はここに私は行く、スタック/グーグルで多くのことを検索し、私の質問に適切な答えを見つけられませんでした:foreach内のクエリはOKですか?

を私はのためにいくつかの計算やものを使用してのような全く悪い習慣であることを知っている:

foreach (SomeModel::find() as $item) 

それは大丈夫ですがforeachの中で直接見つける置くために、数のように($アイテム)や並べ替えの:

for ($i = 0; $i < count($items); $i++) 

は最近、私は私が働いているコードで奇妙な練習を見ましたか?私はそのアイデアが好きではないので、本能的に私はいくつかの変数を入れないようにしていますが、今は自分の仕事が改善/コードを見直しています。なぜ?

foreachがインテリジェントな実装であることはわかっていますが、この構造がそのような最適化を行うかどうかはわかりません。

+1

さて、私はこのケースでは、最適化のことは知らないが、それは読みやすさとクリーンなコードに来るとき、私はそれだけで結果を保持する変数 '$のmodels'を使用するクリーナーだと確信しています。私は、この種のコードにいくつかのパフォーマンスの欠陥があるかどうかを知ることに興味があります。 – teeyo

答えて

1

foreach()は冒頭arrayを取得し、それを反復処理するためにポインタを移動:

最初のフォームは、与えられた配列をループby array_expression各繰り返しで、現在の要素の値が$ valueに割り当てられ、内部配列ポインタが1つ進んでになります(次の反復では、次の要素が表示されます)。

重点鉱山

だからあなたの関数は一度だけ呼び出されます。この動作は、オペコードを見ると分かります。

Without assignment

<?php 
function find() { 
    return [1, 2, 3, 4, 5, 6, 7, 8]; 
} 

foreach (find() as $n) { 
    echo $n.PHP_EOL; 
} 

オペコード:

line  #* E I O op       fetch   ext return operands 
------------------------------------------------------------------------------------- 
    3  0 E > NOP              
    7  1  INIT_FCALL            'find' 
     2  DO_FCALL          0 $1  
     3  > FE_RESET_R          $2  $1, ->8 
     4 > > FE_FETCH_R            $2, !0, ->8 
    8  5 > CONCAT           ~3  !0, '%0A' 
     6  ECHO              ~3 
     7  > JMP              ->4 
     8 > FE_FREE             $2 
    9  9  > RETURN             1 

そしてwith assignment

<?php 
function find() { 
    return [1, 2, 3, 4, 5, 6, 7, 8]; 
} 
$f = find(); 
foreach ($f as $n) { 
    echo $n.PHP_EOL; 
} 

オペコード:

line  #* E I O op       fetch   ext return operands 
------------------------------------------------------------------------------------- 
    3  0 E > NOP              
    6  1  INIT_FCALL            'find' 
     2  DO_FCALL          0 $2  
     3  ASSIGN             !0, $2 
    7  4  > FE_RESET_R          $4  !0, ->9 
     5 > > FE_FETCH_R            $4, !1, ->9 
    8  6 > CONCAT           ~5  !1, '%0A' 
     7  ECHO              ~5 
     8  > JMP              ->5 
     9 > FE_FREE             $4 
    9 10  > RETURN             1 

ご覧のとおり、唯一の相違点は、への割り当てが行われたときのASSIGN命令です。

これはほとんどの場合、読みやすさの問題です。私の意見では、適切な名前の変数にメソッドの戻り値を代入するのが少し読みやすくなっています。アンクルボブは、しかし、クリーンコードで反対を述べている:

ループの制御変数は、通常、同じソースからこのかわいい機能のように、ループ文内で宣言されなければなりません。

public int countTestCases() { 
    int count= 0; 
    for (Test each : tests) 
   count += each.countTestCases(); 
   return count; 
} 
2

forループを使用している場合は、すべての反復で条件がチェックされます。したがって、varと値を単に比較するのではなく、すべての反復で関数(count)を呼び出す必要があります。ループは

$count = count($items); 
for ($i = 0; $i < $count; ++$i) { ... } 

foreachは異なる振る舞いの違いを作る前に、だから、カウント条件を動かします。すべての反復でSomeModel::find()を評価する代わりに、この部分は一度だけ評価され、ループのためだけに保存​​されます。また、SomeModel::find()の結果をvarに保存して、その変数をforeachループに使用することもできますが、それは違いはありません。ループのためにだけを使用する場合、コンパイラはまったく同じことを行う必要があります。

しかし、留意してください。この種の最適化はコンパイラの一部でなければならず、わずかな繰り返ししかない場合は、タイミングの利点は0に近くなるはずです。各命令は、各反復において評価さfor()、対照的に

+0

あなたの答えは良いですが、@isheggは良い詳細で説明しました、ありがとう! – calexandre

関連する問題