PHP foreach cambia i valori dell'array originale


143

Sono molto nuovo negli array multidimensionali e questo mi sta facendo impazzire.

Il mio array è il seguente:

$fields = array(
    "names" => array(
         "type"         => "text",
         "class"        => "name",
         "name"         => "name",
         "text_before"  => "name",
         "value"        => "",
         "required"     => true,
    )
)

Poi ho ottenuto una funzione che controlla se questi ingressi sono riempiti, se sono richiesti.

function checkForm($fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

Ora il mio problema è questa linea

$fields[$field]['value'] = "Some error";

Voglio cambiare il contenuto dell'array originale, poiché sto restituendo questo, ma come posso ottenere il nome dell'array corrente (nomi in questo esempio) nel mio ciclo foreach?



1
Non importa quanto tu sia nuovo (o una volta) - questo è qualcosa che puoi leggere dalla documentazione di PHP: php.net/manual/en/control-structures.foreach.php
Nikolay Ivanov

Risposte:


261

In PHP, passare per riferimento ( &) è ... controverso. Consiglio di non usarlo a meno che tu non sappia perché ne hai bisogno e testare i risultati.

Consiglierei di fare quanto segue:

foreach ($fields as $key => $field) {
    if ($field['required'] && strlen($_POST[$field['name']]) <= 0) {
        $fields[$key]['value'] = "Some error";
    }
}

Quindi, in pratica, utilizzare $fieldquando sono necessari i valori e $fields[$key]quando è necessario modificare i dati.


Bene, questo funziona! Ho provato prima qualcosa del genere, ma immagino di aver rovinato un posto :) Ora userò il tuo esempio mille volte e non dimenticherò mai! :)
Jeppe,

Sono contento che abbia aiutato. Inoltre, raccomando di leggere l'articolo che ho collegato e anche la documentazione ufficiale per foreach ( php.net/manual/ro/control-structures.foreach.php )
Vlad Preda,

4
In conclusione: se hai intenzione di cambiare l'array / la variabile, allora dovresti usare un riferimento. È più veloce, più pulito e più leggibile.
Lulu,

2
Sono curioso di sapere perché passare per riferimento in a foreachdovrebbe essere controverso? Non è come se fosse una chiamata di funzione con effetti collaterali nascosti o altro.
UncaAlby,

1
Grazie per aver detto che "passare per riferimento (&) è ... controverso", piuttosto che "non passare per riferimento" o "passare per riferimento è male". Meno probabilità di iniziare una guerra di fiamma. :)
Sean the Bean,

163

Utilizzare &:

foreach($arr as &$value)
{
     $value = $newVal;
}

&passa un valore dell'array come riferimento e non crea una nuova istanza della variabile. Pertanto, se si modifica il riferimento, il valore originale cambierà.

http://php.net/manual/en/language.references.pass.php

Modifica 2018
Questa risposta sembra essere favorita da molte persone su Internet, motivo per cui ho deciso di aggiungere ulteriori informazioni e parole di cautela.
Mentre passare per riferimento in foreach(o funzioni) è una soluzione pulita e breve, per molti principianti potrebbe essere una trappola pericolosa.

  1. I loop in PHP non hanno il loro scopo. - @Mark Amery

    Questo potrebbe essere un problema serio quando le variabili vengono riutilizzate nello stesso ambito. Un'altra domanda SO illustra bene perché questo potrebbe essere un problema.

  2. Poiché foreach si basa sul puntatore di array interno in PHP 5, la modifica all'interno del ciclo può comportare comportamenti imprevisti. - Documenti PHP per foreach

    Disattivare un record o modificare il valore hash (la chiave) durante l'iterazione sullo stesso loop potrebbe portare a comportamenti potenzialmente inattesi in PHP <7. Il problema diventa ancora più complicato quando l'array stesso è un riferimento.

  3. Prestazioni di ogni livello.
    In generale PHP preferisce il passaggio per valore a causa della funzione di copia su scrittura. Significa che internamente PHP non creerà dati duplicati a meno che non sia necessario modificarne la copia. È discutibile se passare per riferimento foreachoffrirebbe un miglioramento delle prestazioni. Come sempre, è necessario testare lo scenario specifico e determinare quale opzione utilizza meno memoria e tempo della CPU. Per ulteriori informazioni, consultare il post SO collegato di seguito da NikiC.

  4. Leggibilità del codice.
    La creazione di riferimenti in PHP è qualcosa che sfugge rapidamente di mano. Se sei un principiante e non hai il pieno controllo di ciò che stai facendo, è meglio stare lontano dai riferimenti. Per ulteriori informazioni &sull'operatore, dai un'occhiata a questa guida: Riferimento - Cosa significa questo simbolo in PHP?
    Per coloro che vogliono saperne di più su questa parte del linguaggio PHP : Spiegazione dei riferimenti PHP

Una bella spiegazione tecnica di @NikiC della logica interna dei loop foreach di PHP:
come funziona realmente il "foreach" di PHP?


A parte i problemi elencati, ti consiglio di aggiungere unset($value);dopo la foreachparentesi quadra di chiusura, per garantire che la variabile per riferimento non sia più disponibile dopo l'iterazione. 3v4l.org/2V2AQ
fyrye

15

Usa foreach($fields as &$field){- così lavorerai con l'array originale.

Ecco di più sul passaggio per riferimento.


@RBA pls si riferisce alle risposte sopra - hanno molti più dettagli e aggiornamenti - Non uso php da un po 'di tempo, quindi ignaro di eventuali aggiornamenti su questo
k102

1
function checkForm(& $fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

Questo è ciò che vorrei suggerire passare per riferimento


Questa tecnica viene utilizzata per modificare il valore della variabile originale. poiché PHP supporta la tecnica Pass by Value. Dobbiamo aggiungere il carattere '&' davanti alla variabile per indicare quel valore che deve essere passato per riferimento
Sagar Kadam

1
Allora perché ancora tornare $fields?
MAZux,

Questa è la risposta peggiore delle 3 suggerite. Per chi si imbatte in questa risposta, non progettare le proprie funzioni per modificare i dati in atto e restituirli. Per l'autore originale: non hai fornito alcuna spiegazione del perché questa soluzione sarebbe migliore delle altre o di come funziona affatto.
Dharman,

-6

Prova questo

function checkForm($fields){
        foreach($fields as $field){
            if($field['required'] && strlen($_POST[$field['name']]) <= 0){
                $field['value'] = "Some error";
            }
        }
        return $field;
    }

3
Non farlo. Riesco a vedere almeno due cose sbagliate con il tuo codice: l'assegnazione a $ field non funziona (l'array $ fields non viene mai modificato quando lo fai), e return $ field restituisce il campo singolare, non l'array.
Staplerfahrer,
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.