161

I have several CONST's defined on some classes, and want to get a list of them. For example:

class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";
}

Is there any way to get a list of the CONST's defined on the Profile class? As far as I can tell, the closest option(get_defined_constants()) won't do the trick.

What I actually need is a list of the constant names - something like this:

array('LABEL_FIRST_NAME',
    'LABEL_LAST_NAME',
    'LABEL_COMPANY_NAME')

Or:

array('Profile::LABEL_FIRST_NAME', 
    'Profile::LABEL_LAST_NAME',
    'Profile::LABEL_COMPANY_NAME')

Or even:

array('Profile::LABEL_FIRST_NAME'=>'First Name', 
    'Profile::LABEL_LAST_NAME'=>'Last Name',
    'Profile::LABEL_COMPANY_NAME'=>'Company')
Charles
  • 50,943
  • 13
  • 104
  • 142
Brock Boland
  • 15,870
  • 11
  • 35
  • 36
  • Using Reflection, and a ReflectionClass on Cl, you can use the function getConstants http://nz.php.net/manual/en/class.reflectionclass.php – Tim Ebenezer Dec 09 '09 at 09:54
  • [Reflection will be your savior](http://se2.php.net/manual/en/reflectionclass.getconstants.php). – Björn Dec 09 '09 at 09:55
  • You can do this using [reflection](http://nz.php.net/oop5.reflection). Search for "Print class constants" on that page to see an example. – n3rd Jun 05 '09 at 15:16

12 Answers12

283

You can use Reflection for this. Note that if you are doing this a lot you may want to looking at caching the result.

<?php
class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";
}


$refl = new ReflectionClass('Profile');
print_r($refl->getConstants());

Output:

Array
(
    'LABEL_FIRST_NAME' => 'First Name',
    'LABEL_LAST_NAME' => 'Last Name',
    'LABEL_COMPANY_NAME' => 'Company'
)
datashaman
  • 8,301
  • 3
  • 22
  • 29
Tom Haigh
  • 57,217
  • 21
  • 114
  • 142
  • 4
    Two minor NBs: first, in 5.3, `Profile` can be used as the argument to the reflector constructor, without quotes (a simple class name); second, to be completely clear, the resulting array’s keys are strings, not constants as the formatting here might be taken to suggest. (Worth mentioning only as the fn is [undocumented](http://www.php.net/manual/en/reflectionclass.getconstants.php).) – Benji XVI May 16 '11 at 23:08
  • 11
    @Benji XVI In 5.3 if you have notices turned on, you won't be able to use `Profile` without the quotes, as it will show the following error: Notice: Use of undefined constant Profile - assumed 'Profile'. So I suggest keeping the quotes `'Profile'` – toneplex Jun 28 '11 at 15:28
  • 10
    It is good to define constants related logic inside of class, so you don't need to hardcode constructor argument but use `__CLASS__` instead. – Luke Adamczewski Mar 27 '13 at 10:57
  • 9
    ```new ReflectionClass(Profile::class)``` works fine too – mtizziani Sep 22 '16 at 11:32
  • @mtizziani true, but be aware of namespaces ! Let's say you have namespace `City` with class `B` - there `B::class` would work fine, but if you'd use those in e.g. namespace `Jungle` - calling `B::class` there without including it with `use` would result in `Jungle\B` (even though Jungle does NOT have B at all!) – jave.web Sep 05 '19 at 18:07
23

This

 $reflector = new ReflectionClass('Status');
 var_dump($reflector->getConstants());
Wrikken
  • 69,272
  • 8
  • 97
  • 136
  • 2
    +1 This would be it since I can't find any built-in procedural PHP functions for getting class constants, which is a bit of a shame. – BoltClock Oct 15 '10 at 23:14
  • 1
    Probably because there is little need for it. The OP might want to do a meta-configuration by setting `types` as `all constants this class has`, which in most cases, and in my granted limited opinion, are probably better served with either inheritance or a static array variable with the types (leaving room for constants with other meanings / use). – Wrikken Oct 15 '10 at 23:19
  • how is this any different than the accepted answer posted in 2009? – But those new buttons though.. Dec 02 '20 at 17:30
  • 1
    @billynoah: answers on questions which get marked as duplicate later that are this old tend to get merged if you did not realize :) You might come across more of this on SO. This is indeed not different from the accepted answer. It however probably was at some point in time the accepted answer to a now removed-as-duplicate question. – Wrikken Dec 17 '20 at 21:04
  • @Wrikken - that makes a lot of sense. Thanks for explaining – But those new buttons though.. Dec 17 '20 at 22:37
17

Use token_get_all(). Namely:

<?php
header('Content-Type: text/plain');

$file = file_get_contents('Profile.php');
$tokens = token_get_all($file);

$const = false;
$name = '';
$constants = array();
foreach ($tokens as $token) {
    if (is_array($token)) {
        if ($token[0] != T_WHITESPACE) {
            if ($token[0] == T_CONST && $token[1] == 'const') {
                $const = true;
                $name = '';
            } else if ($token[0] == T_STRING && $const) {
                $const = false;
                $name = $token[1];
            } else if ($token[0] == T_CONSTANT_ENCAPSED_STRING && $name) {
                $constants[$name] = $token[1];
                $name = '';
            }
        }
    } else if ($token != '=') {
        $const = false;
        $name = '';
    }
}

foreach ($constants as $constant => $value) {
    echo "$constant = $value\n";
}
?>

Output:

LABEL_FIRST_NAME = "First Name"
LABEL_LAST_NAME = "Last Name"
LABEL_COMPANY_NAME = "Company"
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 3
    +1, even though I would say this is an excellent time to use Reflection as mentioned by other posters, it is also important to understand the workings "under-the-hood" and be able to do without them or replicate them if necessary. Good show. – Dereleased Dec 02 '09 at 19:26
  • 1
    If you don't want your class to be loaded into memory, token_get_all is a fantastic alternative. It's MUCH faster than Reflection and doesn't clutter the process memory if you need to do this with lots of classes. – Harold Jul 18 '15 at 10:16
  • +1 for the token-based solution! Understanding token-based parsing is a pleasure considering the performance ... and as always there is one great person who shows off how to parse constants via token_get_all(). Thank you very much! – mwatzer Sep 01 '16 at 21:18
  • Presumably this acts on the single file only, and does not inherit any constants from parent classes. In fact, this technique does not even care about the class - it will give you all constants in the file, even in the global scope. It's a great tool to explore though. – Jason Nov 20 '18 at 10:57
15

In PHP5 you can use Reflection: (manual reference)

$class = new ReflectionClass('Profile');
$consts = $class->getConstants();
OzzyCzech
  • 9,713
  • 3
  • 50
  • 34
Parsingphase
  • 501
  • 5
  • 10
13

Per the PHP docs comments, if you're able to use the ReflectionClass (PHP 5):

function GetClassConstants($sClassName) {
    $oClass = new ReflectionClass($sClassName);
    return $oClass->getConstants();
}

Source is here.

AlienWebguy
  • 76,997
  • 17
  • 122
  • 145
mway
  • 4,334
  • 3
  • 26
  • 37
9

Using ReflectionClass and getConstants() gives exactly what you want:

<?php
class Cl {
    const AAA = 1;
    const BBB = 2;
}
$r = new ReflectionClass('Cl');
print_r($r->getConstants());

Output:

Array
(
    [AAA] => 1
    [BBB] => 2
)
Ben James
  • 121,135
  • 26
  • 193
  • 155
9

It is handy to have a method inside the class to return its own constants.
You can do this way:

class Profile {
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";


    public static function getAllConsts() {
        return (new ReflectionClass(get_class()))->getConstants();
    }
}

// test
print_r(Profile::getAllConsts());
Saic Siquot
  • 6,513
  • 5
  • 34
  • 56
8

Trait with static method - to the rescue

Looks like it is a nice place to use Traits with a static function to extend class functionality. Traits will also let us implement this functionality in any other class without rewriting the same code over and over again (stay DRY).

Use our custom 'ConstantExport' Trait with in Profile class. Do it for every class that you need this functionality.

/**
 * ConstantExport Trait implements getConstants() method which allows 
 * to return class constant as an assosiative array
 */
Trait ConstantExport 
{
    /**
     * @return [const_name => 'value', ...]
     */
    static function getConstants(){
        $refl = new \ReflectionClass(__CLASS__);
        return $refl->getConstants();
    }
}

Class Profile 
{
    const LABEL_FIRST_NAME = "First Name";
    const LABEL_LAST_NAME = "Last Name";
    const LABEL_COMPANY_NAME = "Company";

    use ConstantExport;

}

USE EXAMPLE

// So simple and so clean
$constList = Profile::getConstants(); 

print_r($constList); // TEST

OUTPUTS:

Array
(
    [LABEL_FIRST_NAME] => First Name
    [LABEL_LAST_NAME] => Last Name
    [LABEL_COMPANY_NAME] => Company
)
Antoine
  • 800
  • 3
  • 14
  • 29
DevWL
  • 17,345
  • 6
  • 90
  • 86
5

Yeah, you use reflection. Look at the output of

<?
Reflection::export(new ReflectionClass('YourClass'));
?>

That should give you the idea of what you'll be looking at.

chaos
  • 122,029
  • 33
  • 303
  • 309
3

Eventually with namespaces:

namespaces enums;
class enumCountries 
{
  const CountryAustria          = 1 ;
  const CountrySweden           = 24;
  const CountryUnitedKingdom    = 25;
}

namespace Helpers;
class Helpers
{
  static function getCountries()
  {
    $c = new \ReflectionClass('\enums\enumCountries');
    return $c->getConstants();
  }
}

print_r(\Helpers\Helpers::getCountries());
revoke
  • 529
  • 4
  • 9
3

Why not put them in a class variable as an array to begin with? Makes it easier to loop thru.

private $_data = array("production"=>0 ...);
Detect
  • 2,049
  • 1
  • 12
  • 21
  • 4
    Because arrays aren't constants? If you implement something that's supposed to be a constant as a variable then you risk it getting inadvertently changed or unset. In other words you can't depend on them remaining constant. – GordonM Jul 21 '11 at 08:29
1
class Qwerty 
{
    const __COOKIE_LANG_NAME__ = "zxc";
    const __UPDATE_COOKIE__ = 30000;

    // [1]
    public function getConstants_(){

        return ['__COOKIE_LANG_NAME__' => self::__COOKIE_LANG_NAME__, 
                '__UPDATE_COOKIE__' => self::__UPDATE_COOKIE__]; 
    }    

    // [2]
    static function getConstantsStatic_(){

        return ['__COOKIE_LANG_NAME__' => self::__COOKIE_LANG_NAME__, 
                '__UPDATE_COOKIE__' => self::__UPDATE_COOKIE__]; 
    } 
}

// [1]
$objC = new Qwerty();
var_dump($objC->getConstants_());

// [2]
var_dump(Qwerty::getConstantsStatic_());
Kerem
  • 11,377
  • 5
  • 59
  • 58