我知道PHP还没有本地枚举。但是我已经习惯了来自Java世界的它们。我喜欢使用枚举来提供ide的自动补全功能能够理解的预定义值。
常量可以解决这个问题,但是存在名称空间冲突问题,而且(实际上是因为)它们是全局的。数组没有名称空间的问题,但是它们太模糊了,它们可以在运行时被覆盖,而且ide很少知道如何在没有额外的静态分析注释或属性的情况下自动填充它们的键。
你有什么常用的解决方案/变通办法吗?有人记得PHP的人对枚举有什么想法或决定吗?
我知道PHP还没有本地枚举。但是我已经习惯了来自Java世界的它们。我喜欢使用枚举来提供ide的自动补全功能能够理解的预定义值。
常量可以解决这个问题,但是存在名称空间冲突问题,而且(实际上是因为)它们是全局的。数组没有名称空间的问题,但是它们太模糊了,它们可以在运行时被覆盖,而且ide很少知道如何在没有额外的静态分析注释或属性的情况下自动填充它们的键。
你有什么常用的解决方案/变通办法吗?有人记得PHP的人对枚举有什么想法或决定吗?
当前回答
// My Enumeration Class
class Enum
{
protected $m_actions = array();
public function __construct($actions)
{
$this->init($actions);
}
public function init($actions)
{
$this->m_actions = array();
for($i = 0; $i < count($actions); ++$i)
{
$this->m_actions[$actions[$i]] = ($i + 1);
define($actions[$i], ($i + 1));
}
}
public function toString($index)
{
$keys = array_keys($this->m_actions);
for($i = 0; $i < count($keys); ++$i)
{
if($this->m_actions[$keys[$i]] == $index)
{
return $keys[$i];
}
}
return "undefined";
}
public function fromString($str)
{
return $this->m_actions[$str];
}
}
// Enumeration creation
$actions = new Enum(array("CREATE", "READ", "UPDATE", "DELETE"));
// Examples
print($action_objects->toString(DELETE));
print($action_objects->fromString("DELETE"));
if($action_objects->fromString($_POST["myAction"]) == CREATE)
{
print("CREATE");
}
其他回答
上面的答案太棒了。但是,如果以两种不同的方式进行扩展,那么无论先进行哪种扩展,都会导致对函数的调用,从而创建缓存。这个缓存将被所有后续调用使用,无论调用是由哪个扩展发起的…
要解决这个问题,将变量和第一个函数替换为:
private static $constCacheArray = null;
private static function getConstants() {
if (self::$constCacheArray === null) self::$constCacheArray = array();
$calledClass = get_called_class();
if (!array_key_exists($calledClass, self::$constCacheArray)) {
$reflect = new \ReflectionClass($calledClass);
self::$constCacheArray[$calledClass] = $reflect->getConstants();
}
return self::$constCacheArray[$calledClass];
}
下面是一个github库,用于在php中处理类型安全的枚举:
这个库处理类生成、类缓存,并实现了Type Safe Enumeration设计模式,使用几个辅助方法来处理枚举,比如为枚举排序检索序号,或为枚举组合检索二进制值。
生成的代码使用一个普通的旧php模板文件,该文件也是可配置的,因此您可以提供自己的模板。
它是由phpunit覆盖的完整测试。
Php-enums在github (feel free to fork)
用法:(@参见Usage .php或单元测试了解更多细节)
<?php
//require the library
require_once __DIR__ . '/src/Enum.func.php';
//if you don't have a cache directory, create one
@mkdir(__DIR__ . '/cache');
EnumGenerator::setDefaultCachedClassesDir(__DIR__ . '/cache');
//Class definition is evaluated on the fly:
Enum('FruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'));
//Class definition is cached in the cache directory for later usage:
Enum('CachedFruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'), '\my\company\name\space', true);
echo 'FruitsEnum::APPLE() == FruitsEnum::APPLE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::APPLE()) . "\n";
echo 'FruitsEnum::APPLE() == FruitsEnum::ORANGE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::ORANGE()) . "\n";
echo 'FruitsEnum::APPLE() instanceof Enum: ';
var_dump(FruitsEnum::APPLE() instanceof Enum) . "\n";
echo 'FruitsEnum::APPLE() instanceof FruitsEnum: ';
var_dump(FruitsEnum::APPLE() instanceof FruitsEnum) . "\n";
echo "->getName()\n";
foreach (FruitsEnum::iterator() as $enum)
{
echo " " . $enum->getName() . "\n";
}
echo "->getValue()\n";
foreach (FruitsEnum::iterator() as $enum)
{
echo " " . $enum->getValue() . "\n";
}
echo "->getOrdinal()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
echo " " . $enum->getOrdinal() . "\n";
}
echo "->getBinary()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
echo " " . $enum->getBinary() . "\n";
}
输出:
FruitsEnum::APPLE() == FruitsEnum::APPLE(): bool(true)
FruitsEnum::APPLE() == FruitsEnum::ORANGE(): bool(false)
FruitsEnum::APPLE() instanceof Enum: bool(true)
FruitsEnum::APPLE() instanceof FruitsEnum: bool(true)
->getName()
APPLE
ORANGE
RASBERRY
BANNANA
->getValue()
apple
orange
rasberry
bannana
->getValue() when values have been specified
pig
dog
cat
bird
->getOrdinal()
1
2
3
4
->getBinary()
1
2
4
8
class DayOfWeek {
static $values = array(
self::MONDAY,
self::TUESDAY,
// ...
);
const MONDAY = 0;
const TUESDAY = 1;
// ...
}
$today = DayOfWeek::MONDAY;
// If you want to check if a value is valid
assert( in_array( $today, DayOfWeek::$values ) );
不要使用反射。这使得你很难推断你的代码并追踪某些东西被使用的位置,而且往往会破坏静态分析工具(例如你的IDE中内置的工具)。
好吧,对于一个简单的java,比如php中的enum,我使用:
class SomeTypeName {
private static $enum = array(1 => "Read", 2 => "Write");
public function toOrdinal($name) {
return array_search($name, self::$enum);
}
public function toString($ordinal) {
return self::$enum[$ordinal];
}
}
我们称它为:
SomeTypeName::toOrdinal("Read");
SomeTypeName::toString(1);
但我是PHP初学者,语法不好,所以这可能不是最好的方法。我尝试了一些类常量,使用反射从它的值中获得常量名,可能更整洁。
还有一个本地扩展。的SplEnum
脾提供了模拟和创建枚举对象的能力 原生的PHP。
http://www.php.net/manual/en/class.splenum.php
注意:
https://www.php.net/manual/en/spl-types.installation.php
PECL扩展没有与PHP绑定。 此PECL扩展的DLL目前不可用。