Ver Mensaje Individual
  #4 (permalink)  
Antiguo 12/08/2014, 13:12
Avatar de NSD
NSD
Colaborador
 
Fecha de Ingreso: mayo-2012
Ubicación: Somewhere
Mensajes: 1.332
Antigüedad: 12 años
Puntos: 320
Respuesta: Extraño comportamiento de foreach

Gracias a ambos por las respuestas.

@triby estube revisando el manual y haciendo unas pruebas sobre los destructores, pero no hay mucho mas en su comportamiento de lo que menciona @hhs, se invocan cuando el objeto deja de ser necesario (al final del script, cuando se llama a unset, cuando se le asigna un valor o cuando ya no se lo referencia mas)

@hhs interesante el analisis pero tengo una duda con esta parte de tu razonamiento:
Cita:
$test (es global ) que ya no contiene el objeto si no 1 en la primera iteración por eso al final el ultimo var_dump tiene el valor de 5.
Eso no es tan asi (o no me doy cuenta al menos, espero me tengas paciencia), considera el siguiente ejemplo similar al primero:

Código PHP:
Ver original
  1. <?php
  2.     error_reporting(E_ALL);
  3.    
  4.     class A implements Iterator
  5.     {
  6.         private $datos = [1, 2, 3, 4, 5];
  7.  
  8.         public function rewind() { reset($this->datos); }
  9.         public function current() { return current($this->datos); }
  10.         public function key() { return key($this->datos); }
  11.         public function next() { return next($this->datos); }
  12.         public function valid() { return (key($this->datos) !== NULL && key($this->datos) !== FALSE); }
  13.         public function __destruct()
  14.         {
  15.             echo("destruido");
  16.         }
  17.     }
  18.  
  19.     $test = new A();
  20.     foreach($test as $test)
  21.     {    
  22.         var_dump($test);
  23.     }
  24.     var_dump($test);

La salida que produce es:
Cita:
int 1
int 2
int 3
int 4
int 5
destruido
int 5
Por lo tanto, la variable $test cambia su valor dentro del foreach, pero el objeto sigue "vivo" ya que se esta haciendo uso de sus metodos, solo es destruido al finalizar el foreach.

Pero este este script en cambio:
Código PHP:
Ver original
  1. class A implements IteratorAggregate
  2.     {
  3.         private $datos = [1, 2, 3, 4, 5];
  4.  
  5.         public function getIterator() { return new ArrayIterator($this->datos); }
  6.         public function __destruct()
  7.         {
  8.             echo("destruido");
  9.         }
  10.     }
  11.  
  12.     $test = new A();
  13.     foreach($test as $test)
  14.     {    
  15.         var_dump($test);
  16.     }
  17.     var_dump($test);

produce la salida:
Cita:
destruido
int 1
int 2
int 3
int 4
int 5
int 5
exactamente la misma que si iterara la propiedad publica directamente (lo cual es coherente).

Cita:
Para solucionar el extraño "comportamiento" usa otro nombre de variable.
Si, por supuesto, por error escribi el mismo nombre en ambas partes, el script funciono durante mucho tiempo asi, pero aller tube que actualizarlo y al verlo me llamo la atencion porque a priori supuse que eso no funcionaria.
Quiero entender que es lo que esta ocurriendo mas alla de que la solucion sea cambiar el nombre, porque dependiendo de cual sea el comportamiento puede ser (por ejemplo) una buena forma de optimizar la carga de un listado ya que php iria liberando la memoria a medida que produce la salida en vez de mantenerla ocupada hasta terminar de mostrar todo.

Seria interesante combinar esto con los generadores de alguna forma...
__________________
Maratón de desafíos PHP Junio - Agosto 2015 en FDW | Reglamento - Desafios