19

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

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 语法手册

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

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

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

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

但在我上面的例子中, 的值RAD_TO_CIRCUM在编译时是未知的。那么编译器为 的值添加了RADIUS_TO_CIRCUMFERENCE什么?

我猜测编译器为 的值创建了某种占位符RADIUS_TO_CIRCUMFERENCE,并且在运行时,该占位符被替换为 的值RAD_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();
    }

}

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

还有其他更好的解决方法吗?

4

4 回答 4

15

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

const RADIUS_TO_CIRCUMFERENCE = M_PI * 2;

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

于 2015-04-08T05:17:54.733 回答
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();
    }
}

目标是对所有类实体只计算一次,如实常数。

于 2013-08-06T12:48:48.023 回答
0

就我而言,

我安装的 php 版本是 7.1,但是在我的 IDE(PhpStorm) 设置中选择了我的 php 版本 5.4。一旦我更改了我的 php 版本,问题就消失了。

PhpStorm 设置->PHP 并更改 PHP 语言级别和 CLI 解释器 php 版本。

于 2018-10-01T11:41:02.037 回答
-1

如果您同意使用标准变量而不是 const 关键字:

class Foo {

    public $CONST_A; // = calculation A // To let people quickly see the value.
    public $CONST_B; // = calculation B 

    public static function initClass() {
        self::$CONST_A = /* calculation A */;
        self::$CONST_B = /* calculation B */;
    }
}

Foo::initClass();

initClass()仅在需要类文件时执行一次。

于 2013-08-06T11:40:40.233 回答