Ottieni il valore della costante di classe scelta dinamicamente in PHP


114

Mi piacerebbe poter fare qualcosa del genere:

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

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

Questo non funziona. C'è un modo semplice per fare qualcosa di equivalente? Nota che sono bloccato con la classe; è in una libreria che non posso riscrivere. Sto scrivendo codice che accetta argomenti sulla riga di comando e mi piacerebbe davvero che prendesse nomi simbolici invece di numeri id.


Puoi provare ThingIDs::{$thing}?
David Rodrigues

Già provato. Ottiene un errore di analisi invece di un errore irreversibile di runtime.
Ben

Risposte:


183

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

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


1
Nota a margine: se vuoi prima controllare se la costante è definita o meno, èdefined("ThingIDs::$thing");
Parris Varney

3
o $ id = costante ("self :: $ cosa");
Linea

3
Simile a questo,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum

4
@DavidBaucum, perché vorresti complicare troppo questo? La richiesta è abbastanza semplice e non comporta alcun input esterno manipolabile dall'utente. A parte questo, stai chiamando un'altra funzione perché, immagino, non ti piace che la stringa sia concatenata con delimitatori?
ReSpawN

5
A seconda del tuo caso d'uso, la mia soluzione è meno complicata. In particolare, se stai usando il caricamento automatico della PSR-4, può essere brutto nel tuo codice avere l'FQDN enunciato ovunque. Usando useall'inizio del file e quindi utilizzando il ::classmetodo per ottenere magicamente l'FQDN migliora la leggibilità.
David Baucum

27

Usa la riflessione

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);

3
Le riflessioni forniscono davvero molte informazioni su classi, metodi e altro e sembra che molte persone abbiano paura di fare quel passo per capirli. Bella risposta.
Mike Mackintosh

2
@mikemackintosh Ho preso provvedimenti per capirli, ma non ho visto molto in termini di impatto sulle prestazioni rispetto alla risposta accettata. QUESTO è qualcosa che mi interessa sapere. Creare un'istanza di una nuova classe sembra che avrebbe un rendimento maggiore rispetto alla semplice chiamata statica di una costante. Quali sono i tuoi pensieri al riguardo?
dudewad

13

Se stai usando gli spazi dei nomi, dovresti includere lo spazio dei nomi con la classe.

echo constant('My\Application\ThingClass::ThingConstant'); 

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');

3

Funzione di aiuto

Puoi usare una funzione come questa:

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

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

Ci vogliono due argomenti:

  • Nome della classe o istanza dell'oggetto
  • Nome della costante di classe

Se viene passata un'istanza di oggetto, viene dedotto il nome della sua classe. Se usi PHP 7, puoi usare ::classper passare il nome della classe appropriato senza dover pensare agli spazi dei nomi.

Esempi

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'

0

Se hai un riferimento alla classe stessa, puoi fare quanto segue:

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

0

Il mio problema era simile a questo argomento. Quando hai l'oggetto, ma non il nome della classe, puoi usare:

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

$constant_value = constant($class_name.'::'.$class_const);
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.