63

Assuming you have a constant defined in a class:

class Foo {
    const ERR_SOME_CONST = 6001;

    function bar() {
        $x = 6001;
        // need to get 'ERR_SOME_CONST'
    }
}

Is it possible with PHP?

10 Answers 10

68

You can get them with the reflection API

I'm assuming you would like to get the name of the constant based on the value of your variable (value of variable == value of constant). Get all the constants defined in the class, loop over them and compare the values of those constants with the value of your variable. Note that with this approach you might get some other constant that the one you want, if there are two constants with the same value.

example:

class Foo {
    const ERR_SOME_CONST = 6001;
    const ERR_SOME_OTHER_CONST = 5001;

    function bar() {
        $x = 6001;
        $fooClass = new ReflectionClass ( 'Foo' );
        $constants = $fooClass->getConstants();

        $constName = null;
        foreach ( $constants as $name => $value )
        {
            if ( $value == $x )
            {
                $constName = $name;
                break;
            }
        }

        echo $constName;
    }
}

ps: do you mind telling why you need this, as it seems very unusual ...

3
  • 1
    Nothing serious, actually. Just thinking of the way to pass error code from class function. As for me const ERR_SOME_ERROR='ERR_SOME_ERROR' looks strange, i thought my getLastError() function could return something like array(5003=>'ERR_SOME_ERROR',5002=>'ERR_SOME_ERR2') and so on. Just to have error code and error name returned. Well, the more i think of it, i'll probably will not use it (for the unusual syntax as you told) :) Commented Dec 10, 2009 at 11:09
  • also needed it for CURLE_* constant support where curl_multi_strerror was not available Commented Oct 3, 2013 at 8:36
  • 3
    I "need" something like this in order to provide a nicer error output without having to rewrite how we track certain error codes that are stored as constants.
    – Frug
    Commented Apr 21, 2015 at 14:30
40

Here's what I did to achieve it. Inspired by Jan Hancic.

class ErrorCode
{
    const COMMENT_NEWCOMMENT_DISABLED = -4;
    const COMMENT_TIMEBETWEENPOST_ERROR = -3;
    /**
     * Get error message of a value. It's actually the constant's name
     * @param integer $value
     * 
     * @return string
     */
    public static function getErrorMessage($value)
    {
        $constantNames = array_flip(
           array_filter(
               (new ReflectionClass(OrderStatus::class))->getConstants(),
                static fn($v) => is_scalar($v), // only int/string
           ),
        );

        return $constantNames[$value] ?? null;
    }
}
3
  • 3
    Just wanna say that this will not work if constants have the same value. Shouldn't be a problem most of the time, but yea...
    – Populus
    Commented Jun 24, 2014 at 20:20
  • 1
    I think this wouldn't work when a constant has an array as value as well..
    – DrKey
    Commented Jul 4, 2019 at 9:33
  • edited answer to allow arrays
    – raveren
    Commented Feb 8 at 16:18
14

With Reflection:

$class = new ReflectionClass("Foo");
$constants = $class->getConstants();

$constants is an array which holds all the names and values of the constants defined in class Foo.

14

All the other answers cover the essential points. But, if crazy one liners is your thing, then:

function getConstantName($class, $value)
{
    return array_flip((new \ReflectionClass($class))->getConstants())[$value];
}

If you need to handle the case where the value might not actually be one of the constants, then you can give up an extra line:

function getConstantName($class, $value)
{
    $map = array_flip((new \ReflectionClass($class))->getConstants());
    return (array_key_exists($value, $map) ? $map[$value] : null);
}
1
  • 1
    This is Easy and Quick Solution. Flip the Array and check for the Key. Commented Apr 12, 2016 at 8:15
13

I know this is an old question and all, but I still feel that I have some useful input. I implemented this using an abstract class that all my enums extend. The abstract class contains a generic toString() method;

abstract class BaseEnum{
    private final function __construct(){ }

    public static function toString($val){
        $tmp = new ReflectionClass(get_called_class());
        $a = $tmp->getConstants();
        $b = array_flip($a);

        return ucfirst(strtolower($b[$val]));
    }
}

//actual enum
final class UserType extends BaseEnum {
    const ADMIN = 10;
    const USER = 5;
    const VIEWER = 0;
}

This way you can get a human readable string to use in output, on every enum that extends the base enum. Furthermore, your implementation of the enum, being final, cannot be extended and because the constructor in the BaseEnum is private it can never be instantiated.

So for instance, if you show a list of all usernames with their types you can do something like

foreach($users as $user){
    echo "<li>{$user->name}, ".UserType::toString($user->usertype)."</li>";
}
5

All constant can be assigned to an array using this function.

$const = get_defined_constants();

then using following function you can print the array structure

echo "&lt;pre&gt;";

print_r($const);

and you can see more explanation here www.sugunan.com

3

Warning: This way you should NOT program... ( if youre not sure what youre doing :) )

I wrote 1 row which echos constants and their numeric values by your choice of CATEGORY_

so here is the list of CATEGORY_ ERR_

foreach(get_defined_constants() as $key => $value) if(strlen($key)>5) if(substr($key, 0,5)=="ERR_") echo"<br>Found an php ERR_ constant! : ".$key."=>".$value;

And if you want just the one youre looking for by number => I created 1row function:

//input parameters: CATEGORYNAME_ , #constantNumber
function getConstantName($category,$constantNumber){foreach(get_defined_constants() as $key => $value) if(strlen($key)>strlen($category)) if(substr($key, 0,strlen($category))==$category) if($value==$constantNumber) return $key; return "No constant found.";}

So for example some info constant with number 64:

echo "NameOfConstant: ".getConstantName("INFO_",64);

will output something like: NameOfConstant: INFO_LICENSE

2

OK, OK, I know everything is already covered :) But Jan Hančič asked for use case, so I'll share mine. Aside: everyone seems to use array_flip(). Why not array_search()?

I needed it in a class that extends \Exception and is base class of small set of my concrete exceptions. Each of those concrete exception classes covers a broad exception domain and has defined several precise exception causes. Reason? I don't want to have a horde of exceptions to maintain and remember of. Also, there is exception handler set that dumps exception's guts into log file - and it's here I need to get the constant name as trying to decipher exception cause from status in quite painful.

Examples from my CLI scripts:

class AbstractException extends Exception {
    public function getName() {
        return array_search($this->getCode(), (new ReflectionClass($this))->getConstants());
    }
}

class SyntaxException extends AbstractException {
    const BAD_SYNTAX = 90;
    const REQUIRED_PARAM = 91;
    const REQUIRED_VALUE = 92;
    const VALUE_TYPE = 93;
    const VALUE_OUT_OF_BOUNDS = 94;

    public function __construct ($message = "", $code = self::BAD_SYNTAX, Exception $previous = NULL) {
        $script = basename($GLOBALS['argv'][0]);

        echo "Invalid syntax: $message \nSee: `$script --help` for more information\n";
        parent::__construct($message, $code, $previous);
    }
}

// in autoload include
set_exception_handler(function(Exception $e) {
    error_log(basename($GLOBALS['argv'][0]) . ';'. date('Y-m-d H:i:s') .';'. $e->getName() .';'. $e->getMessage() .';'. $e->getFile() .';'. $e->getLine() ."\n", 3, 'error.log');
    exit ($e->getCode());
});
0
class OrderStatus
{
    public const PENDING = 1;
    public const PROCESSED  = 2;

    public static function getStatusCode($value)
    {
        $class = new ReflectionClass(__CLASS__);
        $constants = array_flip($class->getConstants());

        return $constants[$value] ?? null;
    }

    // OrderStatus::getStatusCode(1); // 'PENDING'

}
-1

if you need to get the constant value on a method of the same class, you just need to use the self operator. You could use reflection if you want to use the constants on another class

class Foo {
    const ERR_SOME_CONST = 6001;

    function bar() {
        self::ERR_SOME_CONST;
    }
}
1
  • 2
    That is not what the OP asked for. Commented Oct 16, 2018 at 14:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.