Puis-je obtenir des CONST définis sur une classe PHP?


140

J'ai plusieurs CONST définis sur certaines classes et je veux en obtenir une liste. Par exemple:

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

Existe-t-il un moyen d'obtenir une liste des CONST définis sur la Profileclasse? Pour autant que je sache, l'option la plus proche ( get_defined_constants()) ne fera pas l'affaire.

Ce dont j'ai réellement besoin est une liste des noms constants - quelque chose comme ceci:

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

Ou:

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

Ou même:

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

Vous pouvez le faire en utilisant la réflexion . Recherchez «Constantes de classe d'impression» sur cette page pour voir un exemple.
n3rd

En utilisant Reflection et une ReflectionClass sur Cl, vous pouvez utiliser la fonction getConstants nz.php.net/manual/en/class.reflectionclass.php
Tim Ebenezer

Réponses:


245

Vous pouvez utiliser Reflection pour cela. Notez que si vous faites beaucoup cela, vous voudrez peut-être regarder la mise en cache du résultat.

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

Production:

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

4
Deux NBs mineurs: d'abord, en 5.3, Profilepeut être utilisé comme argument du constructeur du réflecteur, sans guillemets (un simple nom de classe); deuxièmement, pour être tout à fait clair, les clés du tableau résultant sont des chaînes, pas des constantes comme le formatage ici pourrait être supposé. (À mentionner uniquement car la fn n'est pas documentée .)
Benji XVI

11
@Benji XVI Dans 5.3, si vous avez des avis activés, vous ne pourrez pas utiliser Profilesans les guillemets, car il affichera l'erreur suivante: Remarque: Utilisation d'un profil constant non défini - supposé «Profil». Je suggère donc de garder les citations'Profile'
toneplex

10
Il est bon de définir la logique liée aux constantes à l'intérieur de la classe, vous n'avez donc pas besoin de coder en dur l'argument du constructeur mais de l'utiliser à la __CLASS__place.
Luke Adamczewski

7
new ReflectionClass(Profile::class)fonctionne bien aussi
mtizziani

@mtizziani vrai, mais attention aux espaces de noms! Disons que vous avez un espace Cityde noms avec class B- B::classcela fonctionnerait bien, mais si vous les utilisiez dans l'espace de noms par exemple Jungle- appeler B::classlà sans l'inclure avec useentraînerait Jungle\B(même si Jungle n'a PAS du tout B!)
jave.web

22

Ce

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

1
+1 Ce serait tout car je ne trouve aucune fonction PHP procédurale intégrée pour obtenir des constantes de classe, ce qui est un peu dommage.
BoltClock

1
Probablement parce qu'il n'y en a guère besoin. L'OP pourrait vouloir faire une méta-configuration en définissant typescomme all constants this class has, qui dans la plupart des cas, et à mon avis limité, sont probablement mieux servis avec l'héritage ou une variable de tableau statique avec les types (laissant de la place pour des constantes avec d'autres significations / utilisation).
Wrikken

16

Utilisez token_get_all () . À savoir:

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

Production:

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

1
+1, même si je dirais que c'est un excellent moment pour utiliser Reflection comme mentionné par d'autres affiches, il est également important de comprendre le fonctionnement «sous le capot» et de pouvoir s'en passer ou les reproduire si nécessaire. Bon spectacle.
Sorti

1
Si vous ne voulez pas que votre classe soit chargée en mémoire, token_get_all est une alternative fantastique. C'est BEAUCOUP plus rapide que Reflection et n'encombre pas la mémoire du processus si vous devez le faire avec beaucoup de classes.
Harold

+1 pour la solution basée sur les jetons! Comprendre l'analyse basée sur les jetons est un plaisir compte tenu des performances ... et comme toujours, il y a une personne formidable qui montre comment analyser les constantes via token_get_all (). Merci beaucoup!
mwatzer le

Vraisemblablement, cela n'agit que sur le fichier unique et n'hérite d'aucune constante des classes parentes. En fait, cette technique ne se soucie même pas de la classe - elle vous donnera toutes les constantes du fichier, même dans la portée globale. C'est un excellent outil à explorer.
Jason


13

Selon les commentaires de la documentation PHP, si vous pouvez utiliser ReflectionClass (PHP 5):

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

La source est ici.


9

En utilisant ReflectionClass et getConstants()donne exactement ce que vous voulez:

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

Production:

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

6

Trait avec méthode statique - à la rescousse

On dirait que c'est un bon endroit pour utiliser des traits avec une fonction statique pour étendre les fonctionnalités de classe. Les traits nous permettront également d'implémenter cette fonctionnalité dans n'importe quelle autre classe sans réécrire le même code encore et encore (restez DRY).

Utilisez notre trait personnalisé 'ConstantExport' avec la classe Profile. Faites-le pour chaque classe pour laquelle vous avez besoin de cette fonctionnalité.

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

}

EXEMPLE D'UTILISATION

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

print_r($constList); // TEST

LES SORTIES:

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

5

Ouais, vous utilisez la réflexion . Regardez la sortie de

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

Cela devrait vous donner une idée de ce que vous allez regarder.


4

Il est pratique d'avoir une méthode à l'intérieur de la classe pour renvoyer ses propres constantes.
Vous pouvez faire de cette façon:

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

Pourquoi ne pas les mettre dans une variable de classe sous forme de tableau pour commencer? Facilite la lecture en boucle.

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

2
Parce que les tableaux ne sont pas des constantes? Si vous implémentez quelque chose qui est censé être une constante en tant que variable, vous risquez de le modifier ou de le désactiver par inadvertance. En d'autres termes, vous ne pouvez pas compter sur leur constante.
GordonM

3

Finalement avec des espaces de noms:

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_());
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.