Bisakah saya mendefinisikan CONST di kelas PHP?

140

Saya memiliki beberapa CONST yang didefinisikan pada beberapa kelas, dan ingin mendapatkan daftar mereka. Sebagai contoh:

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

Apakah ada cara untuk mendapatkan daftar CONST yang ditentukan di Profilekelas? Sejauh yang saya tahu, opsi terdekat ( get_defined_constants()) tidak akan berhasil.

Apa yang sebenarnya saya butuhkan adalah daftar nama konstan - sesuatu seperti ini:

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

Atau:

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

Atau bahkan:

array('Profile::LABEL_FIRST_NAME'=>'First Name', 
    'Profile::LABEL_LAST_NAME'=>'Last Name',
    'Profile::LABEL_COMPANY_NAME'=>'Company')
Brock Boland
sumber
Anda dapat melakukan ini menggunakan refleksi . Cari "Cetak konstanta kelas" di halaman itu untuk melihat contoh.
n3rd
Menggunakan Reflection, dan ReflectionClass pada Cl, Anda dapat menggunakan fungsi getConstants nz.php.net/manual/en/class.reflectionclass.php
Tim Ebenezer

Jawaban:

245

Anda dapat menggunakan Refleksi untuk ini. Perhatikan bahwa jika Anda sering melakukan ini, Anda mungkin ingin melihat caching hasilnya.

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

Keluaran:

Array
(
    'LABEL_FIRST_NAME' => 'First Name',
    'LABEL_LAST_NAME' => 'Last Name',
    'LABEL_COMPANY_NAME' => 'Company'
)
Tom Haigh
sumber
4
Dua NB kecil: pertama, dalam 5.3, Profiledapat digunakan sebagai argumen untuk konstruktor reflektor, tanpa tanda kutip (nama kelas sederhana); kedua, agar sepenuhnya jelas, kunci array yang dihasilkan adalah string, bukan konstanta karena pemformatan di sini mungkin diambil untuk menyarankan. (Layak disebutkan hanya karena fn tidak berdokumen .)
Benji XVI
11
@Benji XVI Di 5.3 jika Anda telah mengaktifkan pemberitahuan, Anda tidak akan dapat menggunakan Profiletanpa tanda kutip, karena akan menampilkan kesalahan berikut: Pemberitahuan: Penggunaan Profil konstan yang tidak terdefinisi - diasumsikan 'Profil'. Jadi saya sarankan menyimpan tanda kutip'Profile'
toneplex
10
Adalah baik untuk mendefinisikan konstanta terkait logika di dalam kelas, jadi Anda tidak perlu argumen konstruktor hardcode tetapi gunakan __CLASS__sebagai gantinya.
Luke Adamczewski
7
new ReflectionClass(Profile::class)berfungsi dengan baik juga
mtizziani
@ mtizziani benar, tapi waspadalah dengan ruang nama! Katakanlah Anda memiliki namespace Citydengan kelas B- B::classakan berfungsi dengan baik, tetapi jika Anda akan menggunakan namespace misalnya Jungle- memanggil ke B::classsana tanpa menyertakannya useakan menghasilkan Jungle\B(walaupun Jungle TIDAK memiliki B sama sekali!)
jave.web
22

Ini

 $reflector = new ReflectionClass('Status');
 var_dump($reflector->getConstants());
Terkutuk
sumber
1
+1 Ini karena saya tidak dapat menemukan fungsi PHP prosedural bawaan untuk mendapatkan konstanta kelas, yang agak memalukan.
BoltClock
1
Mungkin karena ada sedikit kebutuhan untuk itu. OP mungkin ingin melakukan meta-konfigurasi dengan menetapkan typessebagai all constants this class has, yang dalam kebanyakan kasus, dan menurut pendapat saya yang terbatas, mungkin lebih baik dilayani dengan pewarisan atau variabel array statis dengan tipe (meninggalkan ruang untuk konstanta dengan makna lain / menggunakan).
Wrikken
16

Gunakan token_get_all () . Yaitu:

<?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";
}
?>

Keluaran:

LABEL_FIRST_NAME = "First Name"
LABEL_LAST_NAME = "Last Name"
LABEL_COMPANY_NAME = "Company"
cletus
sumber
1
+1, meskipun saya akan mengatakan ini adalah waktu yang tepat untuk menggunakan Refleksi seperti yang disebutkan oleh poster lain, penting juga untuk memahami cara kerja "di bawah tenda" dan dapat melakukannya tanpa mereka atau menggandakannya jika perlu. Pertunjukan yang bagus.
Dereleased
1
Jika Anda tidak ingin kelas Anda dimuat ke dalam memori, token_get_all adalah alternatif yang fantastis. Ini JAUH lebih cepat dari Refleksi dan tidak mengacaukan memori proses jika Anda perlu melakukan ini dengan banyak kelas.
Harold
+1 untuk solusi berbasis token! Memahami parsing berbasis token adalah kesenangan mempertimbangkan kinerja ... dan seperti biasa ada satu orang hebat yang memamerkan cara mengurai konstanta melalui token_get_all (). Terima kasih banyak!
mwatzer
Agaknya ini hanya berlaku pada file tunggal, dan tidak mewarisi konstanta dari kelas induk. Bahkan, teknik ini bahkan tidak peduli dengan kelas - itu akan memberi Anda semua konstanta dalam file, bahkan dalam lingkup global. Ini adalah alat yang hebat untuk dijelajahi.
Jason
14

Di PHP5 Anda dapat menggunakan Reflection: (referensi manual)

$class = new ReflectionClass('Profile');
$consts = $class->getConstants();
Parsingphase
sumber
13

Per komentar dokumen PHP, jika Anda dapat menggunakan ReflectionClass (PHP 5):

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

Sumber ada di sini.

mway
sumber
9

Menggunakan ReflectionClass dan getConstants()memberikan apa yang Anda inginkan:

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

Keluaran:

Array
(
    [AAA] => 1
    [BBB] => 2
)
Ben James
sumber
6

Ciri dengan metode statis - untuk menyelamatkan

Sepertinya itu adalah tempat yang bagus untuk menggunakan Ciri-ciri dengan fungsi statis untuk memperluas fungsionalitas kelas. Ciri juga akan memungkinkan kami menerapkan fungsi ini di kelas lain tanpa menulis ulang kode yang sama berulang-ulang (tetap KERING).

Gunakan sifat 'ConstantExport' khusus kami dengan di kelas Profil. Lakukan untuk setiap kelas yang Anda perlukan fungsi ini.

/**
 * 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;

}

CONTOH PENGGUNAAN

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

print_r($constList); // TEST

OUTPUT:

Array
(
    [LABEL_FIRST_NAME] => First Name
    [LABEL_LAST_NAME] => Last Name
    [LABEL_COMPANY_NAME] => Company
)
DevWL
sumber
5

Ya, Anda menggunakan refleksi . Lihatlah output dari

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

Itu akan memberi Anda gagasan tentang apa yang akan Anda lihat.

kekacauan
sumber
4

Sangat berguna untuk memiliki metode di dalam kelas untuk mengembalikan konstanta sendiri.
Anda bisa melakukan ini:

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());
Luis Siquot
sumber
3

Mengapa tidak menempatkan mereka dalam variabel kelas sebagai array untuk memulai? Mempermudah untuk mengulang melalui.

private $_data = array("production"=>0 ...);
Deteksi
sumber
2
Karena array bukan konstanta? Jika Anda menerapkan sesuatu yang seharusnya berupa konstanta sebagai variabel, maka Anda berisiko mengubahnya secara tidak sengaja atau tidak disetel. Dengan kata lain Anda tidak dapat bergantung pada mereka tetap konstan.
GordonM
3

Akhirnya dengan ruang nama:

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());
mencabut
sumber
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_());
Юрий Светлов
sumber