Obtener el valor de la constante de clase elegida dinámicamente en PHP

114

Me gustaría poder hacer algo como esto:

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

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

Esto no funciona. ¿Existe una forma sencilla de hacer algo equivalente? Tenga en cuenta que estoy atrapado con la clase; está en una biblioteca que no puedo reescribir. Estoy escribiendo código que toma argumentos en la línea de comando, y realmente me gustaría que tomara nombres simbólicos en lugar de números de identificación.

Ben
fuente
Se puede tratar ThingIDs::{$thing}?
David Rodrigues
Ya probado. Obtiene un error de análisis en lugar de un error de tiempo de ejecución fatal.
Ben

Respuestas:

183

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

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

Dan Simon
fuente
1
Nota al margen: si desea verificar primero si la constante está definida o no, esdefined("ThingIDs::$thing");
Parris Varney
3
o $ id = constante ("self :: $ cosa");
Línea
3
Similar a esto,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum
4
@DavidBaucum, ¿por qué querrías complicar demasiado esto? La solicitud es bastante simple y no implica ninguna entrada externa manipulable por el usuario. Aparte de eso, está llamando a otra función porque, supongo, ¿no le gusta que la cadena se concatene con delimitadores?
ReSpawN
5
Dependiendo de su caso de uso, mi solución es menos complicada. Específicamente, si está utilizando la carga automática PSR-4, entonces puede ser desagradable en su código tener el FQDN escrito en todas partes. Al usarlo useen la parte superior del archivo y luego usar el ::classmétodo para obtener mágicamente el FQDN, mejora la legibilidad.
David Baucum
27

Usar Reflexión

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);
Phil
fuente
3
Las reflexiones realmente proporcionan mucha información sobre las clases, los métodos y más, y parece que mucha gente tiene miedo de dar ese paso para comprenderlos. Gran respuesta.
Mike Mackintosh
2
@mikemackintosh He tomado medidas para comprenderlos, pero no he visto mucho en términos de impacto en el rendimiento frente a la respuesta aceptada. ESO es algo que me interesa saber. La creación de instancias de una nueva clase parece tener un impacto de rendimiento mayor que simplemente llamar a una constante estáticamente. ¿Qué piensas sobre eso?
dudewad
13

Si está utilizando espacios de nombres, debe incluir el espacio de nombres con la clase.

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

Función auxiliar

Puedes usar una función como esta:

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

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

Se necesitan dos argumentos:

  • Nombre de clase o instancia de objeto
  • Nombre constante de clase

Si se pasa una instancia de objeto, se infiere su nombre de clase. Si usa PHP 7, puede usar ::classpara pasar el nombre de clase apropiado sin tener que pensar en los espacios de nombres.

Ejemplos

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

Si tiene una referencia a la clase en sí, puede hacer lo siguiente:

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

Mi problema era similar a este tema. Cuando tenga el objeto, pero no el nombre de la clase, puede usar:

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

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