获取PHP中动态选择的类常量的值


114

我希望能够执行以下操作:

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

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

这行不通。有一种简单的方法可以做一些等效的事情吗?请注意,我一直在上课。它在我无法重写的库中。我正在编写在命令行上接受参数的代码,我真的希望它接受符号名而不是ID号。


你可以尝试ThingIDs::{$thing}吗?
David Rodrigues

已经尝试过。让我得到一个解析错误,而不是一个致命的运行时错误。

Answers:


182

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

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


1
旁注:如果您要首先检查是否定义了常量,则为defined("ThingIDs::$thing");
Parris Varney 2014年

3
或$ id = constant(“ self :: $ thing”);
在线

3
与此类似$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum '16

4
@DavidBaucum为什么要使这个复杂化?该请求非常简单,不涉及外部用户可操纵的输入。除此之外,您正在调用另一个函数,因为我想您不希望将字符串与定界符连接在一起?
ReSpawN

5
根据您的用例,我的解决方案不太复杂。具体来说,如果您使用的是PSR-4自动加载功能,则在代码中很难在所有位置都清楚说明FQDN。通过use在文件顶部使用,然后使用该::class方法神奇地获取FQDN,可以提高可读性。
David Baucum '16

27

使用反射

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

3
反射确实提供了对类,方法以及更多内容的大量洞察力,而且似乎很多人都害怕采取这一步骤来理解它们。好答案。
Mike Mackintosh

2
@mikemackintosh我已采取步骤来理解它们,但是在性能影响和接受的答案方面并没有看到太多。这是我感兴趣的事情。实例化一个新类似乎比简单地静态调用一个常量会带来更大的性能影响。您对此有何看法?
dudewad

13

如果使用名称空间,则应在类中包括名称空间。

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

辅助功能

您可以使用如下功能:

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

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

它有两个参数:

  • 类名或对象实例
  • 类常量名称

如果传递了对象实例,则推断其类名。如果使用PHP 7,则可以使用::class传递适当的类名,而不必考虑名称空间。

例子

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

如果您有对类本身的引用,则可以执行以下操作:

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

0

我的问题与此主题相似。当有对象但没有类名时,可以使用:

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

$constant_value = constant($class_name.'::'.$class_const);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.