PHP foreach cambia los valores de la matriz original

143

Soy muy nuevo en arreglos multidimensionales, y esto me está molestando a lo grande.

Mi matriz es la siguiente:

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

Luego obtuve una función que verifica si estas entradas están llenas, si son necesarias.

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

Ahora mi problema es esta línea

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

Quiero cambiar el contenido de la matriz original, ya que estoy devolviendo esto, pero ¿cómo obtengo el nombre de la matriz actual (nombres en este ejemplo) en mi bucle foreach?

Jeppe
fuente
1
posible duplicado de PHP - Modificar objeto actual en bucle foreach
PhoneixS
1
No importa lo nuevo que sea (o lo que solía ser): esto es algo que puede leer de la documentación de PHP: php.net/manual/en/control-structures.foreach.php
Nikolay Ivanov

Respuestas:

261

En PHP, pasar por referencia ( &) es ... controvertido. Recomiendo no usarlo a menos que sepa por qué lo necesita y pruebe los resultados.

Yo recomendaría hacer lo siguiente:

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

Básicamente, utilícelo $fieldcuando necesite los valores y $fields[$key]cuando necesite cambiar los datos.

Vlad Preda
fuente
Bien, esto funciona! Intenté algo como esto primero, pero supongo que lo arruiné en algún lugar :) ¡Ahora usaré tu ejemplo mil veces y nunca lo olvidaré! :)
Jeppe
Me alegro de que haya ayudado. Además, recomiendo leer el artículo que vinculé , y también la documentación oficial de foreach ( php.net/manual/ro/control-structures.foreach.php )
Vlad Preda
44
En pocas palabras: si va a cambiar la matriz / variable, entonces debe usar una referencia. Es más rápido, más limpio y más legible.
Lulu
2
Tengo curiosidad por qué pasar por referencia en un foreachdebería ser controvertido? No es como si fuera una llamada de función con efectos secundarios ocultos ni nada.
UncaAlby
1
Gracias por decir que "pasar por referencia (&) es ... controvertido", en lugar de "no pasar por referencia" o "pasar por referencia es malo". Es menos probable que comience una guerra de llamas. :)
Sean the Bean
163

Uso &:

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

&pasa un valor de la matriz como referencia y no crea una nueva instancia de la variable. Por lo tanto, si cambia la referencia, el valor original cambiará.

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

Editar 2018
Esta respuesta parece ser favorecida por muchas personas en Internet, por eso decidí agregar más información y palabras de precaución.
Si bien el paso por referencia en foreach(o funciones) es una solución limpia y corta, para muchos principiantes esto podría ser una trampa peligrosa.

  1. Los bucles en PHP no tienen su propio alcance. - @Mark Amery

    Esto podría ser un problema grave cuando las variables se están reutilizando en el mismo ámbito. Otra pregunta SO ilustra muy bien por qué eso podría ser un problema.

  2. Como foreach se basa en el puntero de matriz interno en PHP 5, cambiarlo dentro del ciclo puede conducir a un comportamiento inesperado. - Documentos PHP para foreach

    Desarmar un registro o cambiar el valor hash (la clave) durante la iteración en el mismo bucle podría conducir a comportamientos potencialmente inesperados en PHP <7. El problema se complica aún más cuando la matriz en sí misma es una referencia.

  3. Foreach rendimiento.
    En general, PHP prefiere pasar por valor debido a la función de copia en escritura. Significa que PHP internamente no creará datos duplicados a menos que la copia de los mismos necesite ser cambiada. Es discutible si pasar por referencia en foreachofrecería una mejora en el rendimiento. Como siempre es el caso, debe probar su escenario específico y determinar qué opción usa menos memoria y tiempo de CPU. Para obtener más información, consulte la publicación SO vinculada a continuación por NikiC.

  4. Legibilidad de código.
    Crear referencias en PHP es algo que rápidamente se sale de control. Si es un novato y no tiene control total de lo que está haciendo, es mejor mantenerse alejado de las referencias. Para obtener más información sobre el &operador, consulte esta guía: Referencia: ¿Qué significa este símbolo en PHP?
    Para aquellos que quieran aprender más sobre esta parte del lenguaje PHP : Referencias PHP explicadas

Una explicación técnica muy agradable por @NikiC de la lógica interna de los bucles foreach de PHP:
¿Cómo funciona realmente el 'foreach' de PHP?

Dharman
fuente
Además de los problemas enumerados, recomiendo agregar unset($value);después del foreachcorchete de cierre, para garantizar que la variable de referencia ya no esté disponible después de la iteración. 3v4l.org/2V2AQ
fyrye
15

Uso foreach($fields as &$field){: para trabajar con la matriz original.

Aquí hay más sobre pasar por referencia.

k102
fuente
@RBA por favor consulte las respuestas anteriores - tienen muchos más detalles y actualizaciones - No he usado php por un tiempo, así que no
estoy al
1
function checkForm(& $fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

Esto es lo que sugeriría pasar por referencia

Sagar Kadam
fuente
Esta técnica se usa para cambiar el valor de la variable original. ya que PHP admite la técnica Pass by Value. Necesitamos agregar el carácter '&' delante de la variable para indicar el valor que se pasará por referencia
Sagar Kadam
1
Entonces, ¿por qué sigues volviendo $fields?
MAZux
Esta es la peor respuesta de las 3 sugeridas. Para quien tropiece con esta respuesta, no diseñe sus funciones para cambiar los datos en su lugar y devolverlos. Para el autor original: No ha proporcionado ninguna explicación de por qué esta solución sería mejor que las otras, o cómo funciona en absoluto ...
Dharman
-6

Prueba esto

function checkForm($fields){
        foreach($fields as $field){
            if($field['required'] && strlen($_POST[$field['name']]) <= 0){
                $field['value'] = "Some error";
            }
        }
        return $field;
    }
Ram Nirmal
fuente
3
No hagas esto. Puedo ver al menos dos cosas mal con su código: la asignación a $ field no funciona (la matriz $ fields nunca se modifica cuando hace esto), y return $ field devuelve el campo singular, no la matriz.
Staplerfahrer