Dynamic constants in PHP?

Is there a way to dynamically create class constants? I know this sounds a little strange, but let me explain what I'm trying to do:

  • I have an Enum class whose attributes are defined by static const definitions
  • This class extends the PHP class SplEnum
  • Instead of entering each of these definitions in code, I would like the static initializer to go into the database and pull out the listed values

Maybe something like this:

 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; } } } 

I understand that this will not work, as it does not set CONST, but rather static variables. Maybe my whole idea is wet hair, and there is the best technique there. In any case, any method of achieving the ultimate goal is greatly appreciated.

UPDATE

I think it would be useful to understand my goals a bit, because I think it is quite possible that my use of constants is not very good. Basically, I want this to be typical of the requirements of an enumerated list:

  • Signals of the restriction function . I want to be able to request a "set" of values ​​as input to a function. For example:

    public function do_something (ENUM_Types $ type) {}

  • Simple and compact . Allow simple and compact syntax when used in code. For example, using constants, I can write a conditional statement, for example:

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

  • Dynamic enumeration . I would like this enumeration to be managed through an interface and stored in a database (I use the Wordpress admin screens for this if someone cares). At run time, this β€œlist” should be pulled out of the database and made available for the code as an enumeration (or a similar structure that achieves the goals above).

+7
source share
4 answers

Wrap the "enum" values ​​in singleton mode and implement the (non-static) __get magic method:

 <?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! } } 

For bonus points, create a function (non-OO) that returns singleton:

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

Consumers of "DynamicEnums" will look like this:

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

[edit] More enum-like.

+8
source

Q: Is there a way to dynamically create class constants?

Answer: Yes, but do not do this :)

 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; 

The next question ...

Q: Signatures of a constraint function. I want to be able to request a "set" of values ​​as input to a function. For example: public function do_something ( ENUM_Types $type ) {}

According to manual , in this case $type must be an instance of the ENUM_Types class. But for a constant it is impossible (they cannot contain objects).

But wait ... We can use this trick:

 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 

And after that we can use the "hint type":

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

Q: Simple and compact. Allow simple and compact syntax when used in code. For example, using constants, I can write a conditional statement, for example: if ( $my_var === ENUM_Types::TypeA ) {}

You can use the values ​​of your pseudo-constants in this form:

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

Q: Dynamic enumeration. I would like this enumeration to be managed through an interface and stored in a database (I use the Wordpress admin screens for this if someone cares). During the execution of this β€œlist”, it should be pulled out of the database and made available for the code as an enumeration (or a similar structure that achieves the goals above).

You can initialize the enumeration by passing an array to EnumFactory::create($class, $constants) :

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

You can do something like Const = $$. Then you can set $ contant = anything. OR you can use a protected property, because you want it to be dynamic and constants not. Example:

 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
source

I do not recommend it, but eval () ... please do not do this.

I modified autoloaders to automatically detect types of exceptions that are missing or mistakenly written. Cause. You can catch an uncaught exception, but you cannot restore it from PHP_FATAL when instantiating in your exception class.

0
source

All Articles