有没有办法动态创建类的常量?我知道这听起来有点奇怪,但让我解释一下我要做的事情:
const
定义也许这样的事情:
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;
}
}
}
我认识到这实际上不会起作用,因为它没有设置CONST而是静态变量。也许我的整个想法都是头脑发达,并且有更好的技巧。无论如何,非常感谢任何实现最终目标的方法。
更新
我认为对我的目标更加清楚可能会有所帮助,因为我认为我对Constants的使用完全不是一个好的。基本上我想实现的是枚举列表的典型要求:
限制功能签名。我希望能够要求一组“值”作为函数的输入。例如:
公共功能do_something(ENUM_Types $ type){}
简单紧凑。在代码中使用时,允许使用简单紧凑的语法。例如,使用常量我可能会写一个条件语句,如:
if($ my_var === ENUM_Types :: TypeA){}
动态枚举。我希望这个枚举通过前端进行管理并存储在数据库中(我正在使用wordpress管理屏幕,以防万一有人关心)。在运行时,这个“列表”应该从数据库中取出,并作为枚举(或实现上述目标的类似结构)提供给代码。
答案 0 :(得分:8)
将“enum”值包装在单例中并实现(非静态)魔术__get
方法:
<?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!
}
}
对于奖励积分,创建一个返回单身的(非OO)函数:
function DynamicEnums() {
return DynamicEnums::singleton();
}
“DynamicEnums”的消费者看起来像:
echo DynamicEnums::singleton()->one;
echo DynamicEnums()->one; //can you feel the magic?
print_r(DynamicEnums::values());
[edit]更像enum-like。
答案 1 :(得分:7)
问:有没有办法动态创建类的常量?
答案是“是”,但不要这样做:)
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;
下一个问题......
问:限制功能签名。我希望能够要求一组“值”作为函数的输入。例如:
public function do_something ( ENUM_Types $type ) {}
根据manual,在这种情况下,$type
必须是ENUM_Types
类的实例。但是对于常数来说它是不可能的(它们不能包含对象)。
但是等等......我们可以使用这样的技巧:
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
之后我们可以使用“类型提示”:
function doSomething(darkSide $var) {
echo 'Bu!';
}
doSomething(darkSide::BAR());
doSomething(aaa::BAR());
问:简单紧凑。在代码中使用时,允许使用简单紧凑的语法。例如,使用常量,我可能会写一个条件语句,如:
if ( $my_var === ENUM_Types::TypeA ) {}
您可以使用以下形式的伪常量值:
if (darkSide::FOO === 1) {}
问:动态枚举。我希望这个枚举通过前端进行管理并存储在数据库中(我正在使用wordpress管理屏幕,以防万一有人关心)。在运行时,这个“列表”应该从数据库中取出,并作为枚举(或实现上述目标的类似结构)提供给代码。
您可以通过将数组传递给EnumFactory::create($class, $constants)
:
EnumFactory::create('darkSide', array('FOO' => 1, 'BAR' => 2));
答案 2 :(得分:0)
你可以做一些像Const = $$常量的东西。然后你可以设置$ contant = whatever。或者您可以使用受保护的属性,因为您希望它是动态的而常量不是。例如:
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');
答案 3 :(得分:0)
我不推荐它,但是eval()......请不要。
我已修改自动加载器以自动定义丢失或拼写错误的异常类型。原因:您可以捕获未捕获的异常,但在实例化异常类中的拼写错误时无法从PHP_FATAL中恢复。