eloquent / enumeration
PHP 的枚举实现。
Requires
- php: >=7.1
Requires (Dev)
- phpunit/phpunit: ^7
README
不再维护
此包不再维护。更多信息请参阅 此声明。
枚举
PHP 的枚举实现。
安装
- 作为 Composer 包 eloquent/enumeration 提供。
什么是枚举?
在软件开发中,枚举(或“枚举类型”)本质上是一组固定的值。这些值称为“成员”或“元素”。
枚举用于希望允许参数仅为特定值集合中的一个,并且其他任何内容都被视为无效的情况。
基本示例
枚举 可以像 C++ 枚举类型 一样使用。以下是一个示例,表示一组 HTTP 请求方法
use Eloquent\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... }
访问枚举成员
通过静态方法调用访问成员,如下所示
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 Eloquent\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); // 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 Eloquent\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... }