如何在 PHP 中实现类似 Enum 的功能? [复制]
Posted
技术标签:
【中文标题】如何在 PHP 中实现类似 Enum 的功能? [复制]【英文标题】:How to implement Enum like functionality in PHP? [duplicate] 【发布时间】:2010-12-04 10:30:36 【问题描述】:如何在 php 中使用类似 Enum 的功能(在 Java 和其他高级语言中提供)?我知道 PHP 目前不允许您创建枚举,但最接近的枚举是什么?
【问题讨论】:
我找到了这篇 (it.toolbox.com/blogs/macsploitation/…) 文章。 另见:***.com/questions/1486747/… 【参考方案1】:也许使用const
。
class SomeClass
const FIRSTVAL = 1;
const SECONDVAL = 2;
;
【讨论】:
问题在于Enum
需要是全局的。类常量不会是真正的
嗯,SomeClass::FIRSTVAL 可以从任何地方引用 ;-)
或self::FIRSTVAL
类内
我也会将类设为抽象类和最终类
@MikeL,如果您仅将类用作命名空间,这可能是一个很好的预防措施,但如果您只是在具有其他目的的类中这样做,则可能不是这样;)【参考方案2】:
这是@Kris 代码的更新版本,可以更好地与较新版本的 PHP 配合使用。它是根据@lassombra 评论制作的。
/**
* Implements the abstract base for all enum types
* @see http://***.com/a/2324746/1003020
* @see http://***.com/a/254543/1003020
*
* Example of a typical enum:
*
* class DayOfWeek extends Enum
*
* const Sunday = 0;
* const Monday = 1;
* const Tuesday = 2;
* const Wednesday = 3;
* const Thursday = 4;
* const Friday = 5;
* const Saturday = 6;
*
*
* Usage examples:
*
* $monday = DayOfWeek::Monday // (int) 1
* DayOfWeek::isValidName('Monday') // (bool) true
* DayOfWeek::isValidName('monday', $strict = true) // (bool) false
* DayOfWeek::isValidValue(0) // (bool) true
* DayOfWeek::fromString('Monday') // (int) 1
* DayOfWeek::toString(DayOfWeek::Tuesday) // (string) "Tuesday"
* DayOfWeek::toString(5) // (string) "Friday"
**/
abstract class Enum
private static $constCacheArray = NULL;
private static function getConstants()
if (self::$constCacheArray == NULL)
self::$constCacheArray = [];
$calledClass = get_called_class();
if (!array_key_exists($calledClass, self::$constCacheArray))
$reflect = new \ReflectionClass($calledClass);
self::$constCacheArray[$calledClass] = $reflect->getConstants();
return self::$constCacheArray[$calledClass];
public static function isValidName($name, $strict = false)
$constants = self::getConstants();
if ($strict)
return array_key_exists($name, $constants);
$keys = array_map('strtolower', array_keys($constants));
return in_array(strtolower($name), $keys);
public static function isValidValue($value, $strict = true)
$values = array_values(self::getConstants());
return in_array($value, $values, $strict);
public static function fromString($name)
if (self::isValidName($name, $strict = true))
$constants = self::getConstants();
return $constants[$name];
return false;
public static function toString($value)
if (self::isValidValue($value, $strict = true))
return array_search($value, self::getConstants());
return false;
【讨论】:
我喜欢这个,非常喜欢。它真的应该比我的原版评分更高。【参考方案3】:自从我发布这个答案后,@Vinicius-Garcia 已经改进了这个解决方案,his version is undoubtedly better 对于大多数用户来说。
下面的旧答案:
我使用类常量和一些反射技巧。
<?php
/**
* @package Red.Core
* @author kris@theredhead.nl
*
* Implements the abstract base for all enum types
*
* example of a typical enum:
*
* class DayOfWeek extends Enum
*
* const Sunday = 0;
* const Monday = 1;
* const Tuesday = 2;
* const Wednesday = 3;
* const Thursday = 4;
* const Friday = 5;
* const Saturday = 6;
*
*
* usage examples:
*
* $monday = Enum::FromString( 'DayOfWeek::Monday' ); // (int) 1
* $monday = DayOfWeek::Monday // (int) 1
* $monday = Enum::ToString( 'DayOfWeek', DayOfWeek::Monday ); // (string) "DayOfWeek::Monday"
* $monday = Enum::Label( 'DayOfWeek', DayOfWeek::Monday ); // (string) "Monday"
*
**/
abstract class Enum
// make sure there are never any instances created
final private function __construct()
throw new Exception( 'Enum and Subclasses cannot be instantiated.' );
/**
* Give the integer associated with the const of the given string in the format of "class:const"
*
* @param string $string
* @return integer
*/
final public static function FromString( $string )
if ( strpos( $string, '::' ) < 1 )
throw new Exception( 'Enum::FromString( $string ) Input string is not in the expected format.' );
list( $class, $const ) = explode( '::', $string );
if ( class_exists( $class, false ) )
$reflector = new ReflectionClass( $class );
if ( $reflector->IsSubClassOf( 'Enum' ) )
if ( $reflector->hasConstant( $const ) )
return eval( sprintf( 'return %s;', $string ) );
throw new Excption( sprintf( '%s does not map to an Enum field', $string ) );
final public static function IsValidValue( $enumType, $enumValue )
if ( class_exists( $enumType ) )
$reflector = new ReflectionClass( $enumType );
if ( $reflector->IsSubClassOf( 'Enum' ) )
foreach( $reflector->getConstants() as $label => $value )
if ( $value == $enumValue )
return true;
return false;
final public static function IsValidLabel( $enumType, $enumValue )
if ( class_exists( $enumType ) )
$reflector = new ReflectionClass( $enumType );
if ( $reflector->IsSubClassOf( 'Enum' ) )
foreach( $reflector->getConstants() as $label => $value )
if ( $label == $enumValue )
return true;
return false;
/**
* For a given $enumType, give the complete string representation for the given $enumValue (class::const)
*
* @param string $enumType
* @param integer $enumValue
* @return string
*/
final public static function ToString( $enumType, $enumValue )
$result = 'NotAnEnum::IllegalValue';
if ( class_exists( $enumType, false ) )
$reflector = new ReflectionClass( $enumType );
$result = $reflector->getName() . '::IllegalValue';
foreach( $reflector->getConstants() as $key => $val )
if ( $val == $enumValue )
$result = str_replace( 'IllegalValue', $key, $result );
break;
return $result;
/**
* For a given $enumType, give the label associated with the given $enumValue (const name in class definition)
*
* @param string $enumType
* @param integer $enumValue
* @return string
*/
final public static function Label( $enumType, $enumValue )
$result = 'IllegalValue';
if ( class_exists( $enumType, false ) )
$reflector = new ReflectionClass( $enumType );
foreach( $reflector->getConstants() as $key => $val )
if ( $val == $enumValue )
$result = $key;
break;
return $result;
?>
【讨论】:
我喜欢它——这是一个很棒的解决方案! 我知道这是可怕的 necro,但是使用 PHP 5.3+ static::class 常量,您不必使用传递 $enumType 的版本,因为您可以在方法中解决它。这也使您不必进行大量检查以查看该值是否有效,因为 PHP 本身提供了它。它还使您能够避免 eval,而是返回 static::$enumValue【参考方案4】:你也可以用这个:
class Enum
private $m_valueName = NULL;
private function __construct($valueName)
$this->m_valueName = $valueName;
public static function __callStatic($methodName, $arguments)
$className = get_called_class();
return new $className($methodName);
function __toString()
return $this->m_valueName;
class NotificationType extends Enum
const Notification = NULL;
const Warning = NULL;
const Error = NULL;
function Test(NotificationType $type)
echo "Test function, type: $type<br>";
Test(NotificationType::Warning());
【讨论】:
不错,尤其是考虑到NotificationType::Warning() == NotificationType::Warning()
。但是,有一个缺点,就是每次调用都会创建一个新对象。
创建一个新对象是一个巨大的缺点。枚举器背后的想法是这些常量易于访问。【参考方案5】:
提供了一个SplEnum
类。
文档中的示例用法:
<?php
class Month extends SplEnum
const __default = self::January;
const January = 1;
const February = 2;
const March = 3;
const April = 4;
const May = 5;
const June = 6;
const July = 7;
const August = 8;
const September = 9;
const October = 10;
const November = 11;
const December = 12;
echo new Month(Month::June) . PHP_EOL;
try
new Month(13);
catch (UnexpectedValueException $uve)
echo $uve->getMessage() . PHP_EOL;
上面的例子会输出
6
Value not a const in enum Month
另一种可能是使用myclabs/php-enum 包。
【讨论】:
【参考方案6】:你可以使用常量
class myClass
const aValue = 123;
const aString = "ABC";
;
但它不会提供一个很好的方式来遍历它们,所以我可能会选择一个关联数组,因为它更容易管理:
class myClass
$enum = array ("first" => 123,
"second" => "ABC");
【讨论】:
【参考方案7】:一个便宜的技巧是创建一个包含可能值的数组。但是,与上述答案不同,我会选择键/值对相等的数组,即:
<?php
$enum = Array(
'apple' => 'apple',
'pear' => 'pear',
'orange' => 'orange'
);
?>
这样,如果($enum[$value] != $value)
,你知道给定的值不在集合中。
当然,如果您希望键/值对不同,则可以使用常规数组。
【讨论】:
【参考方案8】:作为一个数组。
$arr = array('A','B','C','D');
$find = 'A';
$key = array_search($find,$arr);
echo $arr[$key];
【讨论】:
【参考方案9】:就我而言,我需要存储在整个应用程序中使用的权限名称。我最终得到了一个基本枚举抽象类,它为枚举定义了几个实用函数,然后对其进行了扩展。这是基本枚举类:
<?php
namespace App\Enums;
use ReflectionClass;
abstract class BasicEnum
private static $constCacheArray = NULL;
public static function getConstants()
if (self::$constCacheArray == NULL)
self::$constCacheArray = [];
$calledClass = get_called_class();
if (!array_key_exists($calledClass, self::$constCacheArray))
$reflect = new ReflectionClass($calledClass);
self::$constCacheArray[$calledClass] = $reflect->getConstants();
return self::$constCacheArray[$calledClass];
public static function isValidName($name, $strict = false)
$constants = self::getConstants();
if ($strict)
return array_key_exists($name, $constants);
$keys = array_map('strtolower', array_keys($constants));
return in_array(strtolower($name), $keys);
public static function isValidValue($value, $strict = true)
$values = array_values(self::getConstants());
return in_array($value, $values, $strict);
以下是通过扩展抽象类创建的示例枚举:
<?php
namespace App\Enums;
class Permissions extends BasicEnum
const COMMENTS_CREATE = 'create comments';
const COMMENTS_VIEW = 'view comments';
const COMMENTS_EDIT = 'edit comments';
const COMMENTS_DELETE = 'delete comments';
const COMMENTS_RESTORE = 'restore comments';
const REACTIONS_CREATE = 'create reactions';
const REACTIONS_VIEW = 'view reactions';
const REACTIONS_EDIT = 'edit reactions';
const REACTIONS_DELETE = 'delete reactions';
const REACTIONS_RESTORE = 'restore reactions';
const QUESTIONS_CREATE = 'create questions';
const QUESTIONS_VIEW = 'view questions';
const QUESTIONS_EDIT = 'edit questions';
const QUESTIONS_DELETE = 'delete questions';
const QUESTIONS_RESTORE = 'restore questions';
const PERMISSIONS_CREATE = 'create permissions';
const PERMISSIONS_VIEW = 'view permissions';
const PERMISSIONS_EDIT = 'edit permissions';
const PERMISSIONS_DELETE = 'delete permissions';
const PERMISSIONS_RESTORE = 'restore permissions';
<?php
namespace App\Enums;
class PostTypes extends BasicEnum
const POST = 'post';
const NEWS = 'news';
const SERVICE = 'service';
下面是 Permissions 枚举的示例用法:
/**
* Determine whether the user can create reactions.
*
* @param User $user
* @return mixed
*/
public function create(User $user)
return $user->can(Permissions::REACTIONS_CREATE);
希望这会有所帮助。
【讨论】:
以上是关于如何在 PHP 中实现类似 Enum 的功能? [复制]的主要内容,如果未能解决你的问题,请参考以下文章