Получить значение динамически выбираемой константы класса в PHP


115

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

class ThingIDs
{
    const Something = 1;
    const AnotherThing = 2;
}

$thing = 'Something';
$id = ThingIDs::$thing;

Это не работает. Есть ли простой способ сделать что-то эквивалентное? Обратите внимание, что я застрял в классе; это в библиотеке, которую я не могу переписать. Я пишу код, который принимает аргументы в командной строке, и мне бы очень хотелось, чтобы он принимал символические имена вместо номеров идентификаторов.


Можешь попробовать ThingIDs::{$thing}?
Дэвид Родригес

Уже пробовал. Выдает мне ошибку синтаксического анализа вместо фатальной ошибки времени выполнения.
Бен

Ответы:


184

$id = constant("ThingIDs::$thing");

http://php.net/manual/en/function.constant.php


1
Боковое примечание: если вы хотите сначала проверить, определена ли константа, этоdefined("ThingIDs::$thing");
Пэррис Варни,

3
или $ id = constant ("self :: $ thing");
Line

3
Подобно этому,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
Дэвид Баукум

4
@DavidBaucum, зачем тебе все усложнять? Запрос довольно прост и не требует внешнего, управляемого пользователем ввода. Кроме того, вы вызываете другую функцию, потому что, я думаю, вам не нравится, что строка объединяется с разделителями?
ReSpawN 03

5
В зависимости от вашего варианта использования мое решение менее сложное. В частности, если вы используете автозагрузку PSR-4, то в вашем коде может быть некрасиво иметь везде прописанное полное доменное имя. Использование useв верхней части файла, а затем использование ::classметода волшебного получения полного доменного имени улучшает читаемость.
Дэвид Баукум

27

Использовать отражение

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);

3
Размышления действительно позволяют лучше понять классы, методы и многое другое, и кажется, что многие люди боятся сделать этот шаг, чтобы понять их. Отличный ответ.
Майк Макинтош

2
@mikemackintosh Я предпринял шаги, чтобы понять их, но мало что видел с точки зрения влияния на производительность по сравнению с принятым ответом. ЭТО я хочу знать. Создание экземпляра нового класса кажется более сильным в производительности, чем простой статический вызов константы. Что ты думаешь по этому поводу?
dudewad

13

Если вы используете пространства имен, вы должны включить пространство имен с классом.

echo constant('My\Application\ThingClass::ThingConstant'); 

3
<?php

class Dude {
    const TEST = 'howdy';
}

function symbol_to_value($symbol, $class){
    $refl = new ReflectionClass($class);
    $enum = $refl->getConstants();
    return isset($enum[$symbol])?$enum[$symbol]:false;
}

// print 'howdy'
echo symbol_to_value('TEST', 'Dude');

3

Вспомогательная функция

Вы можете использовать такую ​​функцию:

function class_constant($class, $constant)
{
    if ( ! is_string($class)) {
        $class = get_class($class);
    }

    return constant($class . '::' . $constant);
}

Требуется два аргумента:

  • Имя класса или экземпляр объекта
  • Имя константы класса

Если передается экземпляр объекта, выводится имя его класса. Если вы используете PHP 7, вы можете использовать ::classдля передачи соответствующего имени класса, не думая о пространствах имен.

Примеры

class MyClass
{
    const MY_CONSTANT = 'value';
}

class_constant('MyClass', 'MY_CONSTANT'); # 'value'
class_constant(MyClass::class, 'MY_CONSTANT'); # 'value' (PHP 7 only)

$myInstance = new MyClass;
class_constant($myInstance, 'MY_CONSTANT'); # 'value'

0

Если у вас есть ссылка на сам класс, вы можете сделать следующее:

if (defined(get_class($course). '::COURSES_PER_INSTANCE')) {
   // class constant is defined
}

0

Моя проблема была похожа на эту тему. Когда у вас есть объект, но нет имени класса, вы можете использовать:

$class_name = get_class($class_object);
$class_const = 'My_Constant';

$constant_value = constant($class_name.'::'.$class_const);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.