PHP - Modifica el objeto actual en foreach loop

111

Me preguntaba si es posible editar el objeto actual que se maneja dentro de un foreachbucle

Estoy trabajando con una matriz de objetos $questionsy quiero revisar y buscar las respuestas asociadas con ese objeto de pregunta en mi base de datos. Entonces, para cada pregunta, busque los objetos de respuesta y actualice la corriente $question dentro de mi foreachciclo para que pueda generar / procesar en otro lugar.

foreach($questions as $question){
    $question['answers'] = $answers_model->get_answers_by_question_id($question['question_id']);
}
Garbit
fuente
Como sugirieron ArtjomKurapov y @topener, estaba buscando 'pasar por referencia' usando el signo &. Gracias chicos :) que tengas un buen día
Garbit

Respuestas:

207

Hay 2 formas de hacer esto

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

De esta forma guardas la clave, para que puedas actualizarla nuevamente en la $questionsvariable principal

o

foreach($questions as &$question){

Agregar el &mantendrá $questionsactualizado el. Pero yo diría que se recomienda el primero aunque sea más corto (ver comentario de Paystey)

Según la foreachdocumentación de PHP :

Para poder modificar directamente los elementos de la matriz dentro del ciclo, preceda $ value con &. En ese caso, el valor se asignará por referencia.

Rene Pot
fuente
32
foreachRealmente no se recomiendan las referencias en , la forma en que las foreachtransferencias alrededor de la parte de valor del ciclo dan como resultado un comportamiento impredecible. Puede ser más largo, pero está mucho más seguro si usa el método 1 aquí.
Paystey
1
Acabo de pasar una hora perpleja depurando un problema causado por el uso de una referencia en un foreach. Reutilicé el mismo nombre de variable para una segunda llamada foreach; como había pasado la primera por referencia, ¡siguió modificando el último elemento de la matriz! El uso de un índice explícito no habría tenido este problema.
Hippyjim
7
@Paystey, ¿puede citar sus fuentes o dar una explicación detallada?
Nico
2
¿Por qué no sería seguro manipular referencias? ¿C / C ++, donde tienes que manipular referencias en todas partes, es inseguro? Depende de usted hacerlo seguro o no, no del idioma.
Kalzem
2
@BabyAzerty: Paystey no dijo referencias "en general", pero en foreach, con respecto al horror como este: stackoverflow.com/questions/3307409/… (@Nico, FYI, también.)
Sz.
6

Seguramente usar array_mapy si usar una implementación de contenedor ArrayAccesspara derivar objetos es solo una forma más inteligente y semántica de hacerlo.

La semántica del mapa de matriz es similar en la mayoría de los lenguajes e implementaciones que he visto. Está diseñado para devolver una matriz modificada basada en el elemento de matriz de entrada (alto nivel que ignora la preferencia de tipo de compilación / tiempo de ejecución del lenguaje); un bucle está destinado a realizar más lógica.

Para recuperar objetos por ID / PK, dependiendo de si está usando SQL o no (parece sugerido), usaría un filtro para asegurarme de obtener una matriz de PK válidos, luego implosionar con una coma y colocarlo en una IN()cláusula SQL para devuelve el conjunto de resultados. Realiza una llamada en lugar de varias a través de SQL, optimizando un poco el call->waitciclo. Lo más importante es que mi código se leerá bien para alguien de cualquier idioma con un grado de competencia y no nos encontremos con problemas de mutabilidad.

<?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);

Si sabe lo que está haciendo, nunca tendrá problemas de mutabilidad (teniendo en cuenta que si tiene la intención de sobrescribir $arr, siempre podría $arr = array_mapser explícito.

MrMesees
fuente
2
Mucho más intuitivo que hacer un foreach: esto es exactamente para lo que está diseñada esta función.
benjaminhull