Могу ли я определить CONST в классе PHP?


141

У меня есть несколько CONST, определенных для некоторых классов, и я хочу получить их список. Например:

class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";
}

Есть ли способ получить список CONST, определенных в Profileклассе? Насколько я могу судить, ближайший вариант ( get_defined_constants()) не поможет.

Что мне действительно нужно, так это список имен констант - примерно так:

array('LABEL_FIRST_NAME',
    'LABEL_LAST_NAME',
    'LABEL_COMPANY_NAME')

Или:

array('Profile::LABEL_FIRST_NAME', 
    'Profile::LABEL_LAST_NAME',
    'Profile::LABEL_COMPANY_NAME')

Или даже:

array('Profile::LABEL_FIRST_NAME'=>'First Name', 
    'Profile::LABEL_LAST_NAME'=>'Last Name',
    'Profile::LABEL_COMPANY_NAME'=>'Company')

Вы можете сделать это с помощью отражения . Найдите на этой странице «Печать констант класса», чтобы увидеть пример.
n3rd 05

Используя Reflection и ReflectionClass на Cl, вы можете использовать функцию getConstants nz.php.net/manual/en/class.reflectionclass.php
Тим Эбенезер

Ответы:


248

Вы можете использовать для этого Reflection . Обратите внимание, что если вы делаете это часто, вам может потребоваться кеширование результата.

<?php
class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";
}


$refl = new ReflectionClass('Profile');
print_r($refl->getConstants());

Выход:

Array
(
    'LABEL_FIRST_NAME' => 'First Name',
    'LABEL_LAST_NAME' => 'Last Name',
    'LABEL_COMPANY_NAME' => 'Company'
)

4
Два второстепенных примечания: первое, в Profileверсии 5.3, может использоваться как аргумент конструктора отражателя без кавычек (простое имя класса); во-вторых, для полной ясности, ключи результирующего массива являются строками, а не константами, как можно было бы предположить из представленного здесь форматирования. (Стоит упомянуть только, что fn недокументировано .)
Бенджи XVI

11
@Benji XVI В версии 5.3, если у вас включены уведомления, вы не сможете использовать их Profileбез кавычек, так как будет отображаться следующая ошибка: Примечание: использование неопределенного постоянного профиля - предполагается, что это «Профиль». Поэтому я предлагаю сохранить цитаты'Profile'
toneplex

10
Полезно определять логику, связанную с константами, внутри класса, поэтому вам не нужно жестко кодировать аргумент конструктора, а использовать __CLASS__вместо него.
Люк Адамчевски

8
new ReflectionClass(Profile::class)тоже отлично работает
mtizziani

@mtizziani правда, но помните о пространствах имен! Допустим, у вас есть пространство имен Cityс классом B- все B::classбудет работать нормально, но если бы вы использовали их, например, в пространстве имен Jungle- вызов бы B::classтам без его включения useприведет к Jungle\B(хотя в Jungle вообще нет B!)
jave.web

22

Этот

 $reflector = new ReflectionClass('Status');
 var_dump($reflector->getConstants());

1
+1 Это было бы так, потому что я не могу найти никаких встроенных процедурных функций PHP для получения констант класса, что немного обидно.
BoltClock

1
Наверное, потому, что в этом нет необходимости. OP может захотеть выполнить мета-конфигурацию, установив typesas all constants this class has, что в большинстве случаев и, по моему ограниченному мнению, вероятно, лучше обслуживать либо наследованием, либо статической переменной массива с типами (оставляя место для констант с другими значениями / использовать).
Wrikken

16

Используйте token_get_all () . А именно:

<?php
header('Content-Type: text/plain');

$file = file_get_contents('Profile.php');
$tokens = token_get_all($file);

$const = false;
$name = '';
$constants = array();
foreach ($tokens as $token) {
    if (is_array($token)) {
        if ($token[0] != T_WHITESPACE) {
            if ($token[0] == T_CONST && $token[1] == 'const') {
                $const = true;
                $name = '';
            } else if ($token[0] == T_STRING && $const) {
                $const = false;
                $name = $token[1];
            } else if ($token[0] == T_CONSTANT_ENCAPSED_STRING && $name) {
                $constants[$name] = $token[1];
                $name = '';
            }
        }
    } else if ($token != '=') {
        $const = false;
        $name = '';
    }
}

foreach ($constants as $constant => $value) {
    echo "$constant = $value\n";
}
?>

Выход:

LABEL_FIRST_NAME = "First Name"
LABEL_LAST_NAME = "Last Name"
LABEL_COMPANY_NAME = "Company"

1
+1, хотя я бы сказал, что сейчас отличное время для использования Reflection, как упоминалось в других плакатах, также важно понимать работу «под капотом» и иметь возможность обойтись без них или воспроизвести их, если необходимо. Хорошее шоу.
Дата выпуска 02

1
Если вы не хотите, чтобы ваш класс загружался в память, token_get_all - отличная альтернатива. Это НАМНОГО быстрее, чем Reflection, и не загромождает память процесса, если вам нужно сделать это с большим количеством классов.
Гарольд

+1 за решение на основе токенов! Понимать парсинг на основе токенов - одно удовольствие, учитывая производительность ... и, как всегда, есть один замечательный человек, который демонстрирует, как анализировать константы с помощью token_get_all (). Большое спасибо!
mwatzer 01

Предположительно это действует только для одного файла и не наследует никаких констант от родительских классов. Фактически, этот метод даже не заботится о классе - он предоставит вам все константы в файле, даже в глобальной области. Однако это отличный инструмент для изучения.
Джейсон


13

В комментариях к документации PHP, если вы можете использовать ReflectionClass (PHP 5):

function GetClassConstants($sClassName) {
    $oClass = new ReflectionClass($sClassName);
    return $oClass->getConstants();
}

Источник здесь.


9

Использование ReflectionClass getConstants()дает именно то, что вы хотите:

<?php
class Cl {
    const AAA = 1;
    const BBB = 2;
}
$r = new ReflectionClass('Cl');
print_r($r->getConstants());

Выход:

Array
(
    [AAA] => 1
    [BBB] => 2
)

7

Трейт со статическим методом - на помощь

Похоже, это хорошее место для использования Traits со статической функцией для расширения функциональности класса. Черты также позволят нам реализовать эту функциональность в любом другом классе, не переписывая один и тот же код снова и снова (оставайтесь СУХИМИ).

Используйте наш настраиваемый трейт ConstantExport с классом in Profile. Сделайте это для каждого класса, в котором вам нужна эта функциональность.

/**
 * ConstantExport Trait implements getConstants() method which allows 
 * to return class constant as an assosiative array
 */
Trait ConstantExport 
{
    /**
     * @return [const_name => 'value', ...]
     */
    static function getConstants(){
        $refl = new \ReflectionClass(__CLASS__);
        return $refl->getConstants();
    }
}

Class Profile 
{
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";

    use ConstantExport;

}

ПРИМЕР ИСПОЛЬЗОВАНИЯ

// So simple and so clean
$constList = Profile::getConstants(); 

print_r($constList); // TEST

ВЫХОДЫ:

Array
(
    [LABEL_FIRST_NAME] => First Name
    [LABEL_LAST_NAME] => Last Name
    [LABEL_COMPANY_NAME] => Company
)

5

Да, вы используете отражение . Посмотрите на вывод

<?
Reflection::export(new ReflectionClass('YourClass'));
?>

Это должно дать вам представление о том, на что вы будете смотреть.


5

Удобно иметь внутри класса метод, возвращающий его собственные константы.
Сделать можно так:

class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";


    public static function getAllConsts() {
        return (new ReflectionClass(get_class()))->getConstants();
    }
}

// test
print_r(Profile::getAllConsts());

3

Почему бы для начала не поместить их в переменную класса в виде массива? Облегчает сквозное прохождение.

private $_data = array("production"=>0 ...);

2
Потому что массивы не являются константами? Если вы реализуете что-то, что должно быть константой, как переменную, вы рискуете случайно изменить или сбросить ее. Другими словами, вы не можете рассчитывать на их постоянство.
GordonM

3

В конце концов с пространствами имен:

namespaces enums;
class enumCountries 
{
  const CountryAustria          = 1 ;
  const CountrySweden           = 24;
  const CountryUnitedKingdom    = 25;
}

namespace Helpers;
class Helpers
{
  static function getCountries()
  {
    $c = new \ReflectionClass('\enums\enumCountries');
    return $c->getConstants();
  }
}

print_r(\Helpers\Helpers::getCountries());

1
class Qwerty 
{
    const __COOKIE_LANG_NAME__ = "zxc";
    const __UPDATE_COOKIE__ = 30000;

    // [1]
    public function getConstants_(){

        return ['__COOKIE_LANG_NAME__' => self::__COOKIE_LANG_NAME__, 
                '__UPDATE_COOKIE__' => self::__UPDATE_COOKIE__]; 
    }    

    // [2]
    static function getConstantsStatic_(){

        return ['__COOKIE_LANG_NAME__' => self::__COOKIE_LANG_NAME__, 
                '__UPDATE_COOKIE__' => self::__UPDATE_COOKIE__]; 
    } 
}

// [1]
$objC = new Qwerty();
var_dump($objC->getConstants_());

// [2]
var_dump(Qwerty::getConstantsStatic_());
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.