tlr/enum

此包已被弃用且不再维护。未建议替代包。

基于myclabs/enum针对laravel优化的enum包

v3.0.0 2021-07-26 15:18 UTC

This package is auto-updated.

Last update: 2021-07-26 15:20:55 UTC


README

Build Status

弃用

** 此包已被弃用,因为PHP 8.1将支持原生的/基本枚举类型,并解决了此包旨在解决的90%的问题。**

源代码将无限期保留,供已使用此库的人使用。

简介

一个原始的PHP枚举/标志库。在很大程度上基于myclabs/php-enum(我没有分叉,因为我对核心类做了一些细微的修改)。

支持Laravel(以及Nova)。

主要功能

  • 可实例化、可类型提示的枚举。
  • 标志枚举类型(用于与标志和掩码一起使用/操作)。

针对Laravel的主要功能

  • 枚举验证规则。
  • 从枚举中获取显示值的有用工具。
  • 用于Eloquent的使用获取器和设置器。
  • 为Laravel Nova提供的简单枚举字段。

安装

composer require tlr/enum

如果您使用的是Laravel且启用了包自动检测,那么您已经设置好了。如果没有,请将 Tlr\Phpnum\Laravel\EnumServiceProvider 添加到您的已加载服务提供者。

什么是枚举?

一个枚举值 - 它是代表在具体值列表中的一个可能值的值。它允许您定义一个特定的值列表,并确信您的枚举符合该列表。

考虑以下函数

function createNewArticle(string $type) {
    // ...
}

可以将任何字符串传递给此函数 - 'article'、'recipe'、'monkeys',尽管处理许多可能类型可能很简单,但您始终必须处理不存在的任何类型。

枚举允许您从代码中定义的预定义值列表中对值进行类型提示,因此您可以确保您正在处理离散(有限)的选择值(在这种情况下是类型)。例如...

基本用法(枚举)

我个人将一个应用命名空间专门用于项目中所有枚举,并且为了这些示例,我将使用App\Values作为枚举的命名空间。

<?php

namespace App\Values;

use Tlr\Phpnum\Enum;

class ArticleType extends Enum 
{
    const BLOG_POST   = 'blog';
    const REVIEW      = 'review';
    const RECIPE      = 'recipe';
    const CODE_SAMPLE = 'code';
}
use App\Values\ArticleType;

$type = ArticleType::REVIEW();

$type->value(); // 'review'
$type->is($type); // true
$type->is(ArticleType::RECIPE()); // false

$typeFromDb = new ArticleType('review');
$type->is($typeFromDb); // true

new ArticleType('bleh'); // throws exception - not in enum

// ...

function createNewArticle(ArticleType $type) {
    if($type->is(ArticleType::RECIPE())) {
        // do something here...
    }

    switch($type->value()) {
        case ArticleType::RECIPE():
        case ArticleType::BLOG_POST():
            break;
    }
}

完整文档(枚举)

设置

您可以通过三种方式声明枚举的值

如上所述 - 使用const声明在声明类时。这可能是声明枚举的“默认”方式。

class ArticleType extends Enum 
{
    const BLOG_POST   = 'blog';
    const REVIEW      = 'review';
    const RECIPE      = 'recipe';
    const CODE_SAMPLE = 'code';
}

$enum静态变量中。

class ArticleType extends Enum 
{
    protected static $enum = [
        'BLOG_POST'   = 'blog',
        'REVIEW'      = 'review',
        'RECIPE'      = 'recipe',
        'CODE_SAMPLE' = 'code',
    ];
}

重写generateEnums方法(默认实现定义了上述两种声明值的方式)。这可以用于从数据库等加载值,应该小心使用。此方法将仅调用一次,因为其结果被缓存。

class ArticleType extends Enum
{
    /**
     * Get the values for the enum
     *
     * @return array
     */
    public static function generateEnums() : array
    {
        return [
            'BLOG_POST'   = 'blog',
            'REVIEW'      = 'review',
            'RECIPE'      = 'recipe',
            'CODE_SAMPLE' = 'code',
        ];
    }
}

实例化枚举

枚举实例化的两种主要方式是

您可以使用声明的任何枚举名称来静态实例化枚举实例。这在手动声明值时很有用,例如将其保存到数据库中。

ArticleType::REVIEW();

您可以将枚举的提供给构造函数。这在从数据库加载数据或从用户获取输入时很有用。

new ArticleType($request->input('article_type'));

您还可以使用all静态方法获取所有实例化的枚举列表

foreach(ArticleType::all() as $name => $enum) {
    echo "{$name} : {$enum->value()}";
}

获取枚举信息

您可以使用辅助方法从枚举中获取各种信息

$type = ArticleType::CODE_SAMPLE();

$type->value();        // 'code'
$type->name();         // 'CODE_SAMPLE'
$type->friendlyName(); // 'Code Sample'

可以使用friendlyName方法将值显示给用户。它将尝试将键名转换为单词,并首字母大写。您可以通过两种方式覆盖此方法

覆盖friendlifier静态方法。它将传递枚举的键名,并应返回其友好值。

protected static function friendlifier(string $name) : string;

覆盖friendlyNames静态方法,该方法应返回一个数组/映射,其中左侧是友好名称,右侧是普通值。

public static function friendlyNames() : array
{
    return [
        return [
            'Blog Post'   = 'blog',
            'Review'      = 'review',
            'Recipe'      = 'recipe',
            'Code Sample' = 'code',
        ];
    ];
}

比较枚举

您可以使用isequals方法(它们是相同的,两者都包含在内,以便在编写代码时更有语法/英语感)将任何枚举与另一个枚举进行比较。

$type = $request->input('type'); // 'review'
(new ArticleType($type))->is(ArticleType::REVIEW()); // true

此比较考虑了枚举的类名以及其值,因此不同的多个枚举不能与原始枚举进行交叉比较。

ArticleType::RECIPE()->is(SharedItemType::RECIPE()); // false

标志枚举

基本说明

标志(或位掩码)是许多编程语言的常见特性——PHP在标准库中使用一些位掩码常量——例如,请参见json_encode的第二个参数的例子

它们是一种枚举,其中每个值都是2的幂次(1,2,4,8,16等)。虽然标志在技术上只是一个整数值,但如果你用二进制表示这些整数,你会得到一些有趣的东西

  • 1 : 00001
  • 2 : 00010
  • 4 : 00100
  • 8 : 01000
  • 16 : 10000

如果你为每个位位置(从右到左)分配一个意义,那么你就有一种方法使用整数值来存储一组开关或标志。你可以将它们链接在一起——例如,整数500101——或1和4的组合;整数31是所有这些的组合;整数0是没有。

起初这可能会有些复杂,但一旦你对此有了一定的了解,标志就可以是一个非常强大的工具,允许你在单个参数中传递完整的选项开关集,而不会丢失任何上下文意义。在上面的例子中,我们可以为值分配一些名称(在这里,使用json_encode的例子——写作时的正确值)。

  • 1 : 00001 : JSON_HEX_TAG
  • 2 : 00010 : JSON_HEX_AMP
  • 4 : 00100 : JSON_HEX_APOS
  • 8 : 01000 : JSON_HEX_QUOT
  • 16 : 10000 : JSON_FORCE_OBJECT

您可以通过|运算符将前三个传递给json_encode,如下所示

$flag = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS;
json_encode([], $flag);

您可以使用&运算符检查标志是否匹配可能的标志值

$flag & JSON_HEX_AMP; // true
$flag & JSON_FORCE_OBJECT; // false

当然,您可以使用===检查它是否与确切集合匹配

$flag === JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS; // true
$flag === JSON_HEX_TAG; // false

您可以使用位运算符和标志做更多的事情,但这些是基础知识。

注意

一旦定义了标志值,在未来版本的应用程序中就不能更改。如果PHP决定删除JSON_HEX_AMP并添加一个新的可能开关,例如JSON_HEX_SPACE,他们必须将JSON_HEX_SPACE添加到值列表的末尾,并简单地不允许JSON_HEX_AMP的值,或者如果传递了它就忽略它(即,它会弃用2)。

标志应该用于不经常更改的核心事物。

标志和枚举

json_encode选项只是设置为特定值的常量(如上所述的2的幂)。使用此类包的标志的优点是,标志、值和验证都封装在一个对象中,使得定义、引用、验证和比较更容易。

上面使用的Flag类和Enum类共享相同的基类,因此几乎所有上面的内容都适用,只是定义上有一点差异,以及一些额外的比较方法。

定义标志

以一个非常简单的权限集为例。

class Permission extends Flag
{
    protected static $flags = [
        'MANAGE_STAFF',
        'MANAGE_RESEARCH_PROJECTS',
        'VIEW_SECRET_RESEARCH_PROJECTS',
        'VIEW_RESEARCH_REPORTS',
    ];
}

// in some code

$user->permissions = Permission::MANAGE_STAFF();
$reporter->permissions = Permission::VIEW_RESEARCH_REPORTS();

使用标志的掩码

以下都是相同的

$user->permissions = Permission::MANAGE_STAFF();
$user->permissions = new Permission(0b0001);
$user->permissions = new Permission(1); // although you would probably get this from some user input.

如果我们只能设置用户能够做上述其中之一,那么将会有些限制。我们可以像这样给一个值分配多个标志

// The following are equivalent:
$user->permissions = Permission::combineFlags([
    Permission::VIEW_SECRET_RESEARCH_PROJECTS(),
    Permission::VIEW_RESEARCH_REPORTS(),
]);

$user->permissions = new Permission(
    Permission::VIEW_SECRET_RESEARCH_PROJECTS()->value() | Permission::VIEW_RESEARCH_REPORTS()
);

$user->permissions = new Permission(0b1100);
$user->permissions = new Permission(12);

比较标志

除了枚举比较方法(如$enum->is($other))之外,还有一些专门针对标志的方法。

// @todo - 比较

// @todo - 读取

Laravel

// @todo

验证规则

// @todo

Nova字段

// @todo