Uzyskaj wartość dynamicznie wybranej stałej klasy w PHP

114

Chciałbym móc zrobić coś takiego:

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

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

To nie działa. Czy istnieje prosty sposób na zrobienie czegoś równoważnego? Zwróć uwagę, że utknąłem z klasą; jest w bibliotece, której nie mogę przepisać. Piszę kod, który przyjmuje argumenty w wierszu poleceń i naprawdę chciałbym, aby przyjmował nazwy symboliczne zamiast numerów identyfikacyjnych.

Ben
źródło
Możesz spróbować ThingIDs::{$thing}?
David Rodrigues
Już próbowałem. Pobiera mi błąd analizy zamiast krytycznego błędu czasu wykonania.
Ben

Odpowiedzi:

183

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

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

Dan Simon
źródło
1
Uwaga dodatkowa: jeśli chcesz najpierw sprawdzić, czy stała jest zdefiniowana, czy nie, to jestdefined("ThingIDs::$thing");
Parris Varney
3
lub $ id = constant ("self :: $ thing");
Linia
3
Podobnie,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum,
4
@DavidBaucum dlaczego chcesz to zbytnio komplikować? Żądanie jest dość proste i nie wymaga żadnych zewnętrznych danych wejściowych, którymi użytkownik mógłby manipulować. Poza tym wywołujesz inną funkcję, ponieważ, jak sądzę, nie chcesz, aby ciąg był łączony z ogranicznikami?
ReSpawN
5
W zależności od przypadku użycia moje rozwiązanie jest mniej skomplikowane. W szczególności, jeśli używasz automatycznego ładowania PSR-4, to może być brzydkie w twoim kodzie, że FQDN jest zapisane wszędzie. Użycie usew górnej części pliku, a następnie użycie ::classmetody magicznego uzyskania nazwy FQDN poprawia czytelność.
David Baucum
27

Użyj odbicia

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);
Phil
źródło
3
Refleksje naprawdę dostarczają wielu informacji o klasach, metodach i nie tylko, i wydaje się, że wiele osób boi się zrobić ten krok, aby je zrozumieć. Świetna odpowiedź.
Mike Mackintosh,
2
@mikemackintosh Podjąłem kroki, aby je zrozumieć, ale nie widziałem zbyt wiele pod względem wpływu na wydajność w porównaniu z akceptowaną odpowiedzią. TO jest coś, co chciałbym wiedzieć. Tworzenie instancji nowej klasy wydaje się mieć większy wpływ na wydajność niż zwykłe statyczne wywoływanie stałej. Co o tym myślisz?
dudewad
13

Jeśli używasz przestrzeni nazw, powinieneś dołączyć przestrzeń nazw do klasy.

echo constant('My\Application\ThingClass::ThingConstant'); 
Jordi Kroon
źródło
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
źródło
3

Funkcja pomocnicza

Możesz użyć takiej funkcji:

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

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

Wymaga dwóch argumentów:

  • Nazwa klasy lub instancja obiektu
  • Nazwa stałej klasy

Jeśli przekazana zostanie instancja obiektu, zostanie wywnioskowana nazwa jej klasy. Jeśli używasz PHP 7, możesz użyć ::classdo przekazania odpowiedniej nazwy klasy bez konieczności myślenia o przestrzeniach nazw.

Przykłady

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
źródło
0

Jeśli masz odwołanie do samej klasy, możesz wykonać następujące czynności:

if (defined(get_class($course). '::COURSES_PER_INSTANCE')) {
   // class constant is defined
}
crmpicco
źródło
0

Mój problem był podobny do tego tematu. Gdy masz obiekt, ale nie nazwę klasy, możesz użyć:

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

$constant_value = constant($class_name.'::'.$class_const);
Andrei
źródło