此包已被弃用且不再维护。作者建议使用 ifornew/enum 包。

PHP 的枚举实现。

维护者

详情

git.ifornew.com/enum.git

主页

安装: 157

依赖: 0

建议者: 0

安全: 0

1.0.7 2021-03-26 03:20 UTC

This package is auto-updated.

Last update: 2022-06-29 08:22:04 UTC


README

PHP 的枚举实现。

安装和文档

什么是枚举?

在软件开发中,枚举(或“枚举类型”)本质上是一组固定的值。这些值被称为“成员”或“元素”。

枚举用于需要允许参数仅为特定集合中的一个值,并且其他任何值都被视为无效的情况。

一个基本示例

Enum 可以像 [C++ 枚举类型] 一样使用。以下是一个示例,表示一组 HTTP 请求方法

use Iwannamaybe\Enum\AbstractEnumeration;

/**
 * Class HttpMethod
 
 * @method static HttpMethod OPTIONS
 * @method static HttpMethod GET
 * @method static HttpMethod HEAD
 * @method static HttpMethod POST
 * @method static HttpMethod PUT
 * @method static HttpMethod DELETE
 * @method static HttpMethod TRACE
 * @method static HttpMethod CONNECT
 */
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 Iwannamaybe\Enum\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 类。然而,类允许比真正的枚举所需的更多扩展性。

例如,一个简单的枚举实现可能允许开发人员从上面的示例(假设移除了 final 关键字)扩展 HttpRequestMethod

class CustomHttpMethod extends HttpRequestMethod
{
    const PATCH = 'PATCH';
}

这种场景的问题在于,所有编写来仅期望在 HttpRequestMethod 中定义的 HTTP 方法代码现在都受到了损害。任何人都可以扩展 HttpRequestMethod 来添加自定义值,这实际上违背了最初定义 HttpRequestMethod 的原因。

此库提供内置保护以防止此类情况。尝试定义扩展另一个枚举的枚举将引发异常,除非“基础”枚举是抽象的。

抽象枚举

假设确实有扩展 HttpRequestMethod 的需求,处理方式是定义一个抽象基类,然后扩展这个类来创建所需的具体系列枚举

use Iwannamaybe\Enum\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...
}