项目作者: ekvedaras

项目描述 :
🔠 PHP enum implementation
高级语言: PHP
项目地址: git://github.com/ekvedaras/php-enum.git
创建时间: 2020-08-29T09:58:05Z
项目社区:https://github.com/ekvedaras/php-enum

开源协议:MIT License

下载


PHP Enum

Tests
Code Coverage
Software License
Latest Version on Packagist
Total Downloads

Twitter Follow

Big thanks happy-types/enumerable-type for the original idea. Take a look if it suits your needs better.

This package adds meta field, provides a few more methods like options, keys, json, etc.
and there are simple php array, illuminate/collection, arrayy and doctrine collection implementations to choose from.

Benefits

  • Enums in general allow to avoid magic values#Unnamed_numerical_constants)
  • By type hinting forces only allowed values to be passed to methods (or returned)
  • Easy way to list all possible values
  • More feature rich and flexible then other enum implementations
  • Works with strict (===) operator
  • IDE friendly, so auto complete, usage analysis and refactorings all work

Defining enums

Create enums by extending one of:

  • EKvedaras\PHPEnum\PHPArray\Enum
  • EKvedaras\PHPEnum\Illuminate\Collection\Enum
  • EKvedaras\PHPEnum\Arrayy\Enum
  • EKvedaras\PHPEnum\Doctrine\Enum
  1. use EKvedaras\PHPEnum\PHPArray\Enum;
  2. class PaymentStatus extends Enum
  3. {
  4. /**
  5. * @return static
  6. */
  7. final public static function pending(): self
  8. {
  9. return static::get('pending', 'Payment is pending');
  10. }
  11. /**
  12. * @return static
  13. */
  14. final public static function completed(): self
  15. {
  16. return static::get('completed', 'Payment has been processed');
  17. }
  18. /**
  19. * @return static
  20. */
  21. final public static function failed(): self
  22. {
  23. return static::get('failed', 'Payment has failed');
  24. }
  25. }

Integers can be used as IDs instead of string values if you prefer.

Usage

Retrieving and comparing enum values

  1. // Retrieving value statically
  2. $status1 = PaymentStatus::completed();
  3. // Retrieving value dynamically from ID
  4. $status2 = PaymentStatus::from('completed');
  5. // Strict comparison is supported
  6. var_dump($status1 === $status2); // true

Accessing value properties

  1. $status = PaymentStatus::copmleted();
  2. $status->id(); // 'completed'
  3. $status->name(); // 'Payment has been processed'
  4. $status->meta(); // null

Listing enum values

There are two implementations provided:

PHP array

To use PHP array your enums should extend EKvedaras\PHPEnum\PHPArray\Enum class

  1. var_dump(PaymentStatus::enum());
  2. /*
  3. array(3) {
  4. 'pending' =>
  5. class PaymentStatus#12 (3) {
  6. protected $id =>
  7. string(7) "pending"
  8. protected $name =>
  9. string(18) "Payment is pending"
  10. protected $meta =>
  11. NULL
  12. }
  13. 'completed' =>
  14. class PaymentStatus#363 (3) {
  15. protected $id =>
  16. string(9) "completed"
  17. protected $name =>
  18. string(26) "Payment has been processed"
  19. protected $meta =>
  20. NULL
  21. }
  22. 'failed' =>
  23. class PaymentStatus#13 (3) {
  24. protected $id =>
  25. string(6) "failed"
  26. protected $name =>
  27. string(18) "Payment has failed"
  28. protected $meta =>
  29. NULL
  30. }
  31. }
  32. */
  1. var_dump(PaymentStatus::options());
  2. /*
  3. array(3) {
  4. 'pending' =>
  5. string(18) "Payment is pending"
  6. 'completed' =>
  7. string(26) "Payment has been processed"
  8. 'failed' =>
  9. string(18) "Payment has failed"
  10. }
  11. */
  1. var_dump(PaymentStatus::keys());
  2. /*
  3. array(3) {
  4. [0] =>
  5. string(7) "pending"
  6. [1] =>
  7. string(9) "completed"
  8. [2] =>
  9. string(6) "failed"
  10. }
  11. */
  1. var_dump(PaymentStatus::json()); // Will include meta if defined
  1. {
  2. "pending": {
  3. "id": "pending",
  4. "name": "Payment is pending"
  5. },
  6. "completed": {
  7. "id": "completed",
  8. "name": "Payment has been processed"
  9. },
  10. "failed": {
  11. "id": "failed",
  12. "name": "Payment has failed"
  13. }
  14. }
  1. var_dump(PaymentStatus::jsonOptions());
  1. {
  2. "pending": "Payment is pending",
  3. "completed": "Payment has been processed",
  4. "failed": "Payment has failed"
  5. }

Illuminate Collection

Either illuminate/support or illuminate/collections package is required which is not installed by default.

To use Illuminate Collection your enums should extend EKvedaras\PHPEnum\Illuminate\Collection\Enum class.

The only difference is enum, options and keys methods will return Collection instances instead of arrays.
The rest works exactly the same.

  1. var_dump(PaymentStatus::enum());
  2. /*
  3. class Illuminate\Support\Collection#362 (1) {
  4. protected $items =>
  5. array(3) {
  6. 'pending' =>
  7. class PaymentStatus#12 (3) {
  8. protected $id =>
  9. string(7) "pending"
  10. protected $name =>
  11. string(18) "Payment is pending"
  12. protected $meta =>
  13. NULL
  14. }
  15. 'completed' =>
  16. class PaymentStatus#363 (3) {
  17. protected $id =>
  18. string(9) "completed"
  19. protected $name =>
  20. string(26) "Payment has been processed"
  21. protected $meta =>
  22. NULL
  23. }
  24. 'failed' =>
  25. class PaymentStatus#13 (3) {
  26. protected $id =>
  27. string(6) "failed"
  28. protected $name =>
  29. string(18) "Payment has failed"
  30. protected $meta =>
  31. NULL
  32. }
  33. }
  34. }
  35. */
  1. var_dump(PaymentStatus::options());
  2. /*
  3. class Illuminate\Support\Collection#368 (1) {
  4. protected $items =>
  5. array(3) {
  6. 'pending' =>
  7. string(18) "Payment is pending"
  8. 'completed' =>
  9. string(26) "Payment has been processed"
  10. 'failed' =>
  11. string(18) "Payment has failed"
  12. }
  13. }
  14. */
  1. var_dump(PaymentStatus::keys());
  2. /*
  3. class Illuminate\Support\Collection#13 (1) {
  4. protected $items =>
  5. array(3) {
  6. [0] =>
  7. string(7) "pending"
  8. [1] =>
  9. string(9) "completed"
  10. [2] =>
  11. string(6) "failed"
  12. }
  13. }
  14. */

Meta

Meta field is intentionally left as mixed type as it could be used for various reasons.
For example linking enum options with a specific implementation:

  1. use EKvedaras\PHPEnum\PHPArray\Enum;
  2. class PaymentMethod extends Enum
  3. {
  4. final public static function payPal(): self
  5. {
  6. return static::get('paypal', 'PayPal', PayPalHandler::class);
  7. }
  8. final public static function stripe(): self
  9. {
  10. return static::get('stripe', 'Stripe', StripeHandler::class);
  11. }
  12. }

Resolving payment handler in Laravel:

  1. $method = PaymentMethod::from($request['method_id']);
  2. $handler = app($method->meta());

Meta could also be used as a more in detail description of each option that could be displayed to users
or some other object linking other classes, resources together.

Furthermore, in some cases it is useful to resolve enum option from meta. That is also possible:

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

Things to know

final public static function

Only methods marked as final public static will be considered as possible values of enum. Other methods are still there, but
they will not be returned in enum / keys / options, etc. results and won’t be considered as valid values. However, this allows
to extend enums and make them more useful. For example:

  1. use EKvedaras\PHPEnum\Illuminate\Collection\Enum;
  2. use Illuminate\Support\Collection;
  3. class PaymentMethods extends Enum
  4. {
  5. /**
  6. * @return static
  7. */
  8. final public static function payPal(): self
  9. {
  10. return static::get('paypal', 'PayPal');
  11. }
  12. /**
  13. * @return static
  14. */
  15. final public static function stripe(): self
  16. {
  17. return static::get('stripe', 'Stripe');
  18. }
  19. /**
  20. * @return static
  21. */
  22. final public static function mollie(): self
  23. {
  24. return static::get('mollie', 'Mollie');
  25. }
  26. /**
  27. * Returns only enabled payment methods. Useful for validation or rendering payments UI
  28. * @return Collection|static[]
  29. */
  30. public static function enabled(): Collection
  31. {
  32. return static::enum()->only(config('payments.enabled'));
  33. }
  34. }

from($id) only allows valid IDs

Well, this is expected. Calling PaymentMethod::from('ideal') will throw OutOfBoundsException.

No serialization

Enum object instances cannot be serialized. Deserialized objects would get a different address in memory therefore, === would no longer work.
Calling serialize(PaymentMethod::stripe()) will throw a RuntimeException.

As a workaround it is better to store the ID instead of object itself. You still get the bonus of setters only accepting valid values.

  1. class Payment
  2. {
  3. /** @var string */
  4. private $method;
  5. public function setMethod(PaymentMethod $method)
  6. {
  7. $this->method = $method->id();
  8. }
  9. public function getMethod(): PaymentMethod
  10. {
  11. return PaymentMethod::from($this->method);
  12. }
  13. }

Don’t mix implementations

Enum instances cache is stored in a static variable. Choose one implementation for your project
and stick to it, otherwise you may unexpectedly get errors because types don’t match.

You may create your own project enum class and extend your chosen implementation, so if it ever needs to be
changed it can be done in one place only (if storage APIs match).

Changelog

See changes in changelog files: