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.


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


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

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

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

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'

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
}

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);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.