Posso ottenere i CONST definiti su una classe PHP?


140

Ho alcune CONST definite in alcune classi e voglio averne un elenco. Per esempio:

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

Esiste un modo per ottenere un elenco dei CONST definiti nella Profileclasse? Per quanto posso dire, l'opzione più vicina ( get_defined_constants()) non farà il trucco.

Quello di cui ho effettivamente bisogno è un elenco dei nomi delle costanti - qualcosa del genere:

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

O:

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

O anche:

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

Puoi farlo usando la riflessione . Cerca "Stampa costanti di classe" su quella pagina per vedere un esempio.
3

Usando Reflection e una ReflectionClass su Cl, puoi usare la funzione getConstants nz.php.net/manual/en/class.reflectionclass.php
Tim Ebenezer,

Risposte:


245

Per questo puoi usare Reflection . Nota che se lo stai facendo molto, potresti voler guardare nella cache il risultato.

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

Produzione:

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

4
Due NB minori: il primo, in 5.3, Profilepuò essere usato come argomento per il costruttore del riflettore, senza virgolette (un semplice nome di classe); in secondo luogo, per essere completamente chiari, le chiavi dell'array risultante sono stringhe, non costanti, come potrebbe essere suggerito dalla formattazione qui. (Vale la pena menzionare solo perché il fn non è documentato .)
Benji XVI,

11
@Benji XVI In 5.3 se sono state attivate le notifiche, non sarà possibile utilizzare Profilesenza le virgolette, poiché mostrerà il seguente errore: Avviso: utilizzo del profilo costante non definito - assunto "Profilo". Quindi suggerisco di mantenere le virgolette'Profile'
toneplex il

10
È utile definire la logica relativa alle costanti all'interno della classe, quindi non è necessario codificare l'argomento del costruttore ma utilizzare __CLASS__invece.
Luke Adamczewski,

7
new ReflectionClass(Profile::class)funziona anche bene
mtizziani,

@mtizziani vero, ma fai attenzione agli spazi dei nomi! Diciamo che avete spazio dei nomi Citycon classe B- ci B::classavrebbe funzionato bene, ma se devi usare quelli per esempio namespace Jungle- chiamando B::classlì senza includere con useprovocherebbe Jungle\B(! Anche se Jungle NON ha B a tutti)
jave.web

22

Questo

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

1
+1 Questo sarebbe perché non riesco a trovare alcuna funzione PHP procedurale integrata per ottenere costanti di classe, il che è un po 'un peccato.
BoltClock

1
Probabilmente perché non ce n'è bisogno. L'OP potrebbe voler fare una meta-configurazione impostando typescome all constants this class has, che nella maggior parte dei casi, e secondo la mia opinione limitata concessa, sono probabilmente meglio serviti con l'ereditarietà o una variabile di matrice statica con i tipi (lasciando spazio alle costanti con altri significati / uso).
Wrikken,

16

Usa token_get_all () . Vale a dire:

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

Produzione:

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

1
+1, anche se direi che questo è un ottimo momento per usare Reflection, come menzionato da altri poster, è anche importante capire i meccanismi "nascosti" ed essere in grado di farne a meno o replicarli se necessario. Bello spettacolo.
Dereleased

1
Se non vuoi che la tua classe venga caricata in memoria, token_get_all è una fantastica alternativa. È MOLTO più veloce di Reflection e non ingombra la memoria di processo se è necessario farlo con molte classi.
Harold,

+1 per la soluzione basata su token! Comprendere l'analisi basata su token è un piacere considerando le prestazioni ... e come sempre c'è una grande persona che mostra come analizzare le costanti tramite token_get_all (). Grazie mille!
mwatzer,

Presumibilmente, questo agisce solo sul singolo file e non eredita alcuna costante dalle classi principali. In effetti, questa tecnica non si preoccupa nemmeno della classe: ti darà tutte le costanti nel file, anche nell'ambito globale. È comunque un ottimo strumento da esplorare.
Jason,


13

Secondo i commenti dei documenti PHP, se sei in grado di utilizzare ReflectionClass (PHP 5):

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

La fonte è qui


9

Usando ReflectionClass e getConstants()dà esattamente quello che vuoi:

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

Produzione:

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

6

Tratto con metodo statico - in soccorso

Sembra che sia un bel posto per usare Traits con una funzione statica per estendere la funzionalità di classe. I tratti ci permetteranno anche di implementare questa funzionalità in qualsiasi altra classe senza riscrivere lo stesso codice più e più volte (rimanere SECCHI).

Usa il nostro tratto 'ConstantExport' personalizzato con nella classe Profile. Fallo per ogni classe di cui hai bisogno di questa funzionalità.

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

}

ESEMPIO DI UTILIZZO

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

print_r($constList); // TEST

USCITE:

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

5

Sì, usi la riflessione . Guarda l'output di

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

Questo dovrebbe darti l'idea di quello che guarderai.


4

È utile disporre di un metodo all'interno della classe per restituire le proprie costanti.
Puoi fare così:

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

Perché non inserirli in una variabile di classe come array per cominciare? Semplifica il looping.

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

2
Perché le matrici non sono costanti? Se si implementa qualcosa che dovrebbe essere una costante come variabile, si rischia che venga inavvertitamente modificata o disinserita. In altre parole, non puoi dipendere dal fatto che rimangano costanti.
GordonM,

3

Alla fine con spazi dei nomi:

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_());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.