一般来说是的,避免使用常量。它们引入了从消费者到全局范围的耦合。也就是说,消费者依赖外部的东西。这是不明显的,例如
class Foo
{
public function doSomething()
{
if (ENV === ENV_DEV) {
// do something this way
} else {
// do something that way
}
}
}
如果不了解doSomething 的内部结构,您将不会知道具有该常量的全局范围存在依赖关系。因此,除了使您的代码更难理解之外,您还限制了它的重用方式。
对于只有一个值的常量也是如此,例如
public function log($message)
{
fwrite(LOGFILE, $message);
}
这里的常量将指向外部某处定义为的文件资源
define('LOGFILE', fopen('/path/to/logfile'));
这与使用ENV 一样不明显。这是一种依赖,需要类之外的东西存在。为了使用该对象,我必须知道这一点。由于使用这个常量的类隐藏了这个细节,我可能会尝试在不确保常量存在的情况下记录一些东西,然后我想知道为什么它不起作用。它甚至不必是资源,LOGFILE 可以简单地将路径包含为字符串。结果一样。
依赖消费者中的全局常量还需要您在单元测试中设置全局状态。这是您通常希望避免的事情,即使常量是固定值,因为单元测试的重点是单独测试单元,并且必须将环境置于特定状态会阻碍这一点。
此外,使用全局常量总是会带来不同库的常量冲突的威胁。根据经验,不要将任何内容放入全局范围。如果必须使用命名空间来聚集常量。
但是,请注意命名空间常量在耦合方面仍然存在相同的问题,类常量也是如此。只要这种耦合在同一个命名空间内,它就不太重要,但是一旦你开始耦合到来自不同命名空间的常量,你就会再次阻碍重用。为此,请考虑任何常量公共 API。
使用常量的替代方法是使用不可变的值对象,例如:
class Environment
{
private $value;
public function __construct($value)
{
$this->assertValueIsAllowedValue($value);
$this->value = $value;
}
public function getValue() {
// …
这样,除了确保这些值有效之外,您还可以将这些值传递给需要它们的对象。像往常一样,YMMV。这只是一种选择。单个常量不会使您的代码无法使用,但在很大程度上依赖常量会产生不利影响,因此根据经验,尽量将它们保持在最低限度。
在相关的旁注中,您可能还对以下内容感兴趣: