Czy mogę uzyskać CONST zdefiniowane w klasie PHP?

140

Mam kilka zdefiniowanych parametrów CONST dla niektórych klas i chcę uzyskać ich listę. Na przykład:

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

Czy jest jakiś sposób, aby uzyskać listę CONST zdefiniowanych w Profileklasie? O ile wiem, najbliższa opcja ( get_defined_constants()) nie załatwi sprawy.

To, czego potrzebuję, to lista stałych nazw - coś takiego:

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

Lub:

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

Lub nawet:

array('Profile::LABEL_FIRST_NAME'=>'First Name', 
    'Profile::LABEL_LAST_NAME'=>'Last Name',
    'Profile::LABEL_COMPANY_NAME'=>'Company')
Brock Boland
źródło
Możesz to zrobić za pomocą refleksji . Wyszukaj na tej stronie „Drukuj stałe klasy”, aby zobaczyć przykład.
n3.
Używając Reflection i ReflectionClass w Cl, możesz użyć funkcji getConstants nz.php.net/manual/en/class.reflectionclass.php
Tim Ebenezer,

Odpowiedzi:

245

Możesz do tego użyć Reflection . Zauważ, że jeśli robisz to dużo, możesz chcieć spojrzeć na buforowanie wyniku.

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

Wynik:

Array
(
    'LABEL_FIRST_NAME' => 'First Name',
    'LABEL_LAST_NAME' => 'Last Name',
    'LABEL_COMPANY_NAME' => 'Company'
)
Tom Haigh
źródło
4
Dwie mniejsze uwagi: po pierwsze, w 5.3, Profilemożna użyć jako argumentu konstruktora reflektora, bez cudzysłowów (prosta nazwa klasy); po drugie, dla pełnej jasności, klucze wynikowej tablicy są łańcuchami, a nie stałymi, jak sugeruje to formatowanie. (Warto wspomnieć tylko, że fn nie jest udokumentowane .)
Benji XVI
11
@Benji XVI W 5.3, jeśli masz włączone powiadomienia, nie będziesz mógł używać Profilebez cudzysłowów, ponieważ pokaże następujący błąd: Uwaga: użycie niezdefiniowanej stałej Profil - zakładany „Profil”. Dlatego proponuję zachować cytaty'Profile'
toneplex
10
Dobrze jest zdefiniować logikę związaną ze stałymi wewnątrz klasy, więc nie musisz wpisywać argumentów konstruktora na sztywno, ale __CLASS__zamiast tego użyj .
Luke Adamczewski
7
new ReflectionClass(Profile::class)też działa dobrze
mtizziani
@mtizziani prawda, ale uważaj na przestrzenie nazw! Powiedzmy, że masz przestrzeń nazw Cityz klasą B- B::classdziałałaby dobrze, ale gdybyś użył ich np. W przestrzeni nazw Jungle- wywołanie B::classtam bez useJungle\B
dołączania
22

To

 $reflector = new ReflectionClass('Status');
 var_dump($reflector->getConstants());
Wrikken
źródło
1
+1 To by było na tyle, ponieważ nie mogę znaleźć żadnych wbudowanych proceduralnych funkcji PHP do pobierania stałych klas, co jest trochę wstydem.
BoltClock
1
Prawdopodobnie dlatego, że nie ma takiej potrzeby. OP może chcieć wykonać metakonfigurację, ustawiając typesjako all constants this class has, które w większości przypadków i moim ograniczonym zdaniem są prawdopodobnie lepiej obsługiwane przez dziedziczenie lub statyczną zmienną tablicową z typami (pozostawiając miejsce na stałe o innym znaczeniu / posługiwać się).
Wrikken
16

Użyj token_get_all () . Mianowicie:

<?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";
}
?>

Wynik:

LABEL_FIRST_NAME = "First Name"
LABEL_LAST_NAME = "Last Name"
LABEL_COMPANY_NAME = "Company"
cletus
źródło
1
+1, chociaż powiedziałbym, że jest to doskonały czas na użycie Refleksji, o której wspominają inne plakaty, ważne jest również, aby zrozumieć działanie „pod maską” i móc się bez nich obejść lub powielić je, jeśli to konieczne. Dobry występ.
Wydany
1
Jeśli nie chcesz, aby Twoja klasa była ładowana do pamięci, token_get_all jest fantastyczną alternatywą. Jest DUŻO szybszy niż odbicie i nie zaśmieca pamięci procesu, jeśli musisz to zrobić z wieloma klasami.
Harold
+1 za rozwiązanie oparte na tokenach! Zrozumienie analizy opartej na tokenach jest przyjemnością, biorąc pod uwagę wydajność ... i jak zawsze jest jedna wspaniała osoba, która pokazuje, jak analizować stałe za pomocą token_get_all (). Dziękuję Ci bardzo!
mwatzer
Przypuszczalnie działa to tylko na pojedynczy plik i nie dziedziczy żadnych stałych z klas nadrzędnych. W rzeczywistości ta technika nie dba nawet o klasę - da ci wszystkie stałe w pliku, nawet w zakresie globalnym. Jest to jednak świetne narzędzie do odkrywania.
Jason
14

W PHP5 możesz użyć Reflection: (podręcznik)

$class = new ReflectionClass('Profile');
$consts = $class->getConstants();
Parsingphase
źródło
13

Zgodnie z komentarzami w dokumentacji PHP, jeśli możesz użyć klasy ReflectionClass (PHP 5):

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

Źródło jest tutaj.

mway
źródło
9

Używając ReflectionClass i getConstants()daje dokładnie to, czego chcesz:

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

Wynik:

Array
(
    [AAA] => 1
    [BBB] => 2
)
Ben James
źródło
6

Cecha metodą statyczną - na ratunek

Wygląda na to, że jest to przyjemne miejsce do używania cech z funkcją statyczną w celu rozszerzenia funkcjonalności klasy. Cechy pozwolą nam również zaimplementować tę funkcjonalność w dowolnej innej klasie bez przepisywania w kółko tego samego kodu (pozostań DRY).

Użyj naszej niestandardowej cechy „ConstantExport” w klasie profilu. Zrób to dla każdej klasy, na której potrzebujesz tej funkcjonalności.

/**
 * 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;

}

PRZYKŁAD UŻYCIA

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

print_r($constList); // TEST

WYJŚCIA:

Array
(
    [LABEL_FIRST_NAME] => First Name
    [LABEL_LAST_NAME] => Last Name
    [LABEL_COMPANY_NAME] => Company
)
DevWL
źródło
5

Tak, używasz refleksji . Spójrz na wynik

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

To powinno dać ci wyobrażenie o tym, na co będziesz patrzeć.

chaos
źródło
4

Przydatne jest posiadanie metody wewnątrz klasy zwracającej własne stałe.
Możesz to zrobić w ten sposób:

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());
Luis Siquot
źródło
3

Dlaczego nie umieścić ich w zmiennej klasy jako tablicy? Ułatwia wykonywanie pętli.

private $_data = array("production"=>0 ...);
Wykryć
źródło
2
Ponieważ tablice nie są stałymi? Jeśli zaimplementujesz coś, co ma być stałą jako zmienną, ryzykujesz, że zostanie ona nieumyślnie zmieniona lub zmieniona. Innymi słowy, nie możesz polegać na tym, że pozostaną niezmienne.
GordonM,
3

Ostatecznie z przestrzeniami nazw:

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());
unieważnić
źródło
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_());
Юрий Светлов
źródło