PHP - Modifica l'oggetto corrente nel ciclo foreach


111

Mi chiedevo se sia possibile modificare l'oggetto corrente che viene gestito all'interno di un foreachciclo

Sto lavorando con una serie di oggetti $questionse desidero esaminare e cercare le risposte associate a quell'oggetto domanda nel mio database. Quindi, per ogni domanda, vai a prendere gli oggetti risposta e aggiorna la corrente $question all'interno del mio foreachciclo in modo da poter produrre / elaborare altrove.

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

Come hanno suggerito sia ArtjomKurapov che @topener, stavo cercando "passa per riferimento" usando il segno &. Grazie ragazzi :) buona giornata
Garbit

Risposte:


207

Ci sono 2 modi per farlo

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

In questo modo salvi la chiave, in modo da poterla aggiornare nuovamente nella $questionsvariabile principale

o

foreach($questions as &$question){

L'aggiunta di &manterrà $questionsaggiornato. Ma direi che il primo è consigliato anche se è più breve (vedi commento di Paystey)

Secondo la foreachdocumentazione PHP :

Per poter modificare direttamente gli elementi dell'array all'interno del ciclo, anteponi $ value con &. In tal caso il valore verrà assegnato per riferimento.


32
I riferimenti in non foreachsono davvero raccomandati, il modo in cui il foreachpassaggio intorno alla parte del valore del ciclo risulta in un comportamento imprevedibile. Potrebbe essere più lungo ma sei molto più sicuro usando il metodo 1 qui.
Paystey

1
Ho appena trascorso un'ora perplessa a eseguire il debug di un problema causato dall'utilizzo di un riferimento in un foreach. Ho riutilizzato lo stesso nome di variabile per una seconda chiamata foreach: poiché avevo passato il primo per riferimento, continuava a modificare l'ultimo elemento dell'array! L'uso di un indice esplicito non avrebbe avuto questo problema.
Hippyjim

7
@Paystey puoi citare le tue fonti o fornire una spiegazione dettagliata?
Nico

2
Perché la manipolazione dei riferimenti non sarebbe sicura? Il C / C ++ in cui devi manipolare i riferimenti ovunque non è sicuro? Sta a te renderlo sicuro o meno, non la lingua.
Kalzem

2
@BabyAzerty: Paystey non ha detto riferimenti "in generale", ma in foreach, per quanto riguarda l'orrore come questo: stackoverflow.com/questions/3307409/... (@Nico, FYI, anche.)
Sz.

6

Sicuramente usare array_mape se usare un contenitore che implementa ArrayAccessper derivare oggetti è solo un modo semantico più intelligente per farlo?

La semantica della mappa degli array è simile nella maggior parte dei linguaggi e delle implementazioni che ho visto. È progettato per restituire un array modificato in base all'elemento dell'array di input (alto livello che ignora la preferenza del tipo di compilazione / runtime del linguaggio); un ciclo ha lo scopo di eseguire più logica.

Per il recupero di oggetti tramite ID / PK, a seconda che si utilizzi SQL o meno (sembra suggerito), utilizzerei un filtro per assicurarmi di ottenere un array di PK validi, quindi implodere con virgola e posizionarlo in una IN()clausola SQL per restituisce il set di risultati. Effettua una chiamata invece di più tramite SQL, ottimizzando un po 'il call->waitciclo. La cosa più importante è che il mio codice leggerebbe bene a qualcuno di qualsiasi lingua con un certo grado di competenza e non incontriamo problemi di mutabilità.

<?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 sai quello che stai facendo non avrai mai problemi di mutabilità (tenendo presente che se intendi sovrascriverlo $arrpotresti sempre $arr = array_maped essere esplicito.


2
Molto più intuitivo che eseguire un foreach: questo è esattamente ciò per cui è progettata questa funzione.
Benjaminhull
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.