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
Postar um comentário
Nota: fique a vontade para expressar o que achou deste artigo ou do blog.
Dica: para acompanhar as respostas, acesse com uma conta do Google e marque a opção "Notifique-me".
Atenção: o blogger não permite inclusão de tags nos comentários, por isso, use algum site externo para postar seu código com dúvidas e deixe o link aqui. Exemplo: pastebin.com