Лучшее решение для создания константы класса PHP из выражения?

Я хотел бы сделать что-то вроде этого:

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-синтаксису :

Константный модификатор создает константу времени компиляции, поэтому компилятор заменит все использование константы на ее значение. Напротив, define создает постоянную времени выполнения, которая не устанавливается до времени выполнения. Именно по этой причине define констант может быть назначено с выраженными значениями, тогда как const требует постоянных значений, которые известны во время компиляции.

Руководство подтверждает, что «константы, определенные с использованием ключевого слова const … определены во время компиляции».

В этом отчете об ошибке от 3 лет назад член команды PHP написал:

Для константы класса нам нужно постоянное значение во время компиляции и не может оценивать выражения. define() является регулярной функцией, оцененной во время выполнения и поэтому может содержать любое значение любой формы.

Но в моем примере выше значение RAD_TO_CIRCUM неизвестно во время компиляции. Итак, что же делает компилятор для значения RADIUS_TO_CIRCUMFERENCE ?

Я предполагаю, что компилятор создает какой-то заполнитель для значения RADIUS_TO_CIRCUMFERENCE , и во время выполнения этот placeholder заменяется значением 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(); } } 

Это мое любимое обходное решение, о котором я знаю. Значение является постоянным, и оно не влияет на глобальное пространство.

Есть ли еще один обходной путь, который еще лучше?

Начиная с PHP 5.6 вы можете использовать математические выражения в PHP-константах .

поэтому код const RADIUS_TO_CIRCUMFERENCE = M_PI * 2; должно сработать.

Я столкнулся с этим потоком, потому что моя среда не была настроена должным образом (была установлена ​​на php 5.4 случайно), поэтому я подумал, что, возможно, это будет полезно для всех, кто придет сюда.

Я бы рекомендовал этот подход:

 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(); } } 

Цель – вычисление только один раз для всех объектов класса, таких как реальная константа.

Если вы согласны использовать стандартную переменную вместо ключевого слова 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() выполняется только один раз, когда требуется файл класса.