Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] Iterador se rebobina [Ggrrr]

Estas en el tema de Iterador se rebobina [Ggrrr] en el foro de PHP en Foros del Web. Hola, Tengo un problema implementando la interface Iterator y es que en una funcion de busqueda quiero que el cursor siga hacia adelante para buscar ...
  #1 (permalink)  
Antiguo 29/06/2013, 21:45
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Iterador se rebobina [Ggrrr]

Hola,

Tengo un problema implementando la interface Iterator y es que en una funcion de busqueda quiero que el cursor siga hacia adelante para buscar la siguiente ocurrencia si repito la busqueda pero eso no pasa!!! se rebobina ...

Código PHP:
Class TagSequence implements Iterator
{
    private 
$_tags = array();
...
...

public function 
find(tag $search){         
        while (
$this->valid()){
            
$current_tag $this->current();
            if (
$current_tag->compareTo($search)>=0){
                return 
true;                
            } 
            
$this->next();            
        }  
        return 
false;
    }

     
/* implemento interface Iterator:  */

    // a pesar de estar anulada, sigue rebobinandose
    
public function rewind()
    {        
        
//reset($this->_tags );
    
}

...
... 
He intentado anulando rewind() pero no hay caso.......todo lo demas funciona perfecto desde un comienzo y esto no quiere funcionar

Idea por que ? detesto los parches. Por favor
__________________
Salu2!

Última edición por Italico76; 29/06/2013 a las 22:22
  #2 (permalink)  
Antiguo 30/06/2013, 01:10
Avatar de repara2  
Fecha de Ingreso: septiembre-2010
Ubicación: München
Mensajes: 2.445
Antigüedad: 13 años, 7 meses
Puntos: 331
Respuesta: Iterador se rebobina [Ggrrr]

La llamada a rewind() se hace automaticamente después de un loop foreach, de manera que el puntero siempre vuelve al inicio, es un comportamiendo de PHP. En el caso de while(), tal como lo usas tú, no he podido encontrar documentación, pero no sería raro que funcione igual. Salu2
__________________
Fere libenter homines, id quod volunt, credunt.
  #3 (permalink)  
Antiguo 30/06/2013, 06:25
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 3 meses
Puntos: 845
Respuesta: Iterador se rebobina [Ggrrr]

Como lo has comprobado ?, porque el rewind no debería ocurrir hasta que no se llegue al último elemento del iterator y tal cual lo tienes ahora no creo que funcione correctamente, si buscas dos veces el mismo tag entiendo que retornaría true en ambos casos pero no porque se repita el tag sino porque no has movido el puntero y este apunta a la ocurrencia anterior, o talves estas llamando a next en el loop "externo" ?.

Postea la implementación completa y un test.

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #4 (permalink)  
Antiguo 30/06/2013, 08:41
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Iterador se rebobina [Ggrrr]

Cita:
Iniciado por repara2 Ver Mensaje
La llamada a rewind() se hace automaticamente después de un loop foreach, de manera que el puntero siempre vuelve al inicio, es un comportamiendo de PHP. En el caso de while(), tal como lo usas tú, no he podido encontrar documentación, pero no sería raro que funcione igual. Salu2
Listo... he SOLUCIONADO...... puedo decir que tienes razon, el FOREACH sobre la interfaz Iterador rebobina pero el WHILE no lo hace (!)

Sino hubiera hecho pruebas unitarias jamas hubiera logrado debugger esto bien..... hay que usarlas!
__________________
Salu2!

Última edición por Italico76; 30/06/2013 a las 22:33 Razón: SOLUCIONADO
  #5 (permalink)  
Antiguo 01/07/2013, 00:54
Avatar de repara2  
Fecha de Ingreso: septiembre-2010
Ubicación: München
Mensajes: 2.445
Antigüedad: 13 años, 7 meses
Puntos: 331
Respuesta: Iterador se rebobina [Ggrrr]

ok, pero entonces cuál era el problema? Puedes postear la solución?
__________________
Fere libenter homines, id quod volunt, credunt.
  #6 (permalink)  
Antiguo 01/07/2013, 03:02
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Iterador se rebobina [Ggrrr]

Cita:
Iniciado por repara2 Ver Mensaje
ok, pero entonces cuál era el problema? Puedes postear la solución?
Revisando el codigo... de pronto si rebobina el while() tambien jeje ...en fin...

Código PHP:
<?php
namespace FastyPatterns


interface 
IComparable
{
   
/**
    * Hace comparacion como
    * su homologa en C#    
    * 
    * @return int {-1,0,1}
    */
   
public function compareTo($other);

   public function 
getDiff();
}

abstract class 
Comparable implements IComparable
{
    protected 
$_diff = array();

    
/**
     * Devuelve diferencias
     *      
     * @return array
     */
    
public function getDiff ()
    {
      return 
$this->_diff;    
    } 

}

/**
 * Tag: 
 *      almacena un tag con todas sus propiedades
 */
Class Tag extends Comparable
{
    private 
$_element_name null;  // input-text, input-radio,...etc
    
private $_prop = array();

    public function 
__construct($element){
        
$this->_element_name $element;
        return 
$this;
    }      

    public function 
getElementName(){
        return  
$this->_element_name;
    }
 
    
// (objeto)->propiedad = valor   (no es encadenable)
    
public function __set($p,$val)
    {          
        
$this->_prop[$p]= $val;            
    }
  
    public function 
__get($p)
    {  
        return 
$this->_prop[$p];

    } 
// end class

   
    // (objeto)->set_propiedad(valor)   (si es encadenable)
    
public function __call($name$arguments) {

        
// setting a property
        
if (substr($name,0,4) == 'set_') {

            
// get the property name we want to set
            
$property substr($name,4);
            
// assign the value that was passed to this method
            // to the class property
            
$this->_prop[$property] = $arguments[0]; 
            
//var_dump($this->_prop);

        // adding to an array property
        
} else if (substr($name,0,4) == 'add_') {

            
// get the property name we want to add to
            
$property substr($name,4);
            
// add the value
            
array_push($this->_prop[$property], $arguments[0]);

        }

        
// for method chaining
        
return $this;
    }

    public function 
getAllFormated(){
        
$out "Tag: {$this->_element_name} <br/>";
        foreach (
$this->_prop as $prop => $val){
            
$out .= "[$prop] => $val <br/>";
        }
        return 
$out.'<p/>';
    }

    public function 
__ToString()
    {
        return 
$this->getAllFormated();
    }

    
// es revelar el estado interno, pero es lo mas facil
    
public function getProperties(){
        return 
$this->_prop;
    }
   
     
    
/**
    * Compara Tags: variacion de metodo de C# 
    *
    * @return {-1 ,0 , 1} 
    *
    * si el tipo de elemento es distinto, retorna -1    
    * si son iguales, retorna 0
    * si el primero tiene algo de sobra, retorna 1
    */
    
public function compareTo ($tag2)
    {
    
        
$class __CLASS__;
        if (!(
$tag2 instanceof $class))
            throw new 
Exception ('Debe ser del mismo tipo a comparar'); 

        
$this->_diff null;
        

        
// seguro distintos tags y ya
        
if (strtolower($this->getElementName()) != strtolower($tag2->getElementName()))
            return -
1;  

        
$p1 $this->getProperties();
        
$p2 $tag2->getProperties();     

        
// seguro son iguales en todo
        
if ($p1 == $p2)
            return 
0;    

        
// sera que hay en tag2 elementos que no estan en este ?
        
$this->_diff array_diff_assoc ($p2,$p1);
        if (
count($this->_diff)!=0)
            return -
1;

        
// sera que hay en este tag elementos que no estan en tag2 ?
        
$this->_diff array_diff_assoc ($p1,$p2);
        if (
count($this->_diff)!=0)
            return 
1;

        throw new 
Exception ('Fallo al capturar diferencia de tags'); 
    }

// end class



/**
 *   TagSequence:
 *                almacena una secuencia de tags  
 */
Class TagSequence implements Iterator
{
    private 
$_name null;
    private 
$_tags = array();
    private 
$_optionals = array();

    private 
$_last_search =null;
    private 
$_search_cursor =null;


    public function 
__construct($name=null){
        
$this->_name $name;
        return 
$this;
    }      

    public function 
setName($input)
    {
        
$this->_name=$input;
        return 
$this;
    }

    public function 
getName()
    {
        return 
$this->_name;
    }
 
    public function 
addTag (tag $tag $optional=null){
        
$this->_tags[]=$tag;              
        
$this->_optionals[]=$optional;      
        return 
$this;
    }

    
// devuelve si el tag actual en la secuencia esta marcado como opcional o no 
    
public function is_optional(){
        return 
$this->_optionals[$this->key()];
    }  

    public function 
__ToString ()
    {
        
$out '<i><b>Secuence:</b> '.$this->_name.'</i><p/>';
        foreach (
$this->_tags as $tag){
            
$out .= $tag->getAllFormated();
        }
        return 
$out.'<p/>';
    }

    
/* Find:  mueve el cursor hasta la primera ocurrencia o hasta el final sino se encuentra devuelve bool
    *  
    *  El cursor queda sobre el elemento seleccionado o en NULL si llega al final sin encontrarlo
    *  Permite buscar varias ocurrencias si se repite la busqueda
    */
    
public function find(tag $search,$continue=true){     
        if (
$continue and $search==$this->_last_search)
        {           
           while (
$this->valid() and $this->key()<=$this->_search_cursor){
               
$this->next();
           }           
        }
           
        
$this->_last_search $search;  

        while (
$this->valid()){
            
$current_tag $this->current();
            
$this->_search_cursor $this->key();  

            if (
$current_tag->compareTo($search)>=0){
                return 
true;                
            } 
            
$this->next(); 
                      
        }  
        return 
false;
    }



    
/**
     * findFirst : busca la primera ocurrencia
     * 
     * a) Es mas eficiente
     * b) Siempre busca *desde el comienzo* 
     * c) el cursor queda 'pasado' en 1 o o en NULL si llega al final sin encontrarlo 
     *
     * @param tag 
     * @return bool
     */
    
public function findFirst(tag $search){     

        
$ret false;

        foreach (
$this->_tags as $key=> $current_tag)
        {
            if (
$current_tag->compareTo($search)>=0){
                
$ret True;                                    
                break;
            }             
        }          
        
        return 
$ret;      

    }



    
/* Implemento interface Iterator  */

    
public function rewind()
    {        
        
reset($this->_tags );
    }

    public function 
current()
    {
        
$tag current($this->_tags);        
        return 
$tag;
    }

    public function 
next()
    {
        
$tag next($this->_tags );        
        return 
$tag;
    }
  
    public function 
key()
    {
        
$tag_key key($this->_tags ); 
        return 
$tag_key;
    }
  
    public function 
valid()
    {
        
$key key($this->_tags );
        
$tag = ($key !== NULL && $key !== FALSE);        
        return 
$tag;
    }


// end class
Las pruebas no me entraron.......exceden los 10.000 caracteres

No me pegues, despues de tanta vuelta olvide que fue lo que hice aunque creo que el funcionamiento ya se puede asegurar
__________________
Salu2!
  #7 (permalink)  
Antiguo 01/07/2013, 03:05
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Iterador se rebobina [Ggrrr]

Ya veo me vale expulsion por "Suma de mensajes" pero aclaro SUPERABA los 10.000 caracteres

Código PHP:
<?php
namespace FastyPatterns

require(
'patterns.php');
require_once 
'PHPUnit/Autoload.php'// PHPUnit

/**
 * Fasty project
 * 
 * Pruebas unitarias
 */

class tagSequenceTest extends PHPUnit_Framework_TestCase
{
    private 
$seq =null;

    private function 
loadSeq(){
        
$this->seq = (new TagSequence())
        ->
addTag((new Tag('select'))->set_Name('Paises'))
        ->
addTag((new Tag('option'))->set_Id('Uno'))    
        ->
addTag((new Tag('a'))->set_href('www.google.com')) 
        ->
addTag((new Tag('option'))->set_Id('Dos'))
        ->
addTag((new Tag('li')))
        ->
addTag((new Tag('li')))
        ->
addTag((new Tag('img')));
    }
    
    
/*
       Pruebo los metodos de busqueda first() y firstFirst()
    */
    
public function testIfCursorIsMovedAsExpected(){  
        
        
$this->loadSeq();   
        
$option = new Tag('option');
     
        
///// FIND METHOD  ///////////
        
$find_method='find';
  
        
$cursor0$this->seq->key();        
        
$f0 $this->seq->$find_method($option);
        
$cursor1$this->seq->key();        
        
        
$f1 =$this->seq->$find_method($option);
        
$cursor2$this->seq->key();
        
        
$f2 =$this->seq->$find_method($option,false);
        
$cursor3$this->seq->key();

        
$this->seq->rewind(); 
        
$f3 =$this->seq->$find_method(new Tag('a'));
        
$cursor4$this->seq->key();
     
        
$this->seq->rewind(); 
        
$f4 =$this->seq->$find_method((new Tag('select')));
        
$cursor5$this->seq->key();
        
        
$f5 =$this->seq->$find_method((new Tag('tag_inexistente')));
        
$cursor6$this->seq->key();

        
$this->AssertTrue($f0);
        
$this->AssertTrue($f1);
        
$this->AssertTrue($f2);
        
$this->AssertTrue($f3);
        
$this->AssertTrue($f4);
        
$this->AssertFalse($f5);


        
$this->AssertEquals(0,$cursor0); // antes de buscar
        
$this->AssertEquals(1,$cursor1); 
        
$this->AssertEquals(3,$cursor2); 
        
$this->AssertEquals(3,$cursor3); // busca desde el comienzo
        
$this->AssertEquals(2,$cursor4);
        
$this->AssertEquals(0,$cursor5);
        
$this->AssertEquals(NULL,$cursor6);

        
///// FIND FIRST METHOD  ///////////
        
$find_method='findFirst';

        
$this->seq->rewind();  
        
$cursor0$this->seq->key();        

        
$f0 $this->seq->$find_method($option);
        
$cursor1$this->seq->key();        
        
        
$f1 =$this->seq->$find_method($option);
        
$cursor2$this->seq->key();  
        
///
        ///
        
$f3 =$this->seq->$find_method(new Tag('a'));
        
$cursor4$this->seq->key();
             
        
$f4 =$this->seq->$find_method((new Tag('select')));
        
$cursor5$this->seq->key();
        
        
$this->AssertTrue($f0);
        
$this->AssertTrue($f1);
        
/// 
        
$this->AssertTrue($f3);
        
$this->AssertTrue($f4);
        
$this->AssertFalse($f5);


        
/* Ojo: el cursor queda 'pasado' en 1 o al final en NULL y es correcto! */
      
        
$this->AssertEquals(0,$cursor0); 
        
$this->AssertEquals(2,$cursor1); 
        
$this->AssertEquals(2,$cursor2); 
        
///
        
$this->AssertEquals(3,$cursor4); 
        
$this->AssertEquals(1,$cursor5); 
        
$this->AssertEquals(NULL,$cursor6); 
           
    }
}
Decia que el WHILE no rebobina porque tiene un parche al comienzo...olvide que lo habia puesto......y al FOREACH no encontre como ponerle el parche asi que por esa razon termino siendo un "findFirst()" ya que justamente rebobina y nada que hacer, siempre comienza del primer elemento...... lo unico que finalmente me funciono fue implementar un noRewindIterator()

Código PHP:
 /* desde ejecutada.. no deberian poder agregarse tags */
    
public function freeze(){

        
$it = new ArrayIterator($this->_tags); 
        
$this->_noRewindIterator = new NoRewindIterator($it);     
    }

    public function 
findNoRewind(tag $search){     

        
$ret false;               
        foreach (
$this->_noRewindIterator as $key=> $current_tag)
        {            
            if (
$current_tag->compareTo($search)>=0){
                
$ret True;                                    
                break;
            }             
        }          
        
        return 
$ret;     

    } 
__________________
Salu2!

Última edición por Italico76; 01/07/2013 a las 05:07

Etiquetas: iterator, phpunit, poo
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:20.