Obtenir la valeur de la constante de classe choisie dynamiquement en PHP

114

J'aimerais pouvoir faire quelque chose comme ceci:

class ThingIDs
{
    const Something = 1;
    const AnotherThing = 2;
}

$thing = 'Something';
$id = ThingIDs::$thing;

Cela ne marche pas. Existe-t-il un moyen simple de faire quelque chose d'équivalent? Notez que je suis coincé avec la classe; c'est dans une bibliothèque que je ne peux pas réécrire. J'écris du code qui prend des arguments sur la ligne de commande, et j'aimerais vraiment qu'il prenne des noms symboliques au lieu de numéros d'identification.

Ben
la source
Pouvez-vous essayer ThingIDs::{$thing}?
David Rodrigues
Déjà essayé. Obtient une erreur d'analyse au lieu d'une erreur d'exécution fatale.
Ben

Réponses:

183

$id = constant("ThingIDs::$thing");

http://php.net/manual/en/function.constant.php

Dan Simon
la source
1
Note latérale: si vous voulez d'abord vérifier si la constante est définie ou non, c'estdefined("ThingIDs::$thing");
Parris Varney
3
ou $ id = constant ("self :: $ thing");
Ligne
3
Similaire à ceci,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum
4
@DavidBaucum pourquoi voudriez-vous trop compliquer cela? La demande est assez simple et n'implique aucune entrée externe manipulable par l'utilisateur. En dehors de cela, vous appelez une autre fonction parce que, je suppose, vous n'aimez pas que la chaîne soit concaténée avec des délimiteurs?
ReSpawN
5
En fonction de votre cas d'utilisation, ma solution est moins compliquée. Plus précisément, si vous utilisez le chargement automatique du PSR-4, il peut être moche dans votre code d'avoir le FQDN épelé partout. En utilisant useen haut du fichier, puis en utilisant la ::classméthode pour obtenir le nom de domaine complet par magie, améliore la lisibilité.
David Baucum
27

Utiliser la réflexion

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);
Phil
la source
3
Les réflexions fournissent vraiment beaucoup d'informations sur les classes, les méthodes et plus encore et il semble que beaucoup de gens aient peur de franchir cette étape pour les comprendre. Très bonne réponse.
Mike Mackintosh
2
@mikemackintosh J'ai pris des mesures pour les comprendre, mais je n'ai pas vu grand-chose en termes d'impact sur les performances par rapport à la réponse acceptée. C'est quelque chose que je veux savoir. L'instanciation d'une nouvelle classe semble avoir un plus gros impact sur les performances que de simplement appeler une constante de manière statique. Que pensez-vous de cela?
dudewad
13

Si vous utilisez des espaces de noms, vous devez inclure l'espace de noms avec la classe.

echo constant('My\Application\ThingClass::ThingConstant'); 
Jordi Kroon
la source
3
<?php

class Dude {
    const TEST = 'howdy';
}

function symbol_to_value($symbol, $class){
    $refl = new ReflectionClass($class);
    $enum = $refl->getConstants();
    return isset($enum[$symbol])?$enum[$symbol]:false;
}

// print 'howdy'
echo symbol_to_value('TEST', 'Dude');
Josh
la source
3

Fonction d'assistance

Vous pouvez utiliser une fonction comme celle-ci:

function class_constant($class, $constant)
{
    if ( ! is_string($class)) {
        $class = get_class($class);
    }

    return constant($class . '::' . $constant);
}

Cela prend deux arguments:

  • Nom de classe ou instance d'objet
  • Nom de la constante de classe

Si une instance d'objet est transmise, son nom de classe est déduit. Si vous utilisez PHP 7, vous pouvez utiliser ::classpour passer le nom de classe approprié sans avoir à penser aux espaces de noms.

Exemples

class MyClass
{
    const MY_CONSTANT = 'value';
}

class_constant('MyClass', 'MY_CONSTANT'); # 'value'
class_constant(MyClass::class, 'MY_CONSTANT'); # 'value' (PHP 7 only)

$myInstance = new MyClass;
class_constant($myInstance, 'MY_CONSTANT'); # 'value'
Glutexo
la source
0

Si vous avez une référence à la classe elle-même, vous pouvez effectuer les opérations suivantes:

if (defined(get_class($course). '::COURSES_PER_INSTANCE')) {
   // class constant is defined
}
crmpicco
la source
0

Mon problème était similaire à ce sujet. Lorsque vous avez l'objet, mais pas le nom de la classe, vous pouvez utiliser:

$class_name = get_class($class_object);
$class_const = 'My_Constant';

$constant_value = constant($class_name.'::'.$class_const);
Andrei
la source