Dapatkan nilai konstanta kelas yang dipilih secara dinamis dalam PHP

114

Saya ingin bisa melakukan sesuatu seperti ini:

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

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

Ini tidak berhasil. Apakah ada cara langsung untuk melakukan sesuatu yang setara? Perhatikan bahwa saya terjebak dengan kelas; itu ada di perpustakaan yang tidak bisa saya tulis ulang. Saya sedang menulis kode yang membutuhkan argumen pada baris perintah, dan saya sangat ingin menggunakan nama simbolis daripada nomor id.

Ben
sumber
Dapatkah Anda mencoba ThingIDs::{$thing}?
David Rodrigues
Sudah mencoba. Memberi saya kesalahan parse, bukan kesalahan runtime fatal.
Ben

Jawaban:

183

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

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

Dan Simon
sumber
1
Catatan samping: jika Anda ingin memeriksa terlebih dahulu apakah konstanta ditentukan atau tidak, itudefined("ThingIDs::$thing");
Parris Varney
3
atau $ id = konstanta ("self :: $ thing");
Jalur
3
Mirip dengan ini,$id = constant(sprintf('%s::%s', ThingIDs::class, $thing));
David Baucum
4
@DavidBaucum mengapa Anda ingin memperumit hal ini? Permintaannya cukup sederhana dan tidak melibatkan masukan dari luar yang dapat dimanipulasi oleh pengguna. Selain itu, Anda memanggil fungsi lain karena, saya kira, Anda tidak suka string digabungkan dengan pembatas?
ReSpawN
5
Bergantung pada kasus penggunaan Anda, solusi saya tidak terlalu rumit. Khususnya jika Anda menggunakan pemuatan otomatis PSR-4, maka FQDN dapat dieja di mana-mana akan sangat buruk. Dengan menggunakan usedi bagian atas file dan kemudian menggunakan ::classmetode ajaib untuk mendapatkan FQDN meningkatkan keterbacaan.
David Baucum
27

Gunakan Refleksi

$r = new ReflectionClass('ThingIDs');
$id = $r->getConstant($thing);
Phil
sumber
3
Refleksi benar-benar memberikan banyak wawasan tentang kelas, metode, dan lainnya dan tampaknya banyak orang takut mengambil langkah itu untuk memahaminya. Jawaban yang bagus.
Mike Mackintosh
2
@mikemackintosh Saya telah mengambil langkah-langkah untuk memahaminya, tetapi belum melihat banyak dalam hal dampak kinerja vs jawaban yang diterima. ITU adalah sesuatu yang ingin saya ketahui. Instansiasi kelas baru sepertinya akan memiliki kinerja yang lebih baik daripada sekadar memanggil konstan secara statis. Apa pendapat Anda tentang itu?
dudewad
13

Jika Anda menggunakan namespace, Anda harus menyertakan namespace dengan kelas.

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

Fungsi pembantu

Anda dapat menggunakan fungsi seperti ini:

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

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

Dibutuhkan dua argumen:

  • Nama kelas atau contoh objek
  • Nama konstanta kelas

Jika sebuah instance objek dilewatkan, nama kelasnya akan disimpulkan. Jika Anda menggunakan PHP 7, Anda dapat menggunakan ::classuntuk mengirimkan nama kelas yang sesuai tanpa harus memikirkan ruang nama.

Contoh

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

Jika Anda memiliki referensi ke kelas itu sendiri, maka Anda dapat melakukan hal berikut:

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

Masalah saya mirip dengan subjek ini. Jika Anda memiliki objek, tetapi bukan nama kelasnya, Anda dapat menggunakan:

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

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