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

Я хотел бы иметь возможность сделать что-то вроде этого:

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

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

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


person Ben    schedule 27.05.2011    source источник
comment
Можешь попробовать ThingIDs::{$thing}?   -  person David Rodrigues    schedule 27.05.2011
comment
Уже попробовал. Получает ошибку синтаксического анализа вместо фатальной ошибки времени выполнения.   -  person Ben    schedule 27.05.2011


Ответы (7)


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

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

person Dan Simon    schedule 27.05.2011
comment
Примечание: если вы хотите сначала проверить, определена ли константа, это defined("ThingIDs::$thing"); - person Parris Varney; 12.11.2014
comment
или $id = константа (self::$thing); - person Line; 23.03.2015
comment
Аналогично этому, $id = constant(sprintf('%s::%s', ThingIDs::class, $thing)); - person David Baucum; 05.07.2016
comment
@DavidBaucum, зачем тебе это усложнять? Запрос довольно прост и не требует внешнего ввода, которым может управлять пользователь. Кроме того, вы вызываете другую функцию, потому что, я думаю, вам не нравится, когда строка объединяется с разделителями? - person ReSpawN; 03.11.2016
comment
В зависимости от вашего варианта использования мое решение менее сложное. В частности, если вы используете автозагрузку PSR-4, то в вашем коде может быть некрасиво указывать везде полное доменное имя. Использование use в верхней части файла, а затем использование метода ::class для волшебного получения полного доменного имени улучшает читаемость. - person David Baucum; 08.11.2016

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

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);
person Phil    schedule 27.05.2011
comment
Размышления действительно дают много информации о классах, методах и многом другом, и кажется, что многие люди боятся сделать этот шаг, чтобы понять их. Отличный ответ. - person Mike Mackintosh; 05.12.2012
comment
@mikemackintosh Я предпринял шаги, чтобы понять их, но не видел многого с точки зрения влияния на производительность по сравнению с принятым ответом. ЭТО то, что мне интересно знать. Кажется, что создание экземпляра нового класса будет иметь больший удар по производительности, чем просто статический вызов константы. Что ты думаешь по этому поводу? - person dudewad; 23.09.2013

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

echo constant('My\Application\ThingClass::ThingConstant'); 
person Jordi Kroon    schedule 07.10.2014

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

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

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'
person Glutexo    schedule 02.01.2018

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

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

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

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

$constant_value = constant($class_name.'::'.$class_const);
person Andrei    schedule 24.09.2019

Я знаю, что немного опоздал, но я надеюсь, что это может помочь в любом случае.

Основываясь на ответе Фила, я создал класс перечислителя по умолчанию, который можно расширить.

class DefaultEnum
{
    static public function getConstantText(string $constant)
    {
        try {
            // Get child class name that called this method
            $child_class = get_called_class();

            $reflection = new ReflectionClass($child_class);
            $const = $reflection->getConstant($constant);

            return $const;
        } catch (\ReflectionException $e) {
            // ...
        }
    }
}

class CustomEnum extends DefaultEnum
{
    const something = 'abcd';
    const something2 = 'ABCD';
}

Вы можете вызвать этот метод следующим образом

CustomEnum::getConstantText('something');

Он вернет 'abcd'.

Функция get_called_class() — это функция, которая возвращает класс имя, вызвавшее этот метод, и оно работает специально для статических методов.

В этом случае значение $child_class будет CustomEnum::class. ReflectionClass принимает строки и объект в качестве параметра.

person Gabriele Rulli    schedule 09.11.2020