Foros del Web » Programando para Internet » PHP »

Nuevos tipos de datos: Struct de C y Range

Estas en el tema de Nuevos tipos de datos: Struct de C y Range en el foro de PHP en Foros del Web. Buenas, Hay tipos de datos que en alguna circunstancia he necesitado demasiado y aqui les dejo la implementacion: TIPO STRUCT (sacado de lenguaje C) La ...
  #1 (permalink)  
Antiguo 28/05/2014, 12:47
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 7 meses
Puntos: 292
Nuevos tipos de datos: Struct de C y Range

Buenas,

Hay tipos de datos que en alguna circunstancia he necesitado demasiado y aqui les dejo la implementacion:


TIPO STRUCT (sacado de lenguaje C)

La idea es tener una estructura rigida que no permita creas indices por error como en el caso de un array o propiedades publicas en el caso de una clase solo por error

Se usaria asi:

Código PHP:
// creo la estructura
$st_per = (new Struct('persona'));
$st_per    ->create('nombre','str','NN')
        ->
create('apellido','str')
        ->
create('edad','int')
        ->
create('sexo_masc','bool',true)
        ->
create('hijos','bool',false)
        ->
create('fecha_aniversario','object',null)
        ->
create('telefonos','array');        

        
// creo tantos registros como necesito
$per1 = clone $st_per;        
$per2 = clone $st_per;        
        
            
// la uso :)
$per1->nombre  'Pablo';    
$per1->apellido  'Bozzolo';    
$per1->edad 32;
$per1->fecha_aniversario = (new Datetime)->setDate (1980,1,10);
$per1->telefonos=array('301 203 4445','300 434 5564');
#$per1->sexo_masc = 'h';  // Excepcion 
#$per1->direccion = 'en mi casa'; // Excepcion

$per2->nombre  'Maria';    
$per2->apellido  'Mosconi';    
$per2->edad 19;
$per2->fecha_aniversario = (new Datetime)->setDate (2006,2,23);
$per2->telefonos=array('600 455 554');
$per2->sexo_masc false;  
$per2->hijos true

Y la Clase que lo implementa es:

Código PHP:

/*
    Struct as in C
    @author: Pablo Bozzolo

    struct database {
        int id_number;
        int age;
        float salary;
    };
*/
Class Struct
{
    private 
$_field = array();
    private 
$_type  = array();
    private 
$_name null;
    
    private 
$_tipos_ = array ("boolean","integer","double","string","array","object","resource","NULL" );
        
    public function 
__construct($name)
    {
        
$this->_name=$name;
    }
    
    
// sin implentar
    
public function __clone()
    { }
    
    
    
// sin implentar
    
public function parse($str)
    { }

    public function 
create($var,$type=null,$val=null)
    {
        if ((!empty(
$type)) and ($type!="unknown type"))
        {
            
// alias
            
if ($type=='bool'$type='boolean';
            if (
$type=='int'$type='integer';                
            if (
$type=='float'$type='double';    
            if (
$type=='str'$type='string';    
            
            if ((
in_array($type,$this->_tipos_)))
                
$this->_type[$var] = $type;    
            else
                throw new 
Exception ("Tipo de dato no soportado");        
        }                
                
    
        
$this->_field[$var] = $val;        
        return 
$this;
    }
    
    
    public function 
__set($var,$val)
    {        
        if (
gettype($val)!= $this->_type[$var])
            throw new 
Exception ("Tipos no coinciden");        
    
        if (
in_array($var,array_keys($this->_field)))
            
$this->_field[$var] = $val;        
        else
            throw new 
Exception("No existe el campo $var!");
    }
    
    public function 
__get($var)
    {
        return 
$this->_field[$var];                
    }

Habia pensado en implementar un metodo parse() para cambiar la sintaxis pero me parecio demasiada sobrecarga (quizas no)... y lo dejo asi por ahora:

Se usaba asi:

Código PHP:
/* Experimental */

$st_diccio = (new Struct('alquiler videos'))->parse('
    string $pelicula;
    object    $nom_persona;
    object $fecha_prestamo;
    int    $dias_prestamo = 3;
'
); 
Tener en cuenta que uso alias para integer (int), string (str), float (double) ... tambien habia pensado en dar la opcion de deshabilitar el alias pero de momento queda asi

CRITIQUEN POR FAVOR... !
__________________
Salu2!
  #2 (permalink)  
Antiguo 28/05/2014, 12:52
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 7 meses
Puntos: 292
Respuesta: Nuevos tipos de datos: Struct de C y Range

TIPO RANGE

Permite manejar un tipo de dato rango que ademas es iterable (implementa Iterator):

Código PHP:
$rango = new Range(1,100,2);

foreach (
$rango as $valor){
    echo 
"$valor\n";
}

echo 
$rango
echo 
str_replace (' ',' ,',$rango); 
Quien lo implementa:

Código PHP:
<?php 

/*
    Clase Range
    @author: Pablo Bozzolo (italico76)
*/
Class Range implements Iterator {

    private 
$_arr = [];
    private 
$_ini  null;
    private 
$_end  null;
    private 
$_step null;

    public function 
__construct($a,$b,$step=null){        
        
$this->_ini  $a;
        
$this->_end  $b;
        
$this->_step = ($step == null $step);
        
$this->_arr  range($this->_ini,$this->_end,$this->_step);
    }

    public function 
getArray(){
        return 
$this->_arr;
    }

    public function 
__toString(){        
        
$out null

        foreach (
$this->_arr as $val)
            
$out .= "$val ";
     
        return 
rtrim($out);
           
    }

    
/* Implemento interface Iterator  */

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

    public function 
current()
    {
        
$elem current($this->_arr);        
        return 
$elem;
    }

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

// endClass
__________________
Salu2!
  #3 (permalink)  
Antiguo 28/05/2014, 12:54
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años, 7 meses
Puntos: 2534
Respuesta: Nuevos tipos de datos: Struct de C y Range

Suena interesante, me pregunto si la extensión SPL de PHP no implementa algo parecido.

Digo, PHP ha evolucionado mucho y no me sorprendería que exista algo similar, en caso de no existir veo elegante tu implementación.
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #4 (permalink)  
Antiguo 28/05/2014, 12:56
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 7 meses
Puntos: 292
Respuesta: Nuevos tipos de datos: Struct de C y Range

Cita:
Iniciado por pateketrueke Ver Mensaje
Suena interesante, me pregunto si la extensión SPL de PHP no implementa algo parecido.

Digo, PHP ha evolucionado mucho y no me sorprendería que exista algo similar, en caso de no existir veo elegante tu implementación.
Mucha gracias por las flores


VERSION ACTUALIZADA DE "STRUCT":

Código PHP:
Ver original
  1. <?php
  2. /*
  3.     Struct as in C
  4.     @author: Pablo Bozzolo
  5.  
  6.     struct database {
  7.         int id_number;
  8.         int age;
  9.         float salary;
  10.     };
  11. */
  12.  
  13. Class Struct
  14. {
  15.     protected $_field = array();
  16.     protected $_type  = array();
  17.     protected $_name = null;
  18.     protected $_type_hinting = true;   
  19.     protected $_tipos_ = array ("boolean","integer","double","string","array","object","resource","NULL" );
  20.     protected $_aliases = array(); 
  21.    
  22.     /* setter on-off */
  23.     public function alias($flag=true)
  24.     {
  25.         if ($flag)
  26.             $this->_aliases=array('bool'=>'boolean','int'=>'integer','float'=>'double','str'=>'string');
  27.         else
  28.             $this->_aliases=null;
  29.            
  30.         return $this;  
  31.     }
  32.        
  33.     public function __construct($name)
  34.     {
  35.         $this->_name=$name;
  36.         $this->alias();
  37.     }
  38.    
  39.     // sin implentar
  40.     public function __clone()
  41.     {   }
  42.  
  43.     public function typeHinting($flag)
  44.     {
  45.         $this->_type_hinting=$flag;        
  46.     }
  47.    
  48.     public function parse($str)
  49.     {
  50.         $patt = '|^[\s]{0,}([a-z_]*)[\s]{0,}([$]?[a-z_]*[0-9a-z]*)[\s]{0,}[=;]?[\s]{0,}(.*)|i';
  51.        
  52.         $statements = explode(';',trim($str));
  53.         foreach ($statements as $st)
  54.         {      
  55.             if (strlen($st)==0)
  56.                 continue;
  57.                
  58.             if (preg_match($patt,$st,$resul))
  59.             {
  60.                 $type = $resul[1];
  61.                 $var_name = str_replace('$','',$resul[2]);
  62.                 $default = $resul[3];              
  63.                                
  64.                 if ( (empty($var_name)) and (!empty($type)) )
  65.                 {
  66.                     $var_name=$type;
  67.                     $type=null;
  68.                 }
  69.                
  70.                 $this->create($var_name,$type,$default);                               
  71.             }else
  72.                 echo "FAIL PARSING : $st \n";;
  73.         }
  74.         return $this;
  75.     }
  76.  
  77.     public function create($var,$type=null,$val=null)
  78.     {
  79.         if ((!empty($type)) and ($type!="unknown type"))
  80.         {      
  81.             // alias
  82.             foreach ((array) $this->_aliases as $alias => $typo)
  83.                 if ($type==$alias) $type=$typo;
  84.                        
  85.             if ((in_array($type,$this->_tipos_)))
  86.                 $this->_type[$var] = $type;
  87.             else
  88.                 throw new Exception ("Tipo de dato no soportado");     
  89.         }              
  90.                
  91.    
  92.         $this->_field[$var] = $val;    
  93.         return $this;
  94.     }
  95.    
  96.    
  97.     public function __set($var,$val)
  98.     {      
  99.         if (!empty($this->_type[$var]))
  100.             if (gettype($val)!= $this->_type[$var])
  101.                 throw new Exception ("Tipos no coinciden");    
  102.    
  103.         if (in_array($var,array_keys($this->_field)))
  104.             $this->_field[$var] = $val;    
  105.         else
  106.             throw new Exception("No existe el campo $var!");
  107.     }
  108.    
  109.     public function __get($var)
  110.     {
  111.         return $this->_field[$var];            
  112.     }
  113. }


A considerar si se usa parse()

Cita:
1.- Las propiedades del struct pueden o no comenzar con $ como las variables (opcional)

2.- No se admiten ningun tipo de comentario inline ni multiline (no molesten xD)
--
Aca un tema viejito donde me surgio la idea de la clase Range
__________________
Salu2!

Última edición por Italico76; 29/05/2014 a las 06:37
  #5 (permalink)  
Antiguo 30/05/2014, 11:55
lolainas
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Nuevos tipos de datos: Struct de C y Range

Buen y curioso artificio los structs

Respecto a los ranges, para los que tengáis la suerte de escribir en las últimas versiones de PHP (como yo!!), esto es muy interesante

Cita:
(PHP 5 >= 5.5.0)
Los generadores proporcionan un modo fácil de implementar iteradores simples sin la sobrecarga o complejidad de implementar una clase que implemente la interfaz Iterator.

Un generador permite escribir código que utilice foreach para iterar sobre un conjunto de datos sin que sea necesario cargar el array en memoria, lo que puede ocasionar que se exceda el límite de memoria, o requiera una cantidad considerable de tiempo de procesado para generarse. En su lugar, se puede escribir una función generadora, que es igual que una función normal, con la salvedad de que en vez de hacer un solo return, un generador puede invocar yield tantas veces como necesite para proporcionar valores por los que iterar.

Un ejemplo simple de esto es reimplementar la función range() como un generador. La función estándar range() tiene que generar un array con cada uno de los valores y devolverlo, lo que puede resultar en arrays grandes: por ejemplo, llamar range(0, 1000000) resultará en más de 100 MB de memoria utilizada.

Como alternativa, se puede implementar un generador xrange(), que sólo necesitará memoria para crear un objeto Iterator y controlar el estado actual del generador de manera interna, lo que no ocupa más de 1 kilobyte.
  #6 (permalink)  
Antiguo 30/05/2014, 13:04
lolainas
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Nuevos tipos de datos: Struct de C y Range

Apuntes sobre struct (constructivos, por las dudas)

1. Partiendo de la base de que los structs en C son declarados en tiempo de compilación y no de ejecución, dejaría de usar create para ello.

2. En el type hinting quizás el tipo 'object' sea muy genérico y fácilmente franqueable, sería de utilidad usar el operador de tipo instanceof, además de gettype para tipos primitivos.

Código PHP:
Ver original
  1. abstract class Struct {
  2.  
  3.     private $data;
  4.     private $definition;
  5.  
  6.     function __construct(array $definition) {
  7.         $this->definition = $definition;
  8.     }
  9.  
  10.     function __get($name) {
  11.         return $this->data[$name];
  12.     }
  13.  
  14.     function __set($name, $value) {
  15.         if (isset($this->definition[$name]))
  16.             if (($value_type = gettype($value)) === ($definition_type = $this->definition[$name]) || $value instanceof $definition_type)
  17.                 $this->data[$name] = $value;
  18.             else
  19.                 throw new Exception("Trying to assign ({$definition_type}: {$name}) with {$value_type}");
  20.         else
  21.             throw new Exception("Trying to access undefined variable {$name}");
  22.     }
  23.  
  24. }
  25.  
  26. class Persona extends Struct {
  27.  
  28.     function __construct() {
  29.         parent::__construct([
  30.             'nombre'           => 'string',
  31.             'apellidos'        => 'string',
  32.             'fecha_nacimiento' => 'DateTime',
  33.             'telefonos'        => 'array'
  34.         ]);
  35.     }
  36.  
  37. }
  38.  
  39. $p = new Persona;
  40.  
  41. $p->nombre = 'Pablo';
  42. $p->apellidos = 'Bozzolo';
  43. $p->fecha_nacimiento = new DateTime('1980-10-01');
  44. $p->telefonos = ['435435435', '342343242'];
  45.  

Que conste que este tipo de aritificios no están garantizados para un entorno de producción real, pero es un tema interesante al que últimamente se le da mucha vuelta por el foro, por ejemplo este artificio para emular polimorfismo del amigo NSD.

Saludos.
  #7 (permalink)  
Antiguo 30/05/2014, 14:16
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 7 meses
Puntos: 292
Respuesta: Nuevos tipos de datos: Struct de C y Range

@lolainas : que te digo ? tu version funciona, es mas simple..... me gusta y mucho excepto porque la forma de utilizarla es mucho mas complicada, toca crear una clase y escribir un su constructor una llamada al constructor del padre Struct con un array tambien hecho a mano.


Como me destacaba por MP el compañero @hhs ... es importante ofrecer una "API simple", igualmente me tome el atrevimiento de "mejorar" un poco tu version y agregarle el alias de tipos:

Código PHP:
Ver original
  1. abstract class Struct
  2. {
  3.  
  4.     private $data;
  5.     private $definition;
  6.     private $_aliases = array();   
  7.  
  8.     function __construct(array $definition) {
  9.         $this->definition = $definition;
  10.         $this->alias();
  11.     }
  12.  
  13.     function __get($name) {
  14.         return $this->data[$name];
  15.     }
  16.  
  17.     function __set($name, $value)
  18.     {  
  19.         if (isset($this->definition[$name]))
  20.         {
  21.             $value_type = gettype($value);
  22.             $definition_type = $this->definition[$name];
  23.        
  24.             // alias
  25.             foreach ((array) $this->_aliases as $alias => $typo)
  26.                 if ($definition_type==$alias) $definition_type=$typo;
  27.                        
  28.             if (($value_type === $definition_type) || $value instanceof $definition_type)
  29.                 $this->data[$name] = $value;
  30.                
  31.             else
  32.                 throw new Exception("Trying to assign ({$definition_type}: {$name}) with {$value_type}");
  33.         }else
  34.             throw new Exception("Trying to access undefined variable {$name}");
  35.            
  36.     }      
  37.    
  38.     /* setter on-off */
  39.     function alias($flag=true)
  40.     {
  41.         $this->_aliases= $flag ? array('bool'=>'boolean','int'=>'integer','float'=>'double','str'=>'string') : null;
  42.            
  43.         return $this;  
  44.     }  
  45. }

Código PHP:
Ver original
  1. class Persona extends Struct {
  2.  
  3.     function __construct() {
  4.         parent::__construct([
  5.             'nombre'           => 'str',
  6.             'apellidos'        => 'str',
  7.             'hijos'            => 'int',
  8.             'fecha_nacimiento' => 'DateTime',
  9.             'telefonos'        => 'array'
  10.         ]);
  11.     }
  12.  
  13. }
  14.  
  15. $p = new Persona;
  16.  
  17. $p->nombre = 'Pablo';
  18. $p->apellidos = 'Bozzolo';
  19. $p->fecha_nacimiento = new DateTime('1980-10-01');
  20. $p->telefonos = ['435435435', '342343242'];
  21.  
  22. debug($p);
__________________
Salu2!

Última edición por Italico76; 30/05/2014 a las 16:32
  #8 (permalink)  
Antiguo 30/05/2014, 18:49
lolainas
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Nuevos tipos de datos: Struct de C y Range

Muy bueno
  #9 (permalink)  
Antiguo 01/06/2014, 16:55
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 4 meses
Puntos: 379
Respuesta: Nuevos tipos de datos: Struct de C y Range

Excelente conclusión en la implementación para los dos.
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #10 (permalink)  
Antiguo 01/06/2014, 18:53
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años, 7 meses
Puntos: 292
Respuesta: Nuevos tipos de datos: Struct de C y Range

Gracias compa, Ud sabe que tomo muchos de sus sugerencias y valioso conocimiento

Aprovecho para felicitar a @lolainas y @NSD por sus aportes en este y otros hilos
__________________
Salu2!
  #11 (permalink)  
Antiguo 02/06/2014, 01:22
lolainas
Invitado
 
Mensajes: n/a
Puntos:
Respuesta: Nuevos tipos de datos: Struct de C y Range

Felicitaciones para ti que aportas retos e ideas interesantes.

Y felicitaciones a hhs q me entretiene y me gusta leer sus respuestas sobre temas de diseño.

Saludos.

Etiquetas: fecha, nuevos, range, registro, struct
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 10:23.