định nghĩa () so với const


658

Trong PHP, khi nào bạn sử dụng

define('FOO', 1);

và khi nào bạn sử dụng

const FOO = 1;

?

Sự khác biệt chính giữa hai là gì?


4
Về hiệu suất (lãng phí thời gian với tối ưu hóa vi mô như tôi), hãy xem câu trả lời này : constnhanh hơn hai lần so với define. Về thời gian tải trang và sử dụng bộ nhớ: xem câu hỏi nàybài viết này ... Xem thêm một vài điều về bộ đệm opcode tại đây .
Peter Krauss

2
Đừng chỉ nhìn vào câu trả lời được chấp nhận hiện tại, nhưng vui lòng xem qua stackoverflow.com/a/3193704/1412157 vì nó phải là câu trả lời được chấp nhận
LucaM 21/07/2015

1
Chỉ cần nhìn thấy thông báo cho bình luận của bạn. Tôi đã cập nhật câu trả lời được chấp nhận.
danjarvis

Câu trả lời:


1037

Kể từ phiên bản PHP 5.3, có hai cách để xác định các hằng số : Sử dụng consttừ khóa hoặc sử dụng define()hàm:

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

Sự khác biệt cơ bản giữa hai cách đó là constxác định các hằng số tại thời gian biên dịch, trong khi defineđịnh nghĩa chúng tại thời gian chạy. Điều này gây ra hầu hết các constnhược điểm. Một số nhược điểm của const:

  • constkhông thể được sử dụng để xác định các hằng số có điều kiện. Để xác định hằng số toàn cầu, nó phải được sử dụng trong phạm vi ngoài cùng:

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

    Tại sao bạn vẫn muốn làm điều đó? Một ứng dụng phổ biến là kiểm tra xem hằng số đã được xác định chưa:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • constchấp nhận một vô hướng tĩnh (số, chuỗi hoặc thường xuyên khác như true, false, null, __FILE__), trong khi define()có bất kỳ biểu hiện. Do các biểu thức hằng của PHP 5.6 cũng được cho phép const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
    
  • constlấy một tên hằng đơn giản, trong khi define()chấp nhận bất kỳ biểu thức nào làm tên. Điều này cho phép làm những việc như thế này:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • consts luôn define()phân biệt chữ hoa chữ thường , trong khi cho phép bạn xác định các hằng số không phân biệt chữ hoa chữ thường bằng cách chuyển truelàm đối số thứ ba (Lưu ý: xác định các hằng số không phân biệt chữ hoa chữ thường không được dùng trong PHP 7.3.0.):

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

Vì vậy, đó là mặt xấu của mọi thứ. Bây giờ hãy xem lý do tại sao cá nhân tôi luôn sử dụng consttrừ khi một trong những tình huống trên xảy ra:

  • constchỉ đơn giản là đọc đẹp hơn. Đó là cấu trúc ngôn ngữ thay vì hàm và cũng phù hợp với cách bạn xác định các hằng trong các lớp.
  • const, là một cấu trúc ngôn ngữ, có thể được phân tích tĩnh bằng công cụ tự động.
  • constđịnh nghĩa một hằng số trong không gian tên hiện tại, trong khi define()phải thông qua tên không gian tên đầy đủ:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • Vì các consthằng số PHP 5.6 cũng có thể là các mảng, trong khi define()chưa hỗ trợ các mảng. Tuy nhiên, mảng sẽ được hỗ trợ cho cả hai trường hợp trong 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
    

Cuối cùng, lưu ý rằng constcũng có thể được sử dụng trong một lớp hoặc giao diện để xác định hằng số lớp hoặc hằng số giao diện. definekhông thể được sử dụng cho mục đích này:

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

Tóm lược

Trừ khi bạn cần bất kỳ loại định nghĩa có điều kiện hoặc biểu thức, sử dụng consts thay vì define()s - đơn giản là vì mục đích dễ đọc!


1
Như tôi biết với PHP 5.6, bạn sẽ có khả năng sử dụng các biểu thức vô hướng đơn giản ngay cả với constcấu trúc ngôn ngữ - xem wiki.php.net/rfc/const_scalar_exprs
mabe.berlin

6
Một lợi ích khác khi sử dụng constlà thiếu dấu ngoặc kép, có nghĩa là nó được định dạng giống như nơi nó được sử dụng trong IDE của bạn.
rybo111

3
Đây phải là những gì trong tài liệu PHP. Đó là lời giải thích tốt nhất mà tôi đã thấy, đặc biệt là phần mà hầu hết mọi người đều quên (biên dịch so với thời gian chạy).
James

4
define('a', $_GET['param']);, const b = a;hoạt động hoàn hảo và nhận được giá trị trong khi const c = $_GET['param'];không hợp lệ. Là constthực sự biên dịch thời gian? Tôi hầu như không nghĩ vậy ... (đã thử nghiệm trên PHP 7.0.7)
mcserep

1
wiki.php.net/rfc/case_insensitive_constant_deprecation " Trong PHP 8.0: Loại bỏ khả năng tuyên bố case-insensitive hằng. " đối với bất cứ ai khác mạo hiểm ở đây trong tương lai liên quan đến trường hợp nhạy cảm
Scuzzy

196

Cho đến khi PHP 5.3, constkhông thể được sử dụng trong phạm vi toàn cầu. Bạn chỉ có thể sử dụng điều này từ trong một lớp. Điều này nên được sử dụng khi bạn muốn đặt một số loại tùy chọn hoặc cài đặt liên quan đến lớp đó. Hoặc có thể bạn muốn tạo ra một số loại enum.

definecó thể được sử dụng cho cùng một mục đích, nhưng nó chỉ có thể được sử dụng trong phạm vi toàn cầu. Nó chỉ nên được sử dụng cho các cài đặt toàn cầu có ảnh hưởng đến toàn bộ ứng dụng.

Một ví dụ về constcách sử dụng tốt là loại bỏ các con số ma thuật. Hãy xem các hằng số của PDO . Khi bạn cần chỉ định loại tìm nạp, bạn sẽ nhập PDO::FETCH_ASSOC, ví dụ. Nếu consts không được sử dụng, cuối cùng bạn sẽ gõ một cái gì đó như 35(hoặc bất cứ điều gì FETCH_ASSOCđược định nghĩa là). Điều này không có ý nghĩa với người đọc.

Một ví dụ về definecách sử dụng tốt có thể chỉ định đường dẫn gốc của ứng dụng hoặc số phiên bản của thư viện.


12
Nó có thể đáng được đề cập đến việc sử dụng constvới không gian tên.
chào mừng

31
Cũng cần lưu ý rằng PHP5.3 có thể sử dụng rất nhiều const trong phạm vi toàn cầu.
Gordon

5.2 cũng có thể. Vẻ đẹp của consts so với định nghĩa là bạn phải đặt tiền tố cho chúng với tên lớp. Sử dụng chúng làm cho mã dễ đọc hơn và đẹp hơn. Và đó là một phần thưởng cho tôi.
sáng suốt

1
@ryeguy nhưng còn sau PHP 5.3, nơi const có thể được sử dụng trên toàn cầu giống như định nghĩa?
andho

1
@andho, phấn đấu khác với điệu nhảy PHP một bước tiến, lùi một bước, nhảy "cải tiến". Anh ta. :)
Hợp đồng của Giáo sư Falken vi phạm

37

Tôi biết điều này đã được trả lời, nhưng không có câu trả lời hiện tại nào đề cập đến không gian tên và cách nó ảnh hưởng đến hằng số và định nghĩa.

Kể từ PHP 5.3, consts và định nghĩa là tương tự nhau trong hầu hết các khía cạnh. Tuy nhiên, vẫn còn một số khác biệt quan trọng:

  • Các hằng số không thể được định nghĩa từ một biểu thức. const FOO = 4 * 3;không làm việc, nhưng define('CONST', 4 * 3);không.
  • Tên được chuyển đến definephải bao gồm không gian tên được xác định trong không gian tên đó.

Mã dưới đây sẽ minh họa sự khác biệt.

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

namespace {
    var_dump(get_defined_constants(true));
}

Nội dung của mảng con người dùng sẽ là ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== CẬP NHẬT ===

PHP 5.6 sắp tới sẽ cho phép linh hoạt hơn một chút với const. Bây giờ bạn sẽ có thể định nghĩa các hằng số theo biểu thức, với điều kiện là các biểu thức đó được tạo thành từ các hằng số khác hoặc bằng chữ. Điều này có nghĩa là những điều sau đây phải hợp lệ kể từ 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;

Mặc dù vậy, bạn vẫn không thể xác định các hằng số theo các biến hoặc trả về hàm, vì vậy

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

vẫn sẽ ra ngoài


8
Tôi không thể cưỡng lại việc hỏi: Bạn có định nghĩa FORTY_TWOlà 54 không?
Punchlinern

9
"Sáu giờ chín? Bốn mươi hai? Tôi luôn nói rằng có một cái gì đó sai về cơ bản với vũ trụ" Hãy xem các tác phẩm của Douglas Adams nếu bạn cần một lời giải thích đầy đủ.
GordonM

2
Oh. Tôi đã nhận ra rằng 42 là cuộc sống trả lời, vũ trụ và tất cả mọi thứ nhưng tôi đã bỏ lỡ Six by chín phần. Cảm ơn đã giải thích!
Punchlinern


20

define Tôi sử dụng cho hằng số toàn cầu.

const Tôi sử dụng cho hằng số lớp.

Bạn không thể definevào phạm vi lớp học, và với constbạn có thể. Không cần phải nói, bạn không thể sử dụng constphạm vi lớp học bên ngoài.

Ngoài ra, với const, nó thực sự trở thành một thành viên của lớp, và với define, nó sẽ được đẩy lên phạm vi toàn cầu.


8
Như đã lưu ý trong các câu trả lời khác, const có thể được sử dụng bên ngoài các lớp trong PHP 5.3+
MrWhite

Chỉ có thể sử dụng từ khóa const để tạo hằng số được đặt tên, không chỉ các lớp
Alireza Rahmani Khalili

16

Câu trả lời của NikiC là tốt nhất, nhưng hãy để tôi thêm một cảnh báo không rõ ràng khi sử dụng không gian tên để bạn không bị bắt gặp với hành vi bất ngờ. Điều cần nhớ là các định nghĩa luôn nằm trong không gian tên toàn cục trừ khi bạn thêm rõ ràng không gian tên như một phần của định danh xác định. Điều không rõ ràng về điều đó là định danh được đặt tên vượt qua định danh toàn cầu. Vì thế :

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

sản xuất:

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

Điều này đối với tôi làm cho toàn bộ khái niệm không thể nhầm lẫn vì ý tưởng về const trong hàng tá ngôn ngữ khác là nó luôn giống nhau ở bất cứ đâu trong mã của bạn và PHP không thực sự đảm bảo điều đó.


1
Yeah, nhưng BAR\foo\BARchỉ không các hằng số tương tự. Tôi đồng ý rằng nó thực sự khó hiểu, nhưng nếu bạn cũng coi những thứ như logic không gian tên là nhất quán theo cách này và constcũng không define()giống như macro C ( #define), thì PHP có thể có một số lý do.
Sz.

1
Khái niệm const chính xác là cách nó nên cư xử - bạn đang ở trong một không gian tên! Bạn muốn nó mà không có định danh không gian tên, sau đó tạo nó bên ngoài không gian tên .. Điều này cũng làm cho nó phù hợp với const được định nghĩa trong một lớp, ngay cả khi nó sử dụng cú pháp khác nhau. Vâng, định nghĩa là nhất quán quá, theo một cách khác.
Gerard ONeill

12

Hầu hết các câu trả lời là sai hoặc chỉ kể một nửa câu chuyện.

  1. Bạn có thể phạm vi hằng số của bạn bằng cách sử dụng không gian tên.
  2. Bạn có thể sử dụng từ khóa "const" bên ngoài các định nghĩa lớp. Tuy nhiên, giống như trong các lớp, các giá trị được gán bằng từ khóa "const" phải là biểu thức không đổi.

Ví dụ:

const AWESOME = 'Bob'; // Valid

Ví dụ xấu:

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

Để tạo các hằng số biến, hãy sử dụng định nghĩa () như vậy:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid

1
PHP> = 5.6 một số thay đổi đã được thực hiện trong Zend Engine Compiler và const hiện đang được xử lý theo cách khác.
Ankit Vishwakarma

6

Có, const được định nghĩa tại thời gian biên dịch và vì các trạng thái nikic không thể được chỉ định một biểu thức, như có thể của định nghĩa (). Nhưng cũng không thể khai báo điều kiện (vì lý do tương tự). I E. Bạn không thể làm điều này:

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

Trong khi đó bạn có thể với một định nghĩa (). Vì vậy, nó không thực sự đi theo sở thích cá nhân, có một cách đúng và sai để sử dụng cả hai.

Ở một bên ... Tôi muốn thấy một số loại const lớp có thể được gán một biểu thức, một loại định nghĩa () có thể được tách ra cho các lớp?


5

Để thêm vào câu trả lời của NikiC. constcó thể được sử dụng trong các lớp theo cách sau:

class Foo {
    const BAR = 1;

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

Bạn không thể làm điều này với define().


4

Không ai nói gì về php-doc, nhưng đối với tôi đó cũng là một đối số rất có ý nghĩa đối với sở thích của const:

/**
 * My foo-bar const
 * @var string
 */
const FOO = 'BAR';

0

Với hằng số từ khóa xác định, bạn sẽ có được các phương tiện không phân biệt chữ hoa chữ thường nhưng với từ khóa const thì không.

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.