梦游者 / 枚举
PHP的枚举实现,由eloquent/enumeration派生。
Requires
- php: >=8.1
Requires (Dev)
- phpunit/phpunit: ^10.4
README
为PHP提供比PHP 8+的enum更广泛的枚举支持。该项目是eloquent/enumeration的延续。
安装
什么是枚举?
在软件开发中,枚举(或“枚举类型”)本质上是一组固定的值。这些值被称为“成员”或“元素”。
枚举用于需要允许参数只属于一组特定值的情况,其他任何值都被视为无效。
基本示例
枚举可以像C++枚举类型一样使用。以下是一个示例,表示一组HTTP请求方法
use Somnambulist\Enumeration\AbstractEnumeration; final class HttpRequestMethod extends AbstractEnumeration { const OPTIONS = 'OPTIONS'; const GET = 'GET'; const HEAD = 'HEAD'; const POST = 'POST'; const PUT = 'PUT'; const DELETE = 'DELETE'; const TRACE = 'TRACE'; const CONNECT = 'CONNECT'; }
现在可以使用这个类在类型提示中轻松接受任何有效的HTTP请求方法
function handleHttpRequest(HttpRequestMethod $method, $url, $body = null) { // handle request... }
注意:对于简单的枚举,建议使用PHP的本地枚举。
访问枚举成员
成员通过静态方法调用访问,如下所示
handleHttpRequest(HttpRequestMethod::GET(), 'http://example.org/'); handleHttpRequest(HttpRequestMethod::POST(), 'http://example.org/', 'foo=bar&baz=qux');
对于枚举的每个成员,都会实例化一个枚举类的单个实例(即在上述示例中的HttpRequestMethod
实例)。这意味着可以使用严格的比较(===)来确定传递给函数的是哪个成员
function handleHttpRequest(HttpRequestMethod $method, $url, $body = null) { if ($method === HttpRequestMethod::POST()) { // handle POST requests... } else { // handle other requests... } }
Java风格的枚举
Java的枚举类型比C++枚举类型有更多功能。它们可以有额外的属性和/或方法,并且实际上只是固定实例集的专用类。
这有时被称为Multiton模式,实际上,此实现中的所有枚举都是Multitons。《AbstractEnumeration》类仅根据类常量定义其成员。
以下是一个从Java枚举类型文档中借用示例。以下Multiton描述了我们太阳系中的所有行星,包括它们的质量和半径
use Somnambulist\Enumeration\AbstractMultiton; final class Planet extends AbstractMultiton { /** * Universal gravitational constant. * * @var float */ const G = 6.67300E-11; /** * @return float */ public function surfaceGravity() { return self::G * $this->mass / ($this->radius * $this->radius); } /** * @param float $otherMass * * @return float */ public function surfaceWeight($otherMass) { return $otherMass * $this->surfaceGravity(); } protected static function initializeMembers() { new static('MERCURY', 3.302e23, 2.4397e6); new static('VENUS', 4.869e24, 6.0518e6); new static('EARTH', 5.9742e24, 6.37814e6); new static('MARS', 6.4191e23, 3.3972e6); new static('JUPITER', 1.8987e27, 7.1492e7); new static('SATURN', 5.6851e26, 6.0268e7); new static('URANUS', 8.6849e25, 2.5559e7); new static('NEPTUNE', 1.0244e26, 2.4764e7); // Pluto will always be a planet to me! new static('PLUTO', 1.31e22, 1.180e6); } /** * @param string $key * @param float $mass * @param float $radius */ protected function __construct($key, $mass, $radius) { parent::__construct($key); $this->mass = $mass; $this->radius = $radius; } private $mass; private $radius; }
上面的类可以用来接受地球上的已知重量(以任何单位),并计算所有行星上的重量(以相同单位)
$earthWeight = 175; $mass = $earthWeight / Planet::EARTH()->surfaceGravity(); foreach (Planet::members() as $planet) { echo sprintf( 'Your weight on %s is %f' . PHP_EOL, $planet, $planet->surfaceWeight($mass) ); }
如果上述脚本执行,将产生如下类似输出
Your weight on MERCURY is 66.107480
Your weight on VENUS is 158.422560
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279359
Your weight on JUPITER is 442.677903
Your weight on SATURN is 186.513785
Your weight on URANUS is 158.424919
Your weight on NEPTUNE is 199.055584
枚举和类继承
定义枚举时,通常的意图是定义一组不应改变的合法值,至少在程序执行的生命周期内。
由于PHP没有内置的枚举支持,因此此库将其实现为常规PHP类。然而,类允许比真正的枚举所需的更多可扩展性。
例如,一个简单的枚举实现可能允许开发者扩展上述示例中的HttpRequestMethod
类(假设移除了final
关键字)
class CustomHttpMethod extends HttpRequestMethod { const PATCH = 'PATCH'; }
这种场景的问题在于,所有只期望在 HttpRequestMethod
中定义的 HTTP 方法代码现在都受到了影响。任何人都可以扩展 HttpRequestMethod
来添加自定义值,实际上取消了最初定义 HttpRequestMethod
的原因。
这个库提供了对这些情况的内置保护。尝试定义一个扩展另一个枚举类型的枚举将会抛出异常,除非“基础”枚举是抽象的。
抽象枚举
假设确实需要扩展 HttpRequestMethod
,可以通过定义一个抽象基类来实现,然后扩展这个类来创建所需的具体枚举。
use Somnambulist\Enumeration\AbstractEnumeration; abstract class AbstractHttpRequestMethod extends AbstractEnumeration { const OPTIONS = 'OPTIONS'; const GET = 'GET'; const HEAD = 'HEAD'; const POST = 'POST'; const PUT = 'PUT'; const DELETE = 'DELETE'; const TRACE = 'TRACE'; const CONNECT = 'CONNECT'; } final class HttpRequestMethod extends AbstractHttpRequestMethod {} final class CustomHttpMethod extends AbstractHttpRequestMethod { const PATCH = 'PATCH'; }
这样,当开发人员使用 HttpRequestMethod
的类型提示时,他们永远不会接收到‘PATCH’方法。
function handleHttpRequest(HttpRequestMethod $method, $url, $body = null) { // only handles normal requests... } function handleCustomHttpRequest( CustomHttpRequestMethod $method, $url, $body = null ) { // handles normal requests, and custom requests... }