从表达式创建 PHP 类常量的最佳解决方法?

2022-08-30 21:15:52

我希望能够做这样的事情:

class Circle {

    const RADIUS_TO_CIRCUMFERENCE = M_PI * 2;  // Not allowed

    private $radius;

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

    ...

    public function getCircumference() {
        return $this->radius * self::RADIUS_TO_CIRCUMFERENCE;
    }

}

但是我不能从这样的表达式创建类常量

该值必须是常量表达式,而不是(例如)变量、属性、数学运算的结果或函数调用。


所以我的问题是:PHP的这种限制的最佳解决方法是什么?我知道以下解决方法,但是还有其他更好的方法吗?

1. 创建属性

class Circle {

    private static $RADIUS_TO_CIRCUMFERENCE;

    private $radius;

    public function __construct( $radius ) {
        $this->radius = $radius;
        $this->RADIUS_TO_CIRCUMFERENCE = M_PI * 2;
    }

    ...

    public function getCircumference() {
        return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE;
    }

}

我不喜欢这样,因为的值是可以改变的,所以它并不是一个真正的“常量”。$RADIUS_TO_CIRCUMFERENCE

2. 使用define()

define( 'RAD_TO_CIRCUM', M_PI * 2 );

class Circle {

    const RADIUS_TO_CIRCUMFERENCE = RAD_TO_CIRCUM;

    ...

    public function getCircumference() {
        return $this->radius * self::RADIUS_TO_CIRCUMFERENCE;
    }

}

这更好,因为值确实是恒定的,但缺点是已经全局定义。RAD_TO_CIRCUM

题外话

我不明白这怎么能工作。(编辑:我已经测试过了,它确实有效。根据PHP语法手册

修饰符创建一个编译时常量,因此编译器将用其值替换该常量的所有用法。相反,创建一个运行时常量,直到运行时才设置该常量。这就是为什么常量可以分配表达式值,而需要编译时已知的常量值的原因。constdefinedefineconst

该手册确认“使用关键字定义的常量...在编译时定义”。const

在3年前的这份错误报告中,PHP团队的一名成员写道:

对于类常量,我们需要在编译时使用常量值,并且无法计算表达式。 是一个常规函数,在运行时计算,因此可以包含任何形式的任何值。define()

但在我上面的示例中,编译时不知道 的值。那么编译器为 的值放了什么?RAD_TO_CIRCUMRADIUS_TO_CIRCUMFERENCE

我猜编译器为 的值创建了某种占位符,并且在运行时,该占位符被替换为 的值。这个占位符可能是一种资源吗?如果是这样,也许应该避免这种技术?该手册:“可以将常量定义为资源,但应该避免,因为它可能导致意外的结果。RADIUS_TO_CIRCUMFERENCERAD_TO_CIRCUM

3. 创建方法

class Circle {

    ...

    private static function RADIUS_TO_CIRCUMFERENCE() {
        return M_PI * 2;
    }

    public function getCircumference() {
        return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE();
    }

}

这是我所知道的我最喜欢的解决方法。该值是常量,并且不会影响全局空间。

有没有另一种更好的解决方法?


答案 1

从 PHP 5.6 开始,您可以在 PHP 常量中使用数学表达式,因此这可以正常工作:

const RADIUS_TO_CIRCUMFERENCE = M_PI * 2;

我遇到这个线程,因为我的环境配置不正确(意外设置为PHP 5.4),所以不要忘记检查你的PHP版本。


答案 2

我会推荐这种方法:

class Circle {

    ...

    private function RADIUS_TO_CIRCUMFERENCE() {
        static $RADIUS_TO_CIRCUMFERENCE;

        if ( null === $RADIUS_TO_CIRCUMFERENCE )
            $RADIUS_TO_CIRCUMFERENCE = M_PI * 2;

        return $RADIUS_TO_CIRCUMFERENCE;
    }

    public function getCircumference() {
        return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE();
    }
}

目标是对所有类实体只计算一次,就像一个实常量一样。


推荐