define () vs const

658

Di PHP, kapan Anda menggunakannya

define('FOO', 1);

dan kapan Anda menggunakannya

const FOO = 1;

?

Apa perbedaan utama antara keduanya?

danjarvis
sumber
4
Tentang kinerja (buang-buang waktu dengan optimasi mikro seperti saya), lihat jawaban ini : constdua kali lebih cepat daripada define. Tentang waktu buka halaman dan penggunaan memori: lihat pertanyaan ini dan artikel ini ... Lihat juga sesuatu tentang cache opcode di sini .
Peter Krauss
2
Jangan hanya melihat jawaban yang diterima saat ini, tetapi silakan lihat ke stackoverflow.com/a/3193704/1412157 karena seharusnya jawaban yang diterima
LucaM
1
Baru saja melihat pemberitahuan untuk komentar Anda. Saya telah memperbarui jawaban yang diterima.
danjarvis

Jawaban:

1039

Pada PHP 5.3 ada dua cara untuk mendefinisikan konstanta : Entah menggunakan constkata kunci atau menggunakan define()fungsi:

const FOO = 'BAR';
define('FOO', 'BAR');

Perbedaan mendasar antara kedua cara tersebut adalah bahwa constmendefinisikan konstanta pada waktu kompilasi, sedangkan definemendefinisikannya pada saat run time. Ini menyebabkan sebagian besar constkerugian. Beberapa kelemahan constadalah:

  • consttidak dapat digunakan untuk mendefinisikan konstanta secara kondisional. Untuk mendefinisikan konstanta global, ia harus digunakan dalam lingkup terluar:

    if (...) {
        const FOO = 'BAR';    // Invalid
    }
    // but
    if (...) {
        define('FOO', 'BAR'); // Valid
    }

    Mengapa Anda tetap ingin melakukan itu? Satu aplikasi umum adalah untuk memeriksa apakah konstanta sudah ditentukan:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
  • constmenerima skalar statis (nomor, string atau konstan lain seperti true, false, null, __FILE__), sedangkan define()mengambil ekspresi apapun. Karena PHP 5.6 ekspresi konstan juga diperbolehkan const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
  • constmengambil nama konstan polos, sedangkan define()menerima ekspresi apa pun sebagai nama. Ini memungkinkan untuk melakukan hal-hal seperti ini:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
  • consts selalu peka huruf besar kecil, sedangkan define()memungkinkan Anda untuk mendefinisikan konstanta tidak peka huruf besar kecil dengan melewatkan truesebagai argumen ketiga (Catatan: mendefinisikan konstanta peka-huruf tidak berlaku lagi pada PHP 7.3.0.):

    define('FOO', 'BAR', true);
    echo FOO; // BAR
    echo foo; // BAR

Jadi, itulah sisi buruknya. Sekarang mari kita lihat alasan mengapa saya selalu menggunakan constkecuali jika salah satu dari situasi di atas terjadi:

  • consthanya membaca lebih baik. Ini adalah konstruksi bahasa alih-alih fungsi dan juga konsisten dengan cara Anda mendefinisikan konstanta di kelas.
  • const, sebagai konstruksi bahasa, dapat dianalisis secara statis dengan perkakas otomatis.
  • constmendefinisikan konstanta di namespace saat ini, sementara define()harus melewati nama namespace lengkap:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
  • Karena constkonstanta PHP 5.6 juga bisa berupa array, sementara define()itu belum mendukung array. Namun, array akan didukung untuk kedua kasus di PHP 7.

    const FOO = [1, 2, 3];    // Valid in PHP 5.6
    define('FOO', [1, 2, 3]); // Invalid in PHP 5.6 and valid in PHP 7.0

Akhirnya, perhatikan bahwa constjuga dapat digunakan dalam kelas atau antarmuka untuk menentukan konstanta kelas atau antarmuka konstan. definetidak dapat digunakan untuk tujuan ini:

class Foo {
    const BAR = 2; // Valid
}
// But
class Baz {
    define('QUX', 2); // Invalid
}

Ringkasan

Kecuali jika Anda memerlukan jenis definisi kondisional atau ekspresi, gunakan consts alih-alih define()s - hanya demi keterbacaan!

NikiC
sumber
1
Seperti yang saya tahu dengan PHP 5.6 Anda akan mendapatkan kemungkinan untuk menggunakan ekspresi skalar sederhana bahkan dengan constkonstruksi bahasa - lihat wiki.php.net/rfc/const_scalar_exprs
mabe.berlin
6
Manfaat lain untuk menggunakan constadalah kurangnya tanda kutip, artinya diformat sama dengan yang digunakan dalam IDE Anda.
rybo111
3
Ini harus menjadi apa yang ada dalam dokumen PHP. Ini penjelasan terbaik yang pernah saya lihat, terutama bagian yang kebanyakan orang lupa (kompilasi vs runtime).
James
4
define('a', $_GET['param']);, const b = a;bekerja dengan sempurna dan mendapatkan nilai saat const c = $_GET['param'];tidak valid Apakah constwaktu kompilasi benar-benar? Saya kira tidak begitu ... (diuji pada PHP 7.0.7)
mcserep
1
wiki.php.net/rfc/case_insensitive_constant_deprecation " Dalam PHP 8.0: Hapus kemungkinan mendeklarasikan konstanta case-sensitive. " untuk orang lain bertualang di sini di masa depan dalam hal sensitivitas kasus
Scuzzy
196

Hingga PHP 5.3, consttidak bisa digunakan dalam lingkup global. Anda hanya bisa menggunakan ini dari dalam kelas. Ini harus digunakan ketika Anda ingin mengatur semacam opsi atau pengaturan konstan yang berkaitan dengan kelas itu. Atau mungkin Anda ingin membuat semacam enum.

definedapat digunakan untuk tujuan yang sama, tetapi hanya dapat digunakan dalam lingkup global. Seharusnya hanya digunakan untuk pengaturan global yang mempengaruhi seluruh aplikasi.

Contoh constpenggunaan yang baik adalah untuk menghilangkan angka ajaib. Lihatlah konstanta PDO . Ketika Anda perlu menentukan jenis pengambilan, Anda akan mengetik PDO::FETCH_ASSOC, misalnya. Jika const tidak digunakan, Anda akan mengetik sesuatu seperti 35(atau apa pun FETCH_ASSOCyang didefinisikan sebagai). Ini tidak masuk akal bagi pembaca.

Contoh definepenggunaan yang baik mungkin menentukan jalur akar aplikasi Anda atau nomor versi pustaka.

ryeguy
sumber
12
Mungkin layak menyebutkan penggunaan constdengan ruang nama.
salathe
31
Juga harus dicatat bahwa PHP5.3 dapat menggunakan const dalam lingkup global.
Gordon
5.2 juga bisa. Keindahan consts vs mendefinisikan adalah bahwa Anda harus mengawali mereka dengan nama kelas. Menggunakannya membuat kode lebih mudah dibaca dan lebih cantik. Dan itu bonus bagi saya.
Luar biasa
1
@ryeguy tetapi bagaimana dengan setelah PHP 5.3 dimana const dapat digunakan secara global seperti define?
andho
1
@ andho, buat yang lain ke tarian PHP satu langkah maju, satu langkah mundur, tarian "perbaikan". Dia. :)
Kontrak Prof. Falken dilanggar
37

Saya tahu ini sudah dijawab, tetapi tidak ada jawaban saat ini yang menyebutkan namespacing dan bagaimana pengaruhnya terhadap konstanta dan definisi.

Pada PHP 5.3, konstanta dan definisi hampir sama dalam banyak hal. Namun, masih ada beberapa perbedaan penting:

  • Konstanta tidak dapat didefinisikan dari ekspresi. const FOO = 4 * 3;tidak bekerja, tetapi define('CONST', 4 * 3);tidak.
  • Nama yang diteruskan defineharus menyertakan namespace yang akan didefinisikan dalam namespace itu.

Kode di bawah ini harus menggambarkan perbedaan.

namespace foo 
{
    const BAR = 1;
    define('BAZ', 2);
    define(__NAMESPACE__ . '\\BAZ', 3);
}

namespace {
    var_dump(get_defined_constants(true));
}

Konten dari sub-array pengguna akan ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== UPDATE ===

PHP 5.6 mendatang akan memungkinkan fleksibilitas yang lebih tinggi dengan const. Anda sekarang dapat mendefinisikan const dalam hal ekspresi, asalkan ekspresi tersebut terdiri dari const lain atau literal. Ini berarti yang berikut ini harus valid pada 5.6:

const FOOBAR = 'foo ' . 'bar';
const FORTY_TWO = 6 * 9; // For future editors: THIS IS DELIBERATE! Read the answer comments below for more details
const ULTIMATE_ANSWER = 'The ultimate answer to life, the universe and everything is ' . FORTY_TWO;

Anda masih tidak akan dapat mendefinisikan const dalam hal variabel atau fungsi kembali, jadi

const RND = mt_rand();
const CONSTVAR = $var;

masih akan keluar.

GordonM
sumber
8
Saya tidak bisa menahan diri untuk bertanya: Apakah Anda secara sadar mendefinisikan FORTY_TWOsebagai 54?
Punchlinern
9
"Enam kali sembilan? Empat puluh dua? Saya selalu mengatakan ada sesuatu yang secara fundamental salah dengan alam semesta" Periksa karya-karya Douglas Adams jika Anda membutuhkan penjelasan lengkap.
GordonM
2
Oh Saya sadar bahwa 42 adalah jawaban kehidupan, alam semesta, dan segalanya kecuali sembilan bagian yang saya lewatkan. Terima kasih untuk penjelasannya!
Punchlinern
22

Saya percaya bahwa pada PHP 5.3, Anda dapat menggunakan di constluar kelas, seperti yang ditunjukkan di sini dalam contoh kedua:

http://www.php.net/manual/en/language.constants.syntax.php

<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';

echo CONSTANT;
?>
menggerutu
sumber
20

define Saya gunakan untuk konstanta global.

const Saya gunakan untuk konstanta kelas.

Anda tidak bisa definemasuk ke dalam ruang lingkup kelas, dan dengan constAnda bisa. Tidak perlu dikatakan, Anda tidak dapat menggunakan construang lingkup kelas luar.

Juga, dengan const, itu benar-benar menjadi anggota kelas, dan dengan define, itu akan didorong ke ruang lingkup global.

Jacob Relkin
sumber
8
Seperti disebutkan dalam jawaban lain, const dapat digunakan di luar kelas di PHP 5.3+
MrWhite
Hanya kata kunci const yang dapat digunakan untuk membuat konstanta dengan spasi nama, tidak hanya kelas
Alireza Rahmani Khalili
16

Jawaban NikiC adalah yang terbaik, tetapi izinkan saya menambahkan peringatan yang tidak jelas ketika menggunakan ruang nama sehingga Anda tidak terjebak dengan perilaku yang tidak terduga. Yang perlu diingat adalah bahwa definisi selalu di namespace global kecuali jika Anda secara eksplisit menambahkan namespace sebagai bagian dari pengidentifikasi define. Apa yang tidak jelas tentang itu adalah bahwa pengidentifikasi namespaced mengalahkan pengidentifikasi global. Jadi:

<?php
namespace foo
{
  // Note: when referenced in this file or namespace, the const masks the defined version
  // this may not be what you want/expect
  const BAR = 'cheers';
  define('BAR', 'wonka');

  printf("What kind of bar is a %s bar?\n", BAR);

  // To get to the define in the global namespace you need to explicitely reference it
  printf("What kind of bar is a %s bar?\n", \BAR);
}

namespace foo2
{
  // But now in another namespace (like in the default) the same syntax calls up the 
  // the defined version!
  printf("Willy %s\n", BAR);
  printf("three %s\n", \foo\BAR);  
}
?>

menghasilkan:

What kind of bar is a cheers bar? 
What kind of bar is a wonka bar?
willy wonka 
three cheers

Yang bagi saya membuat seluruh gagasan const tidak perlu membingungkan karena ide tentang const dalam lusinan bahasa lain adalah bahwa itu selalu sama di mana pun Anda berada dalam kode Anda, dan PHP tidak benar-benar menjamin itu.

slartibartfast
sumber
1
Yeah, tapi BARdan \foo\BARhanya tidak konstanta yang sama. Saya setuju itu benar-benar membingungkan, tetapi jika Anda juga menganggap hal-hal seperti logika namespacing konsisten dengan cara ini, dan tidak constjuga define()tidak seperti makro C ( #define), maka PHP dapat memiliki beberapa alasan.
Sz.
1
Gagasan const persis seperti seharusnya berperilaku - Anda berada di namespace! Anda menginginkannya tanpa pengidentifikasi namespace, kemudian membuatnya di luar namespace .. Ini juga membuatnya konsisten dengan konst yang didefinisikan dalam kelas, bahkan jika menggunakan sintaks yang berbeda. Ya, define juga konsisten, dengan cara yang berbeda.
Gerard ONeill
12

Sebagian besar jawaban ini salah atau hanya menceritakan setengah dari cerita.

  1. Anda dapat menetapkan konstanta dengan menggunakan ruang nama.
  2. Anda dapat menggunakan kata kunci "const" di luar definisi kelas. Namun, seperti di kelas, nilai yang diberikan menggunakan kata kunci "const" harus berupa ekspresi konstan.

Sebagai contoh:

const AWESOME = 'Bob'; // Valid

Contoh buruk:

const AWESOME = whatIsMyName(); // Invalid (Function call)
const WEAKNESS = 4+5+6; // Invalid (Arithmetic) 
const FOO = BAR . OF . SOAP; // Invalid (Concatenation)

Untuk membuat konstanta variabel, gunakan define () seperti:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid
KerenBobX64
sumber
1
PHP> = 5.6 beberapa perubahan telah dibuat di Zend Engine Compiler dan const sedang diperlakukan dengan cara lain sekarang.
Ankit Vishwakarma
6

Ya, const didefinisikan pada waktu kompilasi dan karena status nikic tidak dapat diberikan ekspresi, seperti yang dapat didefinisikan () dapat. Tetapi juga const tidak dapat dinyatakan secara kondisional (untuk alasan yang sama). yaitu. Anda tidak dapat melakukan ini:

if (/* some condition */) {
  const WHIZZ = true;  // CANNOT DO THIS!
}

Sedangkan Anda bisa dengan define (). Jadi, itu tidak benar-benar turun ke preferensi pribadi, ada cara yang benar dan salah untuk menggunakan keduanya.

Sebagai tambahan ... Saya ingin melihat semacam konst kelas yang dapat diberi ekspresi, semacam define () yang dapat diisolasi ke kelas?

TuanWhite
sumber
5

Untuk menambahkan jawaban NikiC. constdapat digunakan di dalam kelas dengan cara berikut:

class Foo {
    const BAR = 1;

    public function myMethod() {
        return self::BAR;
    }
}

Anda tidak dapat melakukan ini dengan define().

Marcus Lind
sumber
4

Tidak ada yang mengatakan apa-apa tentang php-doc, tetapi bagi saya itu juga argumen yang sangat signifikan untuk preferensi const:

/**
 * My foo-bar const
 * @var string
 */
const FOO = 'BAR';
Николай Лубышев
sumber
0

Dengan menetapkan kata kunci konstan, Anda akan mendapatkan fasilitas case-insensitive tetapi dengan const kata kunci yang Anda tidak.

define("FOO", 1, true);
echo foo; //1
echo "<br/>";
echo FOO; //1
echo "<br/>";

class A {
  const FOO = 1;
}

echo A::FOO; //valid
echo "<br/>";

//but

class B {
  define FOO = 1; //syntax error, unexpected 'define'
}

echo B::FOO; //invalid
GaziAnis
sumber