我知道PHP还没有本地枚举。但是我已经习惯了来自Java世界的它们。我喜欢使用枚举来提供ide的自动补全功能能够理解的预定义值。
常量可以解决这个问题,但是存在名称空间冲突问题,而且(实际上是因为)它们是全局的。数组没有名称空间的问题,但是它们太模糊了,它们可以在运行时被覆盖,而且ide很少知道如何在没有额外的静态分析注释或属性的情况下自动填充它们的键。
你有什么常用的解决方案/变通办法吗?有人记得PHP的人对枚举有什么想法或决定吗?
我知道PHP还没有本地枚举。但是我已经习惯了来自Java世界的它们。我喜欢使用枚举来提供ide的自动补全功能能够理解的预定义值。
常量可以解决这个问题,但是存在名称空间冲突问题,而且(实际上是因为)它们是全局的。数组没有名称空间的问题,但是它们太模糊了,它们可以在运行时被覆盖,而且ide很少知道如何在没有额外的静态分析注释或属性的情况下自动填充它们的键。
你有什么常用的解决方案/变通办法吗?有人记得PHP的人对枚举有什么想法或决定吗?
当前回答
我所见过的PHP中枚举最常见的解决方案是创建一个通用枚举类,然后扩展它。你可以看看这个。
更新:或者,我从phpclasses.org找到了这个。
其他回答
最后,PHP 7.1+给出了一个不能被重写的常量。
/**
* An interface that groups HTTP Accept: header Media Types in one place.
*/
interface MediaTypes
{
/**
* Now, if you have to use these same constants with another class, you can
* without creating funky inheritance / is-a relationships.
* Also, this gets around the single inheritance limitation.
*/
public const HTML = 'text/html';
public const JSON = 'application/json';
public const XML = 'application/xml';
public const TEXT = 'text/plain';
}
/**
* An generic request class.
*/
abstract class Request
{
// Why not put the constants here?
// 1) The logical reuse issue.
// 2) Single Inheritance.
// 3) Overriding is possible.
// Why put class constants here?
// 1) The constant value will not be necessary in other class families.
}
/**
* An incoming / server-side HTTP request class.
*/
class HttpRequest extends Request implements MediaTypes
{
// This class can implement groups of constants as necessary.
}
如果您使用的是名称空间,那么代码补全应该可以工作。
但是,这样做将失去在类族(protected)或单独在类(private)中隐藏常量的能力。根据定义,接口中的所有内容都是公共的。
PHP手册:接口
更新:
PHP 8.1现在有了枚举。
上面的答案太棒了。但是,如果以两种不同的方式进行扩展,那么无论先进行哪种扩展,都会导致对函数的调用,从而创建缓存。这个缓存将被所有后续调用使用,无论调用是由哪个扩展发起的…
要解决这个问题,将变量和第一个函数替换为:
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];
}
我试图用PHP创建一个枚举…这是非常有限的,因为它不支持对象作为枚举值,但仍然有点有用…
class ProtocolsEnum {
const HTTP = '1';
const HTTPS = '2';
const FTP = '3';
/**
* Retrieve an enum value
* @param string $name
* @return string
*/
public static function getValueByName($name) {
return constant('self::'. $name);
}
/**
* Retrieve an enum key name
* @param string $code
* @return string
*/
public static function getNameByValue($code) {
foreach(get_class_constants() as $key => $val) {
if($val == $code) {
return $key;
}
}
}
/**
* Retrieve associate array of all constants (used for creating droplist options)
* @return multitype:
*/
public static function toArray() {
return array_flip(self::get_class_constants());
}
private static function get_class_constants()
{
$reflect = new ReflectionClass(__CLASS__);
return $reflect->getConstants();
}
}
昨天我在博客上写了这门课。我认为在php脚本中使用它可能很容易:
final class EnumException extends Exception{}
abstract class Enum
{
/**
* @var array ReflectionClass
*/
protected static $reflectorInstances = array();
/**
* Массив конфигурированного объекта-константы enum
* @var array
*/
protected static $enumInstances = array();
/**
* Массив соответствий значение->ключ используется для проверки -
* если ли константа с таким значением
* @var array
*/
protected static $foundNameValueLink = array();
protected $constName;
protected $constValue;
/**
* Реализует паттерн "Одиночка"
* Возвращает объект константы, но но как объект его использовать не стоит,
* т.к. для него реализован "волшебный метод" __toString()
* Это должно использоваться только для типизачии его как параметра
* @paradm Node
*/
final public static function get($value)
{
// Это остается здесь для увеличения производительности (по замерам ~10%)
$name = self::getName($value);
if ($name === false)
throw new EnumException("Неизвестая константа");
$className = get_called_class();
if (!isset(self::$enumInstances[$className][$name]))
{
$value = constant($className.'::'.$name);
self::$enumInstances[$className][$name] = new $className($name, $value);
}
return self::$enumInstances[$className][$name];
}
/**
* Возвращает массив констант пар ключ-значение всего перечисления
* @return array
*/
final public static function toArray()
{
$classConstantsArray = self::getReflectorInstance()->getConstants();
foreach ($classConstantsArray as $k => $v)
$classConstantsArray[$k] = (string)$v;
return $classConstantsArray;
}
/**
* Для последующего использования в toArray для получения массива констант ключ->значение
* @return ReflectionClass
*/
final private static function getReflectorInstance()
{
$className = get_called_class();
if (!isset(self::$reflectorInstances[$className]))
{
self::$reflectorInstances[$className] = new ReflectionClass($className);
}
return self::$reflectorInstances[$className];
}
/**
* Получает имя константы по её значению
* @param string $value
*/
final public static function getName($value)
{
$className = (string)get_called_class();
$value = (string)$value;
if (!isset(self::$foundNameValueLink[$className][$value]))
{
$constantName = array_search($value, self::toArray(), true);
self::$foundNameValueLink[$className][$value] = $constantName;
}
return self::$foundNameValueLink[$className][$value];
}
/**
* Используется ли такое имя константы в перечислении
* @param string $name
*/
final public static function isExistName($name)
{
$constArray = self::toArray();
return isset($constArray[$name]);
}
/**
* Используется ли такое значение константы в перечислении
* @param string $value
*/
final public static function isExistValue($value)
{
return self::getName($value) === false ? false : true;
}
final private function __clone(){}
final private function __construct($name, $value)
{
$this->constName = $name;
$this->constValue = $value;
}
final public function __toString()
{
return (string)$this->constValue;
}
}
用法:
class enumWorkType extends Enum
{
const FULL = 0;
const SHORT = 1;
}
我在github上找到了这个库,我认为它提供了一个非常不错的答案。
PHP枚举实现灵感来自脾
你可以输入:function setAction(Action $ Action) { 你可以用方法丰富枚举(例如format, parse,…) 您可以扩展枚举以添加新值(将枚举设置为final以防止出现这种情况) 您可以得到所有可能值的列表(见下面)
宣言
<?php
use MyCLabs\Enum\Enum;
/**
* Action enum
*/
class Action extends Enum
{
const VIEW = 'view';
const EDIT = 'edit';
}
使用
<?php
$action = new Action(Action::VIEW);
// or
$action = Action::VIEW();
类型提示枚举值:
<?php
function setAction(Action $action) {
// ...
}