"Foreach" vs. "For" em PHP

Artigo que discute a performance das estruturas de repetição (loop) foreach e for no PHP.

performance

Hoje, em uma discussão em uma lista de PHP, fui surpreendido com a informação de que a estrutura "for" era mais rápida que a estrutura "foreach". Depois me deram a fonte da informação: The PHP Benchmark. Na fonte, diz que o "for" é mais rápido para escrita, mas é mais lento para leitura dos elementos percorridos. Observando o código do site, cheguei a conclusão de que ele estava meio furado.

De fato, o "foreach" é mais rápido que um "for" para leitura, já que utiliza um iterador interno que caminha de bloco em bloco de memória, avançando o cursor e obtendo o valor. Já o "for", precisa usar o operador colchetes para obter uma posição do array e esta operação precisa percorrer do início array até chegar à N-esima posição e retorná-la (já que o acesso é randômico). Isso torna o colchetes muito lento.

O problema é que no site dizia que para escrita ocorria o inverso: o "for" era mais rápido que o "foreach" (procure por "Modify Loop" no site). Avaliando os códigos usados para comparação, achei o problema. Veja uma simplificação dos códigos que foram comparados:

// FOR
$count = count($array);
for ($i = 0; $i < $count; ++$i) {
    $array[$i] = 1;
}

// FOREACH
foreach ($array as $i => $valor) {
    $array[$i] = 1;
}

É bastante lógico que o "for", neste caso, seja mais rápido. Veja que as operações internas são idênticas, só que, a cada iteração, o "for" apenas compara dois números e incrementa uma variável, já o "foreach" caminha uma posição do cursor, obtém o índice e atribui a $i, obtém o valor e atribui a $valor. Ou seja, o "foreach" faz coisas a mais, logo é mais lento.

No entanto, não faz sentido utilizar um "foreach" apenas para obter os índices. O ideal, seria comparar com um "foreach" que utiliza referência, pois, assim, não seria necessária a utilização do operador colchetes. O código ficaria assim:

// FOREACH COM REFERENCIA
foreach ($array as &$valor) {
    $valor = 1;
}

Agora sim o "foreach" foi mais rápido que o "for" e mais rápido que o "foreach" sem referência. Este foi o teste que o autor do site esqueceu de colocar e chegou a uma conclusão equivocada ou incompleta.

Portanto, na minha opinião, o "foreach" é sempre mais rápido que um "for" quando o objetivo é trabalhar com leitura ou escrita nos elementos percorridos no array. Como a essência do "foreach" é justamente a leitura ou manipulação dos elementos percorridos, não vejo contra-indicações quanto ao seu uso.

Mas quando usar um "for"?
Simples: quando você quer inicializar um valor, realizar comparações para determinar o momento de parada do loop, e precisa realizar operações a cada interação. Por exemplo, percorrer números de X a Y, obtendo os valores de um array destas posições.

E qual o defeito do "foreach"?
O "foreach" tradicional trabalha com uma cópia do array passado a ele. Isso significa que você usará o dobro da memória usada por um array para guardar os dois arrays na memória. Isso pode causar até estouro de memória em alguns casos. Mas, para as situações mais comuns, o "foreach" é muito bom.

Bom, este post é também para alertar aqueles que acreditam em tudo (ou quase tudo) que lêem. Na área de computação é preciso ter um olhar bastante crítico, até mesmo com resultados empíricos, pois existem muitos detalhes a serem considerados. Este blog também está aberto a críticas construtivas e não deve ser visto como uma verdade absoluta. Se você discorda de algo, pode deixar seu comentário.

0 comentários