2012-08-24 15 views
7

¿Hay alguna forma de crear dinámicamente las constantes de una clase? Sé que esto suena un poco extraño, pero permítanme explicar lo que estoy tratando de hacer:Constantes dinámicas en PHP?

  • tengo una clase de enumeración que sus atributos son definidos por estáticas const definiciones
  • Esta clase extiende la clase PHP SplEnum
  • en lugar de
  • tipo en cada una de estas definiciones en el código me gustaría tener un inicializador estático salir a la base de datos y tire de los valores enumerados

Tal vez algunas cosas como esta:

class myEnum extends SplEnum { 
    public static function init() { 
     $myNameValuePair = DB_Functions::get_enum_list(); 
     foreach ($myNameValuePair as $name => $value) { 
      $const = array (self , $name); 
      $const = $value; 
     } 
    } 
} 

Reconozco que esto no funcionará, ya que no establece las variables estáticas de CONST. Tal vez toda mi idea es el cerebro del cabello y hay una mejor técnica para esto. De todos modos, cualquier método para lograr el objetivo final es muy apreciado.

ACTUALIZACIÓN

yo creo que puede ser útil a ser un poco más claro en mis objetivos, porque creo que es del todo posible que mi uso de constantes no es una buena idea. Básicamente quiero lograr es típico de los requisitos de la lista enumerada:

  1. firmas de función Restringir. Quiero poder solicitar un "conjunto" de valores como entrada para una función. Por ejemplo:

    función pública hacer_algo (ENUM_Types $ tipo) {}

  2. simple y compacto. Permita una sintaxis simple y compacta cuando se usa en el código. Por ejemplo, con el uso de constantes que podría escribir una sentencia condicional algo como:

    if ($ my_var === ENUM_Types :: TypeA) {}

  3. enumeración dinámica. Me gustaría que esta enumeración se administre a través de la interfaz y se almacene en la base de datos (estoy usando pantallas de administración de WordPress para esto en caso de que a alguien le importe). En tiempo de ejecución, esta "lista" debe extraerse del DB y ponerse a disposición del código como una enumeración (o una estructura similar que logre los objetivos anteriores).

+6

Por definición, una constante no puede ser dinámico. ¿Por qué no solo usar variables estáticas? – Matt

+0

Bueno, sí, lo sé y es por eso que lo dije "podría parecer un poco extraño". Actualizaré un poco la pregunta para dejar más claro lo que intento lograr. – ken

+0

En otras palabras ... no quiere constantes dinámicas, quiere enums dinámicos. – EthanB

Respuesta

8

Envuelva sus valores "enumeración" en un producto único e implementar el (no estático) magia __get método:

<?php 
class DynamicEnums { 

    private static $singleton; 

    private $enum_values; 

    public static function singleton() { 
    if (!self::$singleton) { 
     self::$singleton = new DynamicEnums(); 
    } 
    return self::$singleton; 
    } 

    function __construct() { 
    $this->enum_values = array(//fetch from somewhere 
     'one' => 'two', 
     'buckle' => 'my shoe!', 
    ); 
    } 

    function __get($name) { 
    return $this->enum_values[$name]; //or throw Exception? 
    } 

    public static function values() { 
    return self::singleton()->enum_values; //warning... mutable! 
    } 
} 

Para los puntos de bonificación, crear una función (no-OO) que devuelve el singleton:

function DynamicEnums() { 
    return DynamicEnums::singleton(); 
} 

Los consumidores de "DynamicEnums" se vería así:

echo DynamicEnums::singleton()->one; 
echo DynamicEnums()->one;   //can you feel the magic? 
print_r(DynamicEnums::values()); 

[editar ] Más como enum.

+0

Evaluación diferida, ¿eh? –

+1

+1 por magia ... –

+0

Esto se ve bien. Creo que cumple con todos mis requisitos. Muchas gracias por la magia. : ^) – ken

0

Podría hacer algo como Const = $$ constante. Entonces podrías establecer $ contant = lo que sea. O puede usar una propiedad protegida ya que quiere que sea dinámica y las Constantes no. Ejemplo:

class Foo { 

protected $test = ''; 

function set($bar){ 
    $this->test = $bar; 
} 
function get($bar){ 
    return $this->test; 
} 


} 

$foobar = new Foo(); 
$foobar->set('test'); 
echo $foobar->get('test'); 
+0

Por definición, una constante no puede ser dinámica. * Debe * establecerse en un valor literal. – Matt

+0

¿Qué tal si utilizamos una propiedad que está protegida y la usamos como una constante de Psuedo? –

+0

¿Puedes describir lo que quieres decir con tu respuesta? – Matt

0

Yo no lo recomiendo, pero eval() ... Por favor no lo hacen.

He modificado los autocargadores para definir automáticamente los tipos de excepción que faltan o están mal escritos. Motivo: puede atrapar una excepción no detectada, pero no puede recuperar desde PHP_FATAL al crear una instancia de un error tipográfico en su clase de excepción.

7

P: ¿Hay alguna manera de crear las constantes de una clase dinámicamente?

La respuesta es 'sí', pero no hagas eso :)

class EnumFactory { 

    public static function create($class, array $constants) { 
     $declaration = ''; 
     foreach($constants as $name => $value) { 
      $declaration .= 'const ' . $name . ' = ' . $value . ';'; 
     } 
     eval("class $class { $declaration }"); 
    } 

} 

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2)); 
echo darkSide::FOO . ' ' . darkSide::BAR; 

siguiente pregunta ...

Q: Restringir firmas de función. Quiero poder solicitar un "conjunto" de valores como entrada para una función. Por ejemplo: public function do_something (ENUM_Types $type) {}

Según la manual, en ese caso $type es debe ser una instancia de la clase ENUM_Types. Pero para la constante es imposible (no pueden contener objetos).

Pero espera ... Podemos utilizar dicha truco:

class Enum { 

    protected static $_constantToClassMap = array(); 
    protected static function who() { return __CLASS__; } 

    public static function registerConstants($constants) { 
     $class = static::who(); 
     foreach ($constants as $name => $value) { 
      self::$_constantToClassMap[$class . '_' . $name] = new $class(); 
     } 
    } 

    public static function __callStatic($name, $arguments) { 
     return self::$_constantToClassMap[static::who() . '_' . $name]; 
    } 

} 

class EnumFactory { 

    public static function create($class, $constants) { 
     $declaration = ''; 
     foreach($constants as $name => $value) { 
      $declaration .= 'const ' . $name . ' = ' . $value . ';'; 
     } 

     eval("class $class extends Enum { $declaration protected static function who() { return __CLASS__; } }"); 
     $class::registerConstants($constants); 
    } 

} 

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2)); 
EnumFactory::create('aaa', array('FOO' => 1, 'BAR' => 2)); 

echo (aaa::BAR() instanceof aaa) ? 'Yes' : 'No'; // Yes 
echo (aaa::BAR() instanceof darkSide) ? 'Yes' : 'No'; // No 

Y después de eso podemos utilizar un "tipo dando a entender":

function doSomething(darkSide $var) { 
    echo 'Bu!'; 
} 

doSomething(darkSide::BAR()); 
doSomething(aaa::BAR()); 

Q: Simple y Compacto. Permita una sintaxis simple y compacta cuando se usa en el código. Por ejemplo, con el uso de constantes que podría escribir una sentencia condicional algo como: if ($my_var === ENUM_Types::TypeA) {}

Se pueden utilizar valores de sus pseudo-constantes en la forma:

if (darkSide::FOO === 1) {} 

Q: Enumeración dinámica Me gustaría que esta enumeración se administre a través de la interfaz y se almacene en la base de datos (estoy usando pantallas de administración de WordPress para esto en caso de que a alguien le importe). En tiempo de ejecución, esta "lista" debe extraerse del DB y ponerse a disposición del código como una enumeración (o una estructura similar que logre los objetivos anteriores).

Puede init su enumeración pasando array a la EnumFactory::create($class, $constants):

EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2)); 
+3

muchas gracias. Es grandioso ver cómo se puede lograr esto si estás dispuesto a caminar sobre el lado oscuro (también conocido como el lado eval). – ken