dbstudios / php-enum
一个允许枚举使用复杂(即非标量)值的PHP枚举实现
Requires
- php: >= 5.3.0
This package is auto-updated.
Last update: 2024-09-19 09:24:04 UTC
README
请注意:为了支持在 PHP-DaybreakCommons 中实现的Enum包,此仓库已被弃用。
PHP 枚举 - 它是什么?
PHP 枚举是类似于Java枚举的尽可能接近的“移植”。PHP没有内置对枚举的支持,使用类常量或静态变量通常不足以满足特定项目的需求。我编写PHP枚举的两个主要原因是
- 类常量只能是一个简单的值,不能是复杂的对象实例。
- 公共静态属性向“外部世界”暴露了过多的权限。
但为什么???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
枚举中定义的每个行星产生与第一个例子相同的输出。