PHP 中的枚举

Habdul Hazeez 2023年1月30日
  1. 在 PHP 中使用抽象类模拟枚举
  2. 在 PHP 中使用具有验证和更多常量值的抽象类来模拟枚举
  3. 使用 PHP enum 进行枚举
  4. 支持的 PHP 枚举
  5. 使用 PHP 中的方法支持枚举
  6. 列出 PHP 中支持枚举的案例
PHP 中的枚举

本教程将教你如何在 PHP 8.1 之前和之后使用 PHP 中的枚举

原因是在 PHP 8.1 之前,你只能使用抽象类来模拟枚举。但是,从 PHP 8.1 开始,PHP 提供了对枚举的原生支持。

在 PHP 中使用抽象类模拟枚举

在 PHP 8.1 之前,你可以使用抽象类来模拟枚举。由于枚举是将名称分配给整数常量,因此你可以创建一个包含常量值的抽象类。

你可以通过范围解析协议 :: 获取类外的每个常量值。

我们的下一个示例代码有一个包含类常量的抽象类。之后,我们通过范围解析协议调用其中一个常量。

这种方法有其局限性;我们将在下一节讨论它。

<?php
    abstract class CalenderMonths {
        const January 	= 1;
        const February 	= 2;
        const March 	= 3;
        const April 	= 4;
        const May 		= 5;
        const June 		= 6;
        const July		= 7;
        const August 	= 8;
        const September = 9;
        const October 	= 10;
        const November 	= 11;
        const December 	= 12;
    }

    $january = CalenderMonths::January;

    echo $january;
?>

输出:

1

在 PHP 中使用具有验证和更多常量值的抽象类来模拟枚举

这个例子建立在我们之前的例子之上。但是在这里,我们提出了一个改进的版本。

这个版本有验证,可以保存更多的常数值。此外,它还可以防止当你扩展类时,第一个扩展创建一个缓存,而另一个扩展仍然使用相同的缓存。

该代码块使用抽象类模拟枚举,并且它具有防止无效参数的验证。首先,我们定义抽象类。

<?php
    abstract class EmulatePHPEnum {
        private static $cache_array = NULL;

        private static function get_constants() {
            if (self::$cache_array == NULL) {
                self::$cache_array = [];
            }
            $called_class = get_called_class();
            if (!array_key_exists($called_class, self::$cache_array)) {
                $reflection_object = new ReflectionClass($called_class);
                self::$cache_array[$called_class] = $reflection_object->getConstants();
            }
            return self::$cache_array[$called_class];
        }

        public static function check_valid_name($name, $is_strict = false) {
            $constants = self::get_constants();

            if ($is_strict) {
                return array_key_exists($name, $constants);
            }

            $keys = array_map('strtolower', array_keys($constants));
            return in_array(strtolower($name), $keys);
        }

        public static function check_valid_value($value, $is_strict = true) {
            $values = array_values(self::get_constants());
            return in_array($value, $values, $is_strict);
        }
    }
?>

然后,我们扩展它并进行比较。

abstract class CalenderMonths extends EmulatePHPEnum {
	const January 	= 1;
	const February 	= 2;
	const March 	= 3;
	const April 	= 4;
	const May 		= 5;
	const June 		= 6;
	const July		= 7;
	const August 	= 8;
	const September = 9;
	const October 	= 10;
	const November 	= 11;
	const December 	= 12;
}

echo "<b>First check: </b> ";
if (CalenderMonths::check_valid_name("Nothing")) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Second check: </b>";
if (CalenderMonths::check_valid_name("September")) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Third check: </b>";
if (CalenderMonths::check_valid_name("september")) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Fourth check: </b>";
if (CalenderMonths::check_valid_name("september", $is_strict = true)) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Fifth check: </b>";
if (CalenderMonths::check_valid_name(23)) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

输出:

<b>First check</b>: False
<b>Second check</b>: True
<b>Third check</b>: True
<b>Fourth check</b>: False
<b>Fifth check</b>: False

使用 PHP enum 进行枚举

PHP 中枚举的定义是使用 enum 关键字后跟枚举名称和一组花括号。在这些大括号中,你可以定义案例。

我们在下一个代码块中提供一个示例。此外,我们在案例之间进行了一些比较检查。

请注意,你不能将枚举与小于或大于运算符进行比较。

<?php
    enum ProgrammingLanguages {
        case JavaScript;
        case PHP;
        case Ruby;
        case Erlang;
        case Elixir;
    }

    $javascript = ProgrammingLanguages::JavaScript;
    $js 		= ProgrammingLanguages::JavaScript;
    $erlang     = ProgrammingLanguages::Erlang;

    echo $javascript === $js;

    echo "<br/>";

    if ($javascript === $erlang) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br/>";

    if ($javascript instanceof ProgrammingLanguages) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";
    if ($javascript > $js || $javascript < $js) {
        echo "True";
    } else {
        echo "False";
    }
?>

输出:

1 <br />
False <br />
True <br />
False <br />

支持的 PHP 枚举

支持的枚举是枚举声明,后跟枚举中每种情况的数据类型。

在我们查看代码示例之前,请注意以下关于 PHP 中支持的枚举的以下内容。

  1. 为支持值定义值时,确保所有值都有支持值。
  2. 你应该在枚举名称之后声明支持值的类型。
  3. 枚举中的支持值是只读的。
  4. 如果你的枚举包含标量值,它们应该是唯一的。
  5. 支持的值应该是文字表达式或文字。
  6. 你可以使用语法 enum_name::backed_value 访问支持的值。其中 enum_name 是枚举名称,backed_value 是你要访问的值。
  7. 支持的枚举有一个称为 BackedEnum 的内部接口。这个接口有两个方法,fromtryFrom
  8. from 方法将抛出不存在值的异常。而 tryFrom 返回 null

以下代码显示了如何在 PHP 中使用支持的枚举。

<?php
    enum Age : int {
        case John 		= 23;
        case Martinez 	= 30;
        case Mary 		= 43;
        case Velasquez 	= 25;
    }

    $first_age = Age::tryFrom(23);

    if ($first_age) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";

    $second_age = Age::tryFrom(98);

    if ($second_age) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";

    $third_age = Age::from(42);
?>

输出:

True
False

<b>Fatal error</b>: Uncaught ValueError: 42 is not a valid backing value for enum "Age"

使用 PHP 中的方法支持枚举

支持的枚举可以有方法。结果,他们可以实现一个接口。

你将在下一个示例代码中找到一个示例。

<?php

    interface isTravel {
        public function calculate_travel_cost (int $distance_covered): int;
        public function isRequireFuel(): bool;
    }

    enum CarTypes: int implements isTravel {
        case Bughatti 		= 300;
        case Lamborghini 	= 500;
        case Ferrari 		= 450;
        case Audi 			= 350;

        public function calculate_travel_cost(int $distance_covered): int {
            return $this->value * $distance_covered;
        }

        public function isRequireFuel(): bool {
            return match($this) {
                CarTypes::Bughatti, CarTypes::Lamborghini, CarTypes::Ferrari => true,
            };
        }
    }

    $car = CarTypes::Bughatti;

    $does_it_require_fuel = $car->isRequireFuel();

    if ($does_it_require_fuel) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";

    $car_travel_cost = $car ->calculate_travel_cost(250);

    echo $car_travel_cost;
?>

输出:

True
75000

列出 PHP 中支持枚举的案例

如果你希望列出支持枚举的情况,可以通过名为 UnitEnum 的内部接口来完成。这个接口有一个定义为 UnitEnum::cases 的静态方法。

使用此接口,你可以检索枚举中的案例。你将在下面找到示例代码。

<?php
    interface isTravel {
        public function calculate_travel_cost (int $distance_covered): int;
        public function isRequireFuel(): bool;
    }

    enum CarTypes: int implements isTravel {
        case Bughatti 		= 300;
        case Lamborghini 	= 500;
        case Ferrari 		= 450;
        case Audi 			= 350;

        public function calculate_travel_cost(int $distance_covered): int {
            return $this->value * $distance_covered;
        }

        public function isRequireFuel(): bool {
            return match($this) {
                CarTypes::Bughatti, CarTypes::Lamborghini, CarTypes::Ferrari => true,
            };
        }
    }

    $car_names = CarTypes::cases();
    echo "<pre>";
    var_dump($car_names);
    echo "</pre>";
?>

输出:

<pre>
array(4) {
  [0]=>
  enum(CarTypes::Bughatti)
  [1]=>
  enum(CarTypes::Lamborghini)
  [2]=>
  enum(CarTypes::Ferrari)
  [3]=>
  enum(CarTypes::Audi)
}
</pre>
作者: Habdul Hazeez
Habdul Hazeez avatar Habdul Hazeez avatar

Habdul Hazeez is a technical writer with amazing research skills. He can connect the dots, and make sense of data that are scattered across different media.

LinkedIn