Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Eu estava querendo entender por que toda vez que dava um print_r() na variável $GLOBALS aparecia um trecho que tinha "RECURSION".
Daí fui testando pra ver se conseguiria reproduzir algo semelhante, e saiu isso aqui:
$G = array(1,2,3);
$G[] =& $G;
print_r($G);
/**
imprime:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => Array- Alguém sabe explicar o que seria esse RECURSION?
E também tenho outra dúvida.
Quando vamos percorrer esse mesmo array, dá pau:
array_walk_recursive($G, function(&$val, $key){
var_dump($val);
});
//Warning: array_walk_recursive(): recursion detected on line 13
foreach($G as $G){
var_dump($G);
}
//Invalid argument supplied for foreach() in ...
isso também (a parada do foreach ) eu também queria entender, pois já vi alguns códigos em tutoriais em que a variável que recebe o valor a cada iteração com o array (como no caso 2 do meu exemplo) é a mesma variável do array. No caso, $G e $G.
- O que o php faz com essa variável ali?
- Se tentássemos fazer algo no While, daria um NOTICE falando que o array não existe( ou seja, no while o valor é substituído imediatamente), por que no foreach é só depois do último elemento do array que a variável vira o último elemento (e não na primeira iteração como o while)?
Mas e nesse caso?
$a = array('um', 'dois', 'três', 'um', 'passito', 'pra', 'frente', 'Maria'); foreach($a as $a) { echo $a . PHP_EOL; } // imprime: um dois três um passito pra frente Maria
Porque, nesse caso, o loop rola normalmente, e o variável $a não recebe atribuição de valor (mas continua como array) até o final do loop.
Você precisa entender a diferença entre atribuição e referência. É mais fácil entender se você conhecer sobre alocação em memória.
Basicamente, atribuição é a cópia do valor de uma determinada posição da memória para o outra (posição). Já a referência, ao invés de copiar o valor, é feito uma referência para a outra posição em memória, é o que acontece com a atribuição de objetos.
Vamos supor que o indentificador (simplificado) de alocação de memória do array seja #1, logo:
#1 -> array(1 , 2 , 3);
#1 é a posição da memória que possui o valor array (1 , 2 , 3).
Agora iremos atribuir o array nele mesmo, com o seguinte código:
$array = array(1 , 2 , 3);
$array[] = $array;
O resultado final é o seguinte:
#1 -> array(1 , 2 , 3 , array(1 , 2 , 3));
Perceba que o array foi inserido (copiado) nele mesmo.
Agora veja com a referência:
$array = array(1 , 2 , 3);
$array[] =& $array;
A alocação na memória seria similar a esta:
#1 -> array(1 , 2 , 3 , #1);
Perceba que o valor não foi mais copiado, apenas adicionado uma referência a alocação de memória. Com isso, toda vez que chegar no quarto elemento (número de chave 3, referência para #1) ele irá repetir todo o array, isso é um loop causado pela referência.
Explicações mais detalhadas você pode encontrar no manual:
References Explained
na verdade eu entendo perfeitamente como as referências funcionam. E entendi a sua primeira explicação de que isso deve ser barrado, ou, do contrário, geraria um loop infinito.
O que eu não entendo é por que podemos colocar a mesma variável no foreach (tanto o array quando o value),sendo que ela continua "sendo" o array mesmo passando pelo loop (diferente do while). Talvez eu tenha confundido porque quis tratar dos dois assuntos no mesmo post :coolio: .
exemplo:
foreach($array as $array){
echo $array; // imprime o valor atual, mas ele não é passado para o $array antes do "as"
}
echo $array; // agora não é mais o array, ele esperou acabar tudo e atribuiu o valor aqui
no foreach ele "espera" até o final da iteração e, só então, atribuí o último valor do array ao $array (não sendo mais um array, e sim o último elemento).
no while não é assim não! eu já testei.
$array = array(1,2,3,4);
while($array = current($array)){
echo $array;
next($array);
}
// isso gera um Warning dizendo que next espera um array e não uma string, depois da primeira iteração.
como o foreach consegue fazer isso?
$array = array(1,2,3,4);
foreach($array as $array){
echo $array;
unset($array); // o unset é indiferente nesse caso!!!
}
Mas aí vem a questão: o $array é a mesma variável! E não é uma referência, pois existe o foreach que passa o "value" por referência, e não é esse caso.
$array = array(1,2,3,4);
foreach($array as &$val){
$val = "|$val|";
}
print_r($array); // imprime os array, porém seus elementos ganharam o delimitador | |
E agora? confudi?
Dever uma particularidade do foreach em utilizar os valores da variável, e não sua referência, e, após o término da iteração, registrar as variáveis.
foreach é açucar sintático e possui a sua atribuição implícita. Já while tem sua atribuição explícita [inline]$array = current($array)[/inline].
Valeu, Gabriel! Obrigado pela paciência.
Por este trecho:
Você está referenciando um array nele mesmo, isso é considerado um loop de referências, o que também pode ser caracterizado, no seu caso, como recursividade (do tipo ruim). Todas as funções que você utiliza indentifica essa repetição e para o processamento. O outro resultado, seria travar sua aplicação, pois a impressão nunca terminaria e estaria percorrendo o array(array_walk_recursive) infinitamente.