Div PHP 枚举解决方案

1.0.2 2024-01-13 02:43 UTC

This package is auto-updated.

Last update: 2024-09-23 04:25:47 UTC


README

这是一个使用类和类型提示的 PHP 枚举解决方案。你也可以构建枚举的税onomies!

枚举类型,简称 "enum",是一种用于对命名值进行分类的数据类型。枚举可以用来代替硬编码的字符串,以结构化和类型化的方式表示,例如博客文章的状态。

2019 年 7 月,我写了一个 gist 来寻找这个解决方案。

https://gist.github.com/rafageist/aef9825b7c935cdeb0c6187a2d363909/revisions

然后我把 gist 转换成了真实项目。 https://www.phpclasses.org/package/11366-PHP-Implement-enumerated-values-using-classes.html

问题

在 8.1 之前,PHP 没有原生的枚举类型,只有一个非常基础的 SPL 实现 (https://php.ac.cn/manual/en/class.splenum.php),但这真的不够用。一些解决方案使用常量,但并没有解决问题。如何验证 HOT 或 COLD?

从 8.1 开始,PHP 有了一个枚举实现 (https://php.ac.cn/manual/en/language.types.enumerations.php)。

现在你可以结合 PHP 的新功能来使用这个解决方案。

<?php

const HOT = 1;
const COLD = 2;

const FIRE = 1;
const ICE = 2;

function doSomething(int $temperature) { /* ... */}

doSomething(FIRE);

有一个流行的包叫做 myclabs/php-enum。它真的很棒,但有一个问题,因为我们失去了静态分析的好处,比如自动完成和重构。

解决方案

使用 PHP!

divengine\enum 可以帮助你,但请记住:这个库最重要的解决方案是它的概念。

使用这个类,你可以解决以下问题

  1. 具有不同名称和相等值的常量可以作为函数参数使用
  2. 失去静态分析的好处,如自动完成和重构
  3. 在使用文档块类型提示解决第二个问题时,维护重复的代码

我们需要在 PHP 中有内置的枚举!但,现在,这是一个解决方案。

安装

Composer

composer require divengine\enum;

手动

克隆仓库

git clone https://github.com/divengine/enum

包含库

include "/path/to/divengine/enum/src/folder/enum.php";

示例

首先,定义你的枚举。你可以构建一个税onomies!

Enums.php

<?php

namespace MyEnums;

use divengine\enum;

class Temperature extends enum {/* Father of all types of temperatures */}
class ExtremeTemperature extends Temperature {/* Father of all types of extreme temperatures */}
class FIRE extends ExtremeTemperature {}
class ICE extends ExtremeTemperature {}

class NormalTemperature extends Temperature {/* Father of all types of normal temperatures */}
class HOT extends NormalTemperature {}
class COOL extends NormalTemperature {}
class COLD extends NormalTemperature {}

其次,使用你的枚举

<?php

use MyEnums;


// Constants are good tricks, but optional
const COOL = COOL::class;

class AllTemperatures {
    const COOL = COOL::class; // maybe better
    const HOT = 'Enums\\HOT';  // ugly !!!

    //...
}

// Define some function with type hinting
function WhatShouldIdo(Temperature $temperature)
{
    switch (true) {
        case $temperature instanceof ExtremeTemperature:
            switch (true) {
                case $temperature instanceof FIRE:
                    return "Call the fire department";

                case $temperature instanceof ICE:
                    return "Warm up";
            }
            break;

        case $temperature instanceof NormalTemperature:
            switch ($temperature) {

                case HOT::class: // compare using classname
                    return "Drink a beer :D";

                case COOL or AllTemperatures::COOL: // compare using constants
                    return "Just go away !";

                case 'Enums\\COLD': // compare using string, ugly !!!
                    return "Wear a coat";
            }

            break;
    }

    return "I don't know";
}

// Call to function with a instance of any Temperature
echo WhatShouldIdo(new HOT()) . PHP_EOL;

你喜欢 Java 编程语言吗?

实际上你可以使用枚举进行开关,但你不能在 Java 7 之前使用字符串进行开关。你可以考虑使用 Java 枚举的多态方法调度而不是显式的 switch。请注意,枚举在 Java 中是对象,而不是像 C/C++ 中的 int 的符号。你可以在枚举类型上有一个方法,然后而不是写一个 switch,只需调用该方法 - 一行代码:完成!

public enum Temperature {
    HOT {
        @Override
        public void whatShouldIdo() {
            System.out.println("Drink a bear!");
        }
    },
    COLD {
        @Override
        public void whatShouldIdo() {
             System.out.println("Wear a coat!");
        }
    };

    public abstract void whatShouldIdo();
}

// ...

void aMethodSomewhere(final Temperature temperature) {
    doSomeStuff();
    temperature.whatShouldIdo(); // here is where the switch would be, now it's one line of code!
    doSomeOtherStuff();
}

这种方法的一个好处是,你可以避免某些类型的错误。你不会错过一个 switch case(你可以为特定的常量错误地实现一个方法,但没有什么可以完全防止这种情况发生!)。没有 switch "default" 要担心。此外,我见过将枚举常量放入数组并将索引放入数组的代码 - 这打开了数组索引越界的异常的可能性 - 只需使用枚举!Java 枚举非常非常强大。了解有关它们的全部内容,以有效地使用它们。

此外,如果您有多个枚举常量,它们对某个特定方法具有相同的行为(例如星期几,周末的行为相同,以及星期二到星期四的工作日也具有相同的行为),您可以将这些共享代码简单地聚集在一个不会被每个常量(final protected)覆盖的枚举方法中,然后从适当的方法中调用该方法。因此,添加 "final protected void commonMethod() { ... }",然后在每个常量的 method() 方法的实现中只需调用 commonMethod()。

那么关于PHP呢?这是一个类似的解决方案...

<?php

abstract class Temperature extends divengine\enum {
  public function whatShouldIdo() {}
}

class HOT extends Temperature {
  public function whatShouldIdo() {
    echo "Drink a bear!";
  }
}

class COLD extends Temperature {
  public function whatShouldIdo() {
    echo "Wear a coat!";
  }
}

// ....

function someStuff(Temperature $t) {
  $t->whatShouldIdo();
}

someStuff( new HOT() );

祝您玩得开心!

文档:[https://divengine.org](https://divengine.org) (外部链接,不跟随,不索引,不重新加载,非用户生成内容)

--

@rafageist

工程师 Rafa Rodriguez

https://rafageist.com