dbstudios/php-enum

该包最新版本(2.0.1)没有提供许可信息。

一个允许枚举使用复杂(即非标量)值的PHP枚举实现

2.0.1 2014-12-16 17:16 UTC

This package is auto-updated.

Last update: 2024-09-19 09:24:04 UTC


README

请注意:为了支持在 PHP-DaybreakCommons 中实现的Enum包,此仓库已被弃用。

PHP 枚举 - 它是什么?

PHP 枚举是类似于Java枚举的尽可能接近的“移植”。PHP没有内置对枚举的支持,使用类常量或静态变量通常不足以满足特定项目的需求。我编写PHP枚举的两个主要原因是

  1. 类常量只能是一个简单的值,不能是复杂的对象实例。
  2. 公共静态属性向“外部世界”暴露了过多的权限。

但为什么???PHP 什么的……

如果你看到这段代码,立刻想“为什么需要这个?PHP有XYZ,不应该像ABC那样工作!!!”那么这个仓库不是为你准备的,你可能需要继续前进。

我看到了很多人在问“在PHP中能否实现Java风格的枚举”,至今我所见到的所有解决方案都留下了很多遗憾。要么建议使用常量(这会阻止非标量值),要么使用公共静态变量,在我看来,这完全违反了最小权限原则。PHP Enum旨在解决这两个问题。

要求

PHP Enum需要PHP 5 >= 5.3.0,因为它使用了在5.3.0版本中才引入的 get_called_class 函数。

用法

使用PHP枚举非常简单。以下是一个通过扩展PHP Enum基类创建的简单 Planet 枚举的例子。

<?php
	use DaybreakStudios\Enum\Enum;

	class Planet extends Enum {
		private $diameter;

		public function __construct($diameter) {
			$this->diameter = $diameter;
		}

		public function getDiameter() {
			return $this->diameter;
		}

		public static function init() {
			parent::register('MERCURY', 4880.0);
			parent::register('VENUS', 12103.6);
			parent::register('EARTH', 12756.3);
			parent::register('MARS', 6794.0);
			parent::register('JUPITER', 142984.0);
			parent::register('SATURN', 120536.0);
			parent::register('URANUS', 51118.0);
			parent::register('NEPTUNE', 49532.0);
			parent::register('PLUTO', 2274.0);

			parent::stopRegistration();
		}
	}

	Planet::init();
?>

在上面的例子中有几点需要注意。

首先,枚举类(所有枚举应该扩展的基类)被命名空间化,以防止潜在的冲突。推荐的方法是在PHP文件顶部添加 use dbstudios\util\Enum,在类文件包含之后。或者,如果你认为对类进行命名空间化是不必要的,或者这导致了冲突,你只需打开 Enum.php 并删除PHP标签之后的第一行。

其次,任何枚举至少应该有一个定义的方法,即 init。这是我们将注册元素并提供构建它们所需任何参数的地方。

init 方法内部,我们使用 parent::register 来注册新元素。该 register 函数使用PHP的 get_called_class 函数来确定调用该函数的类,因此你不必担心指定哪些元素应属于哪个枚举。传递给 register 的第一个参数总是元素名称。请记住:元素名称是区分大小写的,这意味着如果你将元素注册为 PLUTO,你必须确保你以 PLUTO 访问它。任何后续参数都视为枚举的参数,我将在稍后讨论。如果你的构造函数不接受任何参数,只需传递名称即可。

在上面的例子中,我为枚举添加了一个接受单个参数的构造函数;即行星的直径。我可以在调用register时包含额外的参数来指定。注意:警告:与Java的枚举不同,Java枚举需要将类的构造函数设置为私有,而PHP枚举需要将其设置为公共。这是因为PHP没有提供通过反射访问私有构造函数的方法,而PHP枚举正是使用这种方法来创建枚举元素实例的。

接下来,我们调用parent::stopRegistration。这告诉PHP枚举我们已经注册了所有需要的元素,并且它应该阻止其他元素被添加。由于我们使用get_called_class来确定register调用的来源,因此元素被错误地放入枚举中的可能性非常低。然而,始终调用stopRegistration是一个好习惯,因为它提供了一个指标,表明您的枚举已完全初始化。

最后,在我们的类外部,我们添加了一行来调用Planet::init()。PHP不提供在类加载时自动评估类内代码的方法,因此我们需要告诉PHP要做什么,以便开始枚举的初始化。

现在我们有了枚举,我们可以这样访问它的任何值

<?php
  $planet = Planet::EARTH();

  printf('%s has a diameter of %d.', $planet->name(), $planet->getDiameter());
?>

上面的代码将产生类似“EARTH的直径为12756.3。”的输出。

此外,我们还可以遍历枚举中定义的元素。

<?php
  foreach (Planet::values() as $planet)
    printf('%s has a diameter of %d.<br>', $planet->name(), $planet->getDiameter());
?>

这将为Planet枚举中定义的每个行星产生与第一个例子相同的输出。