PHP - Modifica o objeto atual no loop foreach


111

Eu queria saber se é possível editar o objeto atual que está sendo tratado dentro de um foreachloop

Estou trabalhando com uma série de objetos $questionse quero examinar e procurar as respostas associadas a esse objeto de pergunta em meu banco de dados. Então, para cada pergunta, vá buscar os objetos de resposta e atualize a corrente $question dentro do meu foreachloop para que eu possa produzir / processar em outro lugar.

foreach($questions as $question){
    $question['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}

Como ArtjomKurapov e @topener sugeriram, eu estava procurando por 'passagem por referência' usando o sinal &. Obrigado rapazes :) tenham um bom dia
Garbit

Respostas:


207

Existem 2 maneiras de fazer isso

foreach($questions as $key => $question){
    $questions[$key]['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}

Desta forma, você salva a chave, para que possa atualizá-la novamente na $questionsvariável principal

ou

foreach($questions as &$question){

Adicionar o &manterá o $questionsatualizado. Mas eu diria que o primeiro é recomendado, embora seja mais curto (veja o comentário de Paystey)

De acordo com a foreachdocumentação do PHP :

Para poder modificar diretamente os elementos do array dentro do loop, preceda $ value com &. Nesse caso, o valor será atribuído por referência.


32
Referências em foreachrealmente não são recomendadas, a maneira como o foreachpassa ao redor da parte do valor do loop resulta em um comportamento imprevisível. Pode demorar mais, mas você está muito mais seguro usando o método 1 aqui.
Paystey de

1
Acabei de passar uma hora perplexo depurando um problema causado pelo uso de uma referência em um foreach. Eu reutilizei o mesmo nome de variável para uma segunda chamada foreach - como eu havia passado a primeira por referência, ele continuou modificando o último item na matriz! Usar um índice explícito não teria esse problema.
Hippyjim

7
@Paystey você pode citar suas fontes ou dar uma explicação detalhada?
Nico,

2
Por que manipular referências não seria seguro? C / C ++, onde você tem que manipular referências em todos os lugares, é inseguro? Depende de você torná-lo seguro ou não, não o idioma.
Kalzem

2
@BabyAzerty: Paystey não disse referências "em geral", mas em foreach, sobre terror como este: stackoverflow.com/questions/3307409/… (@Nico, FYI, também.)
Sz.

6

Certamente, usar array_mape se usar uma implementação de contêiner ArrayAccesspara derivar objetos é apenas uma maneira mais inteligente e semântica de fazer isso?

A semântica do mapa de matriz é semelhante na maioria das linguagens e implementações que vi. Ele é projetado para retornar uma matriz modificada com base no elemento da matriz de entrada (alto nível ignorando a preferência de tipo de compilação / tempo de execução da linguagem); um loop destina-se a realizar mais lógica.

Para recuperar objetos por ID / PK, dependendo se você está usando SQL ou não (parece sugerido), eu usaria um filtro para garantir que obtivesse uma matriz de PKs válidos, então implodiria com vírgula e colocaria em uma IN()cláusula SQL para retorna o conjunto de resultados. Ele faz uma chamada em vez de várias via SQL, otimizando um pouco o call->waitciclo. Mais importante ainda, meu código seria lido bem para alguém de qualquer linguagem com um grau de competência e não enfrentamos problemas de mutabilidade.

<?php

$arr = [0,1,2,3,4];
$arr2 = array_map(function($value) { return is_int($value) ? $value*2 : $value; }, $arr);
var_dump($arr);
var_dump($arr2);

vs

<?php

$arr = [0,1,2,3,4];
foreach($arr as $i => $item) {
    $arr[$i] = is_int($item) ? $item * 2 : $item;
}
var_dump($arr);

Se você sabe o que está fazendo, nunca terá problemas de mutabilidade (tendo em mente que se você pretende sobrescrever, $arrvocê pode sempre $arr = array_mape ser explícito.


2
Muito mais intuitivo do que fazer um foreach - é exatamente para isso que essa função foi projetada.
benjaminhull de
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.