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