Чи можу я визначити значення CONST для класу PHP?


140

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

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

Чи є спосіб отримати список визначених на Profileкласі CONST ? Наскільки я можу сказати, найближчий варіант ( 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

Використовуючи Reflection та ReflectionClass на Cl, ви можете використовувати функцію getConstants nz.php.net/manual/en/class.reflectionclass.php
Тім Ебенезер

Відповіді:


245

Ви можете використовувати для цього 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
Дві незначні NB: по-перше, в 5.3, Profileможна використовувати як аргумент конструктору відбивача, без лапок (проста назва класу); по-друге, щоб бути абсолютно зрозумілим, клавіші результуючого масиву - це рядки, а не константи, як може запропоновано форматування тут. (Варто згадати лише про те, що fn є недокументованим .)
Бенджі XVI,

11
@Benji XVI У 5.3, якщо у вас увімкнено сповіщення, ви не зможете користуватися Profileбез лапок, оскільки це покаже таку помилку: Примітка: Використання невизначеного константного профілю - передбачається "Профіль". Тому я пропоную зберегти цитати'Profile'
toneplex

10
Добре визначити константи, пов'язані з логікою всередині класу, тому вам не потрібно аргументувати конструктор жорсткого коду, а використовувати __CLASS__замість цього.
Лука Адамчевський

7
new ReflectionClass(Profile::class)працює також чудово
mtizziani

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

22

Це

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

1
+1 Це було б так, оскільки я не можу знайти жодних вбудованих процедурних функцій PHP для отримання констант класу, що шкода.
BoltClock

1
Можливо, тому, що в цьому мало потреби. ОП може захотіти зробити мета-конфігурацію, встановивши typesяк all constants this class has, що, в більшості випадків, і на мою обмежену думку, ймовірно, краще обслуговуватись або з успадкуванням, або зі статичною змінною масиву з типами (залишаючи місце для констант з іншими значеннями / використання).
Вріккен

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, як згадують інші афіші, також важливо зрозуміти роботу "під кришкою" і вміти обійтися без них або повторити їх, якщо це необхідно. Гарне шоу.
Опубліковано

1
Якщо ви не хочете, щоб ваш клас завантажувався в пам'ять, token_get_all - це фантастична альтернатива. Це набагато швидше, ніж Reflection, і не захаращує процесову пам’ять, якщо вам потрібно зробити це з великою кількістю класів.
Гарольд

+1 для рішення на основі лексеми! Розуміння розбору на основі лексеми - задоволення від врахування продуктивності ... і як завжди, є одна чудова людина, яка демонструє, як розбирати константи за допомогою token_get_all (). Велике спасибі!
mwatzer

Імовірно, це діє лише в одному файлі і не успадковує жодних констант від батьківських класів. Насправді ця техніка навіть не хвилює класу - вона дасть вам всі константи у файлі, навіть у глобальному масштабі. Це чудовий інструмент для дослідження.
Джейсон


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
)

6

Прикмета статичним методом - на допомогу

Схоже, це приємне місце для використання функцій зі статичною функцією для розширення функціональності класу. Особливості дозволять нам реалізовувати цю функціональність і в будь-якому іншому класі, не переписуючи той самий код знову і знову (залишайтеся СУХОМО).

Скористайтеся нашою спеціальною ознакою "ConstantExport" в класі профілю. Зробіть це для кожного класу, який вам потрібен.

/**
 * 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'));
?>

Це має дати вам уявлення про те, що ви будете дивитись.


4

Корисно мати метод всередині класу для повернення власних констант.
Можна зробити так:

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.