2009-09-22 15 views
9

Me encanta la implementación de Hash de Ruby, donde puede inicializar el objeto Hash con un valor predeterminado. Por el momento estoy luchando con la implementación de un objeto similar en PHP. Esta es mi primera oportunidad (no laboral) de esto.Matriz PHP con valor predeterminado para índices no existentes

class DefaultArray extends ArrayObject { 

    protected $_defaultValue; 

    public function setDefault($defaultValue) { 
    $this->_defaultValue = $defaultValue; 
    } 

    public function offsetExists($index) { 
    return true; 
    } 

    public function offsetGet($index) { 
    if(!parent::offsetExists($index)) { 
     if(is_object($this->_defaultValue)) 
     $default = clone $this->_defaultValue; 
     else 
     $default = $this->_defaultValue; 

     parent::offsetSet($index, $default); 
    } 
    return parent::offsetGet($index); 
    } 
} 

$da = new DefaultArray(); 
assert($da["dummy"] == null); 
$da->setDefault = 1; 
assert($da["dummy2"] == 1); 

La segunda afirmación fallará. Al recorrer el código, se muestra que se llama a offsetGet y se ejecuta la cláusula if. Sin embargo, cualquier valor de matriz es nulo. ¿Alguna idea para implementaciones alternativas?

estoy cansado de escribir

if(!isset($myarr['value'])) 
    $myarr['value'] = new MyObj(); 
$myarr['value']->myVal=5; 

en lugar de escribir

$myarr['value']->myVal=5; 
+0

Al tener acceso a una clave que no existe, 'offsetGet' se establecer esa clave con el valor predeterminado (ver 'offsetSet'). Eso significa que la próxima vez existirá. Si no desea ese comportamiento y siempre obtiene el valor predeterminado actual para las claves que no existen, elimine la llamada 'offsetSet'. – Gumbo

+0

Gracias, Gumbo por la importante aclaración, este comportamiento me ha desconcertado en mi primera prueba, pero es el comportamiento previsto. La pregunta ahora está respondida y dejaré el código de prueba defectuoso tal como está. – chiborg

Respuesta

6
$da->setDefault(1); 

También puede utilizar la función mágica __construct:

class DefaultArray extends ArrayObject 
{ 
    public function __construct($value = null){ 
     if(is_null($value)) 
     { 
      $this->value = 'default'; 
     } else { 
      $this->value = $value; 
     } 
    } 
} 
+0

¡Gracias, detectaron mi error! ¡Es $ da-> setDefault (1) en lugar de $ da-> setDefault = 1! Oh la vergüenza! Con esta modificación, mi ejemplo funciona como se esperaba. También pensé en pasar el valor predeterminado en el constructor, pero quería conservar los argumentos originales del constructor de ArrayObject. – chiborg

+0

¿Cómo funciona if (if())? – Codler

+0

@Codler: de ninguna manera ... gracias, arreglado. – erenon

-3

¿Por qué tan complicada ?

function initVal($value) { 
    global $myarr; 
    if(!isset($myarr['value'])) 
     $myarr['value'] = new MyObj(); 
} 

Ahora sólo hay que llamar:

initVal('bla'); 
$myarr['bla']->bla = 'bla'; 

Pero veo, el suyo es mucho más limpio.

+3

El uso de la clase ArrayObject mantiene todas las variables y métodos de soporte en un solo lugar. Donde el uso de la función * global * tiene una probabilidad mucho más alta de conducir a problemas de mantenimiento en el futuro. – null

3

Pruebe el magic methods __get.

class DefaultArray extends ArrayObject { 
    protected $_defaultValue; 

    public function setDefault($defaultValue) { 
     $this->_defaultValue = $defaultValue; 
    } 

    public function __get($index) { 
     return $this->offsetGet($index); 
    } 

    public function offsetGet($index) { 
     if(!parent::offsetExists($index)) { 
      if (is_object($this->_defaultValue)) { 
       $default = clone $this->_defaultValue; 
      } else { 
       $default = $this->_defaultValue; 
      } 
      parent::offsetSet($index, $default); 
     } 
     return parent::offsetGet($index); 
    } 
} 

Ahora sólo tiene que utilizar diferentes claves como el acceso de lectura inicializará que los elementos de matriz:

$da = new DefaultArray(); 
assert($da['foo'] == null); 
$da->setDefault(1); 
assert($da['bar'] == 1); 
0

Se podía usar mi pequeña biblioteca ValueResolver en este caso, por ejemplo:

class DefaultArray extends ArrayObject 
{ 
    public function __construct($value = null){ 
     $this->value = ValueResolver::resolve($value, 'default'); // returns 'default' if $value is null 
    } 
} 

y no se olvide de utilizar espacio de nombres use LapaLabs\ValueResolver\Resolver\ValueResolver;

También hay posibilidad de encasillamiento, por ejemplo, si el valor de la variable debe ser integer, a fin de utilizar esto:

$id = ValueResolver::toInteger('6 apples', 1); // returns 6 
$id = ValueResolver::toInteger('There are no apples', 1); // returns 1 (used default value) 

Compruebe el docs para más ejemplos

Cuestiones relacionadas