HOWTO · PHP

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 中支援的列舉的以下內容。

  1. 為支援值定義值時,確保所有值都有支援值。
  2. 你應該在列舉名稱之後宣告支援值的型別。
  3. 列舉中的支援值是隻讀的。
  4. 如果你的列舉包含標量值,它們應該是唯一的。
  5. 支援的值應該是文字表示式或文字。
  6. 你可以使用語法 enum_name::backed_value 訪問支援的值。其中 enum_name 是列舉名稱,backed_value 是你要訪問的值。
  7. 支援的列舉有一個稱為 BackedEnum 的內部介面。這個介面有兩個方法,from 和 tryFrom。
  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>