Obtenha o valor da constante de classe escolhida dinamicamente em PHP

114

Eu gostaria de ser capaz de fazer algo assim:

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

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

Isso não funciona. Existe uma maneira direta de fazer algo equivalente? Observe que estou preso à classe; está em uma biblioteca que não consigo reescrever. Estou escrevendo um código que usa argumentos na linha de comando e gostaria muito que recebesse nomes simbólicos em vez de números de id.

Ben
fonte
Você pode tentar ThingIDs::{$thing}?
David Rodrigues
Já tentei. Obtém um erro de análise em vez de um erro fatal de tempo de execução.
Ben

Respostas:

182

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

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

Dan Simon
fonte
1
Observação lateral: se você quiser primeiro verificar se a constante está definida ou não, édefined("ThingIDs::$thing");
Parris Varney
3
ou $ id = constant ("self :: $ thing");
Linha
3
Semelhante a este,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum
4
@DavidBaucum, por que você quer complicar demais isso? A solicitação é bastante simples e não envolve entrada externa manipulável pelo usuário. Além disso, você está chamando outra função porque, eu acho, você não gosta que a string seja concatenada com delimitadores?
ReSpawN
5
Dependendo do seu caso de uso, minha solução é menos complicada. Especificamente se você estiver usando o carregamento automático do PSR-4, pode ser desagradável em seu código ter o FQDN escrito em todos os lugares. Usar usena parte superior do arquivo e, em seguida, usar o ::classmétodo para obter magicamente o FQDN melhora a legibilidade.
David Baucum
27

Use Reflexão

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);
Phil
fonte
3
As reflexões realmente fornecem muitos insights sobre classes, métodos e muito mais e parece que muitas pessoas têm medo de dar esse passo para entendê-los. Ótima resposta.
Mike Mackintosh
2
@mikemackintosh Eu dei alguns passos para entendê-los, mas não vi muito em termos de impacto no desempenho em relação à resposta aceita. ISSO é algo que estou interessado em saber. Instanciar uma nova classe parece ter um impacto de desempenho maior do que simplesmente chamar uma constante estaticamente. Quais são seus pensamentos sobre isso?
dudewad
13

Se você estiver usando namespaces, deverá incluir o namespace com a classe.

echo constant('My\Application\ThingClass::ThingConstant'); 
Jordi Kroon
fonte
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
fonte
3

Função auxiliar

Você pode usar uma função como esta:

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

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

Leva dois argumentos:

  • Nome da classe ou instância do objeto
  • Nome da constante de classe

Se uma instância de objeto é passada, seu nome de classe é inferido. Se você usa o PHP 7, pode usar ::classpara passar o nome da classe apropriado sem ter que pensar em namespaces.

Exemplos

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
fonte
0

Se você tiver uma referência à própria classe, poderá fazer o seguinte:

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

Meu problema era semelhante a este assunto. Quando você tem o objeto, mas não o nome da classe, pode usar:

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

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