我知道PHP还没有本地枚举。但是我已经习惯了来自Java世界的它们。我喜欢使用枚举来提供ide的自动补全功能能够理解的预定义值。
常量可以解决这个问题,但是存在名称空间冲突问题,而且(实际上是因为)它们是全局的。数组没有名称空间的问题,但是它们太模糊了,它们可以在运行时被覆盖,而且ide很少知道如何在没有额外的静态分析注释或属性的情况下自动填充它们的键。
你有什么常用的解决方案/变通办法吗?有人记得PHP的人对枚举有什么想法或决定吗?
我知道PHP还没有本地枚举。但是我已经习惯了来自Java世界的它们。我喜欢使用枚举来提供ide的自动补全功能能够理解的预定义值。
常量可以解决这个问题,但是存在名称空间冲突问题,而且(实际上是因为)它们是全局的。数组没有名称空间的问题,但是它们太模糊了,它们可以在运行时被覆盖,而且ide很少知道如何在没有额外的静态分析注释或属性的情况下自动填充它们的键。
你有什么常用的解决方案/变通办法吗?有人记得PHP的人对枚举有什么想法或决定吗?
当前回答
我使用接口而不是类:
interface DaysOfWeek
{
const Sunday = 0;
const Monday = 1;
// etc.
}
var $today = DaysOfWeek::Sunday;
其他回答
公认的答案是要走的路,实际上这是我所做的简单。枚举提供了大多数优点(可读、快速等)。然而,这里缺少一个概念:类型安全。在大多数语言中,枚举也用于限制允许的值。下面是一个通过使用私有构造函数、静态实例化方法和类型检查来获得类型安全的例子:
class DaysOfWeek{
const Sunday = 0;
const Monday = 1;
// etc.
private $intVal;
private function __construct($intVal){
$this->intVal = $intVal;
}
//static instantiation methods
public static function MONDAY(){
return new self(self::Monday);
}
//etc.
}
//function using type checking
function printDayOfWeek(DaysOfWeek $d){ //compiler can now use type checking
// to something with $d...
}
//calling the function is safe!
printDayOfWeek(DaysOfWeek::MONDAY());
我们甚至可以更进一步:在DaysOfWeek类中使用常量可能会导致误用:例如,人们可能会这样错误地使用它:
printDayOfWeek(DaysOfWeek::Monday); //triggers a compiler error.
这是错误的(调用整数常量)。我们可以使用私有静态变量而不是常量来防止这种情况:
class DaysOfWeeks{
private static $monday = 1;
//etc.
private $intVal;
//private constructor
private function __construct($intVal){
$this->intVal = $intVal;
}
//public instantiation methods
public static function MONDAY(){
return new self(self::$monday);
}
//etc.
//convert an instance to its integer value
public function intVal(){
return $this->intVal;
}
}
当然,不可能访问整数常量(这实际上是目的)。intVal方法允许将DaysOfWeek对象转换为其整数表示形式。
请注意,我们甚至可以进一步在实例化方法中实现缓存机制,以在广泛使用枚举的情况下节省内存…
希望这能有所帮助
这里有一些很好的解决方案!
这是我的版本。
它是强类型的 它与IDE自动补全一起工作 枚举由代码和描述定义,其中代码可以是整数、二进制值、短字符串或基本上任何您想要的内容。可以很容易地扩展该模式以支持其他属性。 它支持值(==)和引用(===)比较,并在switch语句中工作。
我认为主要的缺点是枚举成员必须分别声明和实例化,这是由于描述和PHP不能在静态成员声明时构造对象。我想绕过这个问题的一种方法可能是使用带有解析过的文档注释的反射。
抽象枚举看起来像这样:
<?php
abstract class AbstractEnum
{
/** @var array cache of all enum instances by class name and integer value */
private static $allEnumMembers = array();
/** @var mixed */
private $code;
/** @var string */
private $description;
/**
* Return an enum instance of the concrete type on which this static method is called, assuming an instance
* exists for the passed in value. Otherwise an exception is thrown.
*
* @param $code
* @return AbstractEnum
* @throws Exception
*/
public static function getByCode($code)
{
$concreteMembers = &self::getConcreteMembers();
if (array_key_exists($code, $concreteMembers)) {
return $concreteMembers[$code];
}
throw new Exception("Value '$code' does not exist for enum '".get_called_class()."'");
}
public static function getAllMembers()
{
return self::getConcreteMembers();
}
/**
* Create, cache and return an instance of the concrete enum type for the supplied primitive value.
*
* @param mixed $code code to uniquely identify this enum
* @param string $description
* @throws Exception
* @return AbstractEnum
*/
protected static function enum($code, $description)
{
$concreteMembers = &self::getConcreteMembers();
if (array_key_exists($code, $concreteMembers)) {
throw new Exception("Value '$code' has already been added to enum '".get_called_class()."'");
}
$concreteMembers[$code] = $concreteEnumInstance = new static($code, $description);
return $concreteEnumInstance;
}
/**
* @return AbstractEnum[]
*/
private static function &getConcreteMembers() {
$thisClassName = get_called_class();
if (!array_key_exists($thisClassName, self::$allEnumMembers)) {
$concreteMembers = array();
self::$allEnumMembers[$thisClassName] = $concreteMembers;
}
return self::$allEnumMembers[$thisClassName];
}
private function __construct($code, $description)
{
$this->code = $code;
$this->description = $description;
}
public function getCode()
{
return $this->code;
}
public function getDescription()
{
return $this->description;
}
}
下面是一个具体枚举示例:
<?php
require('AbstractEnum.php');
class EMyEnum extends AbstractEnum
{
/** @var EMyEnum */
public static $MY_FIRST_VALUE;
/** @var EMyEnum */
public static $MY_SECOND_VALUE;
/** @var EMyEnum */
public static $MY_THIRD_VALUE;
public static function _init()
{
self::$MY_FIRST_VALUE = self::enum(1, 'My first value');
self::$MY_SECOND_VALUE = self::enum(2, 'My second value');
self::$MY_THIRD_VALUE = self::enum(3, 'My third value');
}
}
EMyEnum::_init();
可以这样使用:
<?php
require('EMyEnum.php');
echo EMyEnum::$MY_FIRST_VALUE->getCode().' : '.EMyEnum::$MY_FIRST_VALUE->getDescription().PHP_EOL.PHP_EOL;
var_dump(EMyEnum::getAllMembers());
echo PHP_EOL.EMyEnum::getByCode(2)->getDescription().PHP_EOL;
并产生如下输出:
1 : My first value array(3) { [1]=> object(EMyEnum)#1 (2) { ["code":"AbstractEnum":private]=> int(1) ["description":"AbstractEnum":private]=> string(14) "My first value" } [2]=> object(EMyEnum)#2 (2) { ["code":"AbstractEnum":private]=> int(2) ["description":"AbstractEnum":private]=> string(15) "My second value" } [3]=> object(EMyEnum)#3 (2) { ["code":"AbstractEnum":private]=> int(3) ["description":"AbstractEnum":private]=> string(14) "My third value" } } My second value
这是我对“动态”enum的看法…这样我就可以用变量来调用它,比如从表单中。
看看这个代码块下面的更新版本…
$value = "concert";
$Enumvalue = EnumCategory::enum($value);
//$EnumValue = 1
class EnumCategory{
const concert = 1;
const festival = 2;
const sport = 3;
const nightlife = 4;
const theatre = 5;
const musical = 6;
const cinema = 7;
const charity = 8;
const museum = 9;
const other = 10;
public function enum($string){
return constant('EnumCategory::'.$string);
}
}
更新:更好的方式做…
class EnumCategory {
static $concert = 1;
static $festival = 2;
static $sport = 3;
static $nightlife = 4;
static $theatre = 5;
static $musical = 6;
static $cinema = 7;
static $charity = 8;
static $museum = 9;
static $other = 10;
}
电话
EnumCategory::${$category};
还有一个本地扩展。的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目前不可用。
我使用带有常量的类:
class Enum {
const NAME = 'aaaa';
const SOME_VALUE = 'bbbb';
}
print Enum::NAME;