PHP foreach alterar os valores originais da matriz

143

Eu sou muito novo em matrizes multidimensionais, e isso está me incomodando bastante.

Minha matriz é a seguinte:

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

Então eu tenho uma função que verifica se essas entradas são preenchidas, se forem necessárias.

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

Agora meu problema é esta linha

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

Quero alterar o conteúdo da matriz original, pois estou retornando isso, mas como obtenho o nome da matriz atual (nomes neste exemplo) no meu loop foreach?

Jeppe
fonte
1
possível duplicata de PHP - Modificar objeto atual no loop foreach
PhoneixS
1
Não importa o quão nova você é (ou costumava ser) - isto é algo que você pode ler a documentação PHP: php.net/manual/en/control-structures.foreach.php
Nikolay Ivanov

Respostas:

261

No PHP, passar por reference ( &) é ... controverso. Eu recomendo não usá-lo, a menos que você saiba por que precisa e teste os resultados.

Eu recomendaria fazer o seguinte:

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

Então, basicamente, use $fieldquando você precisar dos valores e $fields[$key]quando precisar alterar os dados.

Vlad Preda
fonte
Bom, isso funciona! Tentei algo assim primeiro, mas acho que estraguei tudo em algum lugar :) Agora vou usar o seu exemplo mil vezes e nunca esquecer! :)
Jeppe
Ainda bem que ajudou. Além disso, eu recomendo a leitura do artigo I ligada, e também a documentação oficial para foreach ( php.net/manual/ro/control-structures.foreach.php )
Vlad Preda
4
Conclusão: se você deseja alterar a matriz / variável - deve usar uma referência. É mais rápido, mais limpo e mais legível.
Lulu
2
Estou curioso por que passar por referência em um foreachdeve ser controverso? Não é como se fosse uma chamada de função com efeitos colaterais ocultos ou algo assim.
UncaAlby
1
Obrigado por dizer que "passar por referência (&) é ... controverso", em vez de "não passar por referência" ou "passar por referência é mau". Menos probabilidade de iniciar uma guerra de chamas. :)
Sean the Bean
163

Use &:

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

&passa um valor da matriz como referência e não cria uma nova instância da variável. Portanto, se você alterar a referência, o valor original será alterado.

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

Editar 2018
Esta resposta parece ser favorecida por muitas pessoas na internet, e foi por isso que decidi adicionar mais informações e palavras de cautela.
Embora a passagem por referência em foreach(ou funções) seja uma solução limpa e curta, para muitos iniciantes, isso pode ser uma armadilha perigosa.

  1. Os loops no PHP não têm seu próprio escopo. - @Mark Amery

    Isso pode ser um problema sério quando as variáveis ​​estão sendo reutilizadas no mesmo escopo. Outra questão do SO ilustra bem por que isso pode ser um problema.

  2. Como o foreach depende do ponteiro interno do array no PHP 5, alterá-lo no loop pode levar a um comportamento inesperado. - documentos PHP para foreach

    A desativação de um registro ou a alteração do valor do hash (a chave) durante a iteração no mesmo loop pode levar a comportamentos potencialmente inesperados no PHP <7. O problema fica ainda mais complicado quando o próprio array é uma referência.

  3. Foreach performance.
    Em geral, o PHP prefere passar por valor devido ao recurso de copiar na gravação. Isso significa que internamente o PHP não criará dados duplicados, a menos que sua cópia precise ser alterada. É discutível se a passagem por referência foreachofereceria uma melhoria de desempenho. Como sempre é o caso, você precisa testar seu cenário específico e determinar qual opção usa menos memória e tempo de CPU. Para mais informações, consulte a publicação do SO vinculada abaixo pelo NikiC.

  4. Legibilidade do código.
    Criar referências em PHP é algo que rapidamente sai do controle. Se você é iniciante e não tem controle total do que está fazendo, é melhor ficar longe de referências. Para obter mais informações sobre o &operador, consulte este guia: Referência - O que esse símbolo significa no PHP?
    Para aqueles que querem aprender mais sobre esta parte da linguagem PHP : Referências sobre PHP explicadas

Uma explicação técnica muito boa do @NikiC sobre a lógica interna dos loops de foreach do PHP:
Como o 'foreach' do PHP realmente funciona?

Dharman
fonte
Além dos problemas listados, recomendo adicionar unset($value);após o foreachcolchete, para garantir que a variável por referência não esteja mais disponível após a iteração. 3v4l.org/2V2AQ
fyrye 09/07
15

Use foreach($fields as &$field){- para que você trabalhe com a matriz original.

Aqui está mais sobre a passagem por referência.

k102
fonte
Pls @RBA referem-se às respostas acima - eles têm muito mais detalhes e atualizações - Eu não usar php por um tempo agora, para conhecimento de quaisquer atualizações sobre este
K102
1
function checkForm(& $fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

Isto é o que eu sugeriria passar por referência

Sagar Kadam
fonte
Essa técnica é usada para alterar o valor da variável original. já que o PHP suporta a técnica Pass by Value. Nós precisamos adicionar o caractere '&' na frente de variável para estado que valor a ser passado por referência
Sagar Kadam
1
Então, por que ainda está voltando $fields?
MAZux 29/03/19
Esta é a pior resposta das três sugeridas. Para quem se deparar com esta resposta, não projete suas funções para alterar os dados no local e devolvê-los. Para o autor original: Você não forneceram qualquer explicação por esta solução seria melhor do que os outros, ou como ele funciona em todos ..
Dharman
-6

Tente isto

function checkForm($fields){
        foreach($fields as $field){
            if($field['required'] && strlen($_POST[$field['name']]) <= 0){
                $field['value'] = "Some error";
            }
        }
        return $field;
    }
Nirmal Ram
fonte
3
Não faça isso. Eu posso ver pelo menos duas coisas erradas no seu código: atribuir a $ field não funciona (a matriz $ fields nunca é modificada quando você faz isso) e retornar $ field retorna o campo singular, não a matriz.
precisa