PHP 中的枚举
- 在 PHP 中使用抽象类模拟枚举
- 在 PHP 中使用具有验证和更多常量值的抽象类来模拟枚举
-
使用 PHP
enum
进行枚举 - 支持的 PHP 枚举
- 使用 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 中支持的枚举的以下内容。
- 为支持值定义值时,确保所有值都有支持值。
- 你应该在枚举名称之后声明支持值的类型。
- 枚举中的支持值是只读的。
- 如果你的枚举包含标量值,它们应该是唯一的。
- 支持的值应该是文字表达式或文字。
- 你可以使用语法
enum_name::backed_value
访问支持的值。其中enum_name
是枚举名称,backed_value
是你要访问的值。 - 支持的枚举有一个称为
BackedEnum
的内部接口。这个接口有两个方法,from
和tryFrom
。 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 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