ekvedaras/php-enum

PHP 枚举实现

v1.3.0 2020-12-30 10:37 UTC

This package is auto-updated.

Last update: 2024-08-29 05:53:25 UTC


README

Tests Code Coverage Software License Latest Version on Packagist Total Downloads

Twitter Follow

非常感谢happy-types/enumerable-type的原始想法。如果您需要更好的解决方案,请查看。

此包添加了meta字段,提供了一些额外的方法,如optionskeysjson等,并且有简单的php数组、illuminate/collectionarrayydoctrine集合实现可供选择。

优势

  • 枚举通常可以避免魔法值
  • 通过类型提示强制将仅允许的值传递给方法(或返回)
  • 列出所有可能值的一种简单方法
  • 比其他枚举实现更丰富和灵活
  • 与严格的(===)运算符一起工作
  • IDE友好,因此自动完成、使用分析和重构都可以工作

定义枚举

通过扩展以下之一来创建枚举

  • EKvedaras\PHPEnum\PHPArray\Enum
  • EKvedaras\PHPEnum\Illuminate\Collection\Enum
  • EKvedaras\PHPEnum\Arrayy\Enum
  • EKvedaras\PHPEnum\Doctrine\Enum
use EKvedaras\PHPEnum\PHPArray\Enum;

class PaymentStatus extends Enum 
{
    /**
     * @return static
     */
    final public static function pending(): self
    {
        return static::get('pending', 'Payment is pending');
    }

    /**
     * @return static
     */
    final public static function completed(): self
    {
        return static::get('completed', 'Payment has been processed');
    }
    
    /**
     * @return static
     */
    final public static function failed(): self
    {
        return static::get('failed', 'Payment has failed');
    }
}

如果您喜欢,可以使用整数作为ID而不是字符串值。

用法

检索和比较枚举值

// Retrieving value statically
$status1 = PaymentStatus::completed();

// Retrieving value dynamically from ID
$status2 = PaymentStatus::from('completed');

// Strict comparison is supported
var_dump($status1 === $status2); // true

访问值属性

$status = PaymentStatus::copmleted();

$status->id();   // 'completed'
$status->name(); // 'Payment has been processed'
$status->meta(); // null

列出枚举值

提供了两种实现

PHP数组

要使用PHP数组,您的枚举应扩展EKvedaras\PHPEnum\PHPArray\Enum

var_dump(PaymentStatus::enum());
/*
array(3) {
  'pending' =>
  class PaymentStatus#12 (3) {
    protected $id =>
    string(7) "pending"
    protected $name =>
    string(18) "Payment is pending"
    protected $meta =>
    NULL
  }
  'completed' =>
  class PaymentStatus#363 (3) {
    protected $id =>
    string(9) "completed"
    protected $name =>
    string(26) "Payment has been processed"
    protected $meta =>
    NULL
  }
  'failed' =>
  class PaymentStatus#13 (3) {
    protected $id =>
    string(6) "failed"
    protected $name =>
    string(18) "Payment has failed"
    protected $meta =>
    NULL
  }
}
 */
var_dump(PaymentStatus::options());
/*
array(3) {
  'pending' =>
  string(18) "Payment is pending"
  'completed' =>
  string(26) "Payment has been processed"
  'failed' =>
  string(18) "Payment has failed"
}
*/
var_dump(PaymentStatus::keys());
/*
array(3) {
  [0] =>
  string(7) "pending"
  [1] =>
  string(9) "completed"
  [2] =>
  string(6) "failed"
}
*/
var_dump(PaymentStatus::json()); // Will include meta if defined
{
    "pending": {
        "id": "pending",
        "name": "Payment is pending"
    },
    "completed": {
        "id": "completed",
        "name": "Payment has been processed"
    },
    "failed": {
        "id": "failed",
        "name": "Payment has failed"
    }
}
var_dump(PaymentStatus::jsonOptions());
{
    "pending": "Payment is pending",
    "completed": "Payment has been processed",
    "failed": "Payment has failed"
}

Illuminate Collection

需要illuminate/supportilluminate/collections包,该包默认未安装。

要使用Illuminate Collection,您的枚举应扩展EKvedaras\PHPEnum\Illuminate\Collection\Enum类。

唯一的区别是enumoptionskeys方法将返回Collection实例而不是数组。其余部分工作方式完全相同。

var_dump(PaymentStatus::enum());
/*
class Illuminate\Support\Collection#362 (1) {
  protected $items =>
  array(3) {
    'pending' =>
    class PaymentStatus#12 (3) {
      protected $id =>
      string(7) "pending"
      protected $name =>
      string(18) "Payment is pending"
      protected $meta =>
      NULL
    }
    'completed' =>
    class PaymentStatus#363 (3) {
      protected $id =>
      string(9) "completed"
      protected $name =>
      string(26) "Payment has been processed"
      protected $meta =>
      NULL
    }
    'failed' =>
    class PaymentStatus#13 (3) {
      protected $id =>
      string(6) "failed"
      protected $name =>
      string(18) "Payment has failed"
      protected $meta =>
      NULL
    }
  }
}
 */
var_dump(PaymentStatus::options());
/*
class Illuminate\Support\Collection#368 (1) {
  protected $items =>
  array(3) {
    'pending' =>
    string(18) "Payment is pending"
    'completed' =>
    string(26) "Payment has been processed"
    'failed' =>
    string(18) "Payment has failed"
  }
}
*/
var_dump(PaymentStatus::keys());
/*
class Illuminate\Support\Collection#13 (1) {
  protected $items =>
  array(3) {
    [0] =>
    string(7) "pending"
    [1] =>
    string(9) "completed"
    [2] =>
    string(6) "failed"
  }
}
*/

元数据

元数据字段有意保留为混合类型,因为它可以用于各种原因。例如,将枚举选项与特定实现相关联

use EKvedaras\PHPEnum\PHPArray\Enum;

class PaymentMethod extends Enum
{
    final public static function payPal(): self
    {
        return static::get('paypal', 'PayPal', PayPalHandler::class);
    }
    
    final public static function stripe(): self
    {
        return static::get('stripe', 'Stripe', StripeHandler::class);
    }
}

在Laravel中解决支付处理器

$method = PaymentMethod::from($request['method_id']);

$handler = app($method->meta());

元数据也可以用作每个选项的更详细描述,可以显示给用户或链接其他类的某些其他对象。

此外,在某些情况下,从元数据中解决枚举选项很有用。这也是可能的

$method = PaymentMethod::fromMeta(StripeHandler::class);

需要注意的事项

final public static function

只有标记为final public static的方法才会被视为枚举的可能值。其他方法仍然存在,但它们不会在enum / keys / options等结果中返回,也不会被视为有效值。然而,这允许扩展枚举并使其更有用。例如

use EKvedaras\PHPEnum\Illuminate\Collection\Enum;
use Illuminate\Support\Collection;

class PaymentMethods extends Enum
{
    /**
     * @return static
     */
    final public static function payPal(): self
    {
        return static::get('paypal', 'PayPal');
    }
    
    /**
     * @return static
     */
    final public static function stripe(): self
    {
        return static::get('stripe', 'Stripe');
    }
    
    /**
     * @return static
     */
    final public static function mollie(): self
    {
        return static::get('mollie', 'Mollie');
    }
    
    /**
     * Returns only enabled payment methods. Useful for validation or rendering payments UI
     * @return Collection|static[]
     */
    public static function enabled(): Collection
    {
        return static::enum()->only(config('payments.enabled'));
    }
}

from($id)仅允许有效的ID

嗯,这是预期的。调用PaymentMethod::from('ideal')将抛出OutOfBoundsException

不可序列化

枚举对象实例不能序列化。反序列化对象会在内存中获得不同的地址,因此,===将不再工作。调用serialize(PaymentMethod::stripe())将抛出RuntimeException

作为解决方案,最好存储ID而不是对象本身。您仍然可以获得仅接受有效值的设置器的额外好处。

class Payment 
{
    /** @var string */
    private $method;

    public function setMethod(PaymentMethod $method)
    {
        $this->method = $method->id();
    }
    
    public function getMethod(): PaymentMethod
    {
        return PaymentMethod::from($this->method);
    }
}

不要混合实现

枚举实例缓存存储在静态变量中。为您的项目选择一个实现并坚持使用它,否则您可能会意外地遇到由于类型不匹配而引起的错误。

您可以创建自己的项目枚举类,并扩展您选择的实现,这样如果需要更改,只需在一个地方进行(如果存储API匹配)。

相关包

变更日志

查看变更日志文件中的更改