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ì?
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ì?
Câu trả lời:
Kể từ phiên bản PHP 5.3, có hai cách để xác định các hằng số : Sử dụng const
từ 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à const
xá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 const
nhược điểm. Một số nhược điểm của const
:
const
khô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');
}
const
chấ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
const
lấ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);
}
const
s 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 true
là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 const
trừ khi một trong những tình huống trên xảy ra:
const
chỉ đơ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 const
hằ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 const
cũ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. define
khô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 const
s thay vì define()
s - đơn giản là vì mục đích dễ đọc!
const
cấu trúc ngôn ngữ - xem wiki.php.net/rfc/const_scalar_exprs
const
là 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.
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à const
thự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)
Cho đến khi PHP 5.3, const
khô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.
define
có 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ề const
cá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ề define
cá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.
const
với không gian tên.
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:
const FOO = 4 * 3;
không làm việc, nhưng define('CONST', 4 * 3);
không. define
phả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
FORTY_TWO
là 54 không?
Tôi tin rằng kể từ PHP 5.3, bạn có thể sử dụng const
bên ngoài các lớp, như được hiển thị ở đây trong ví dụ thứ hai:
http://www.php.net/manual/en/lingu.constants.syntax.php
<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';
echo CONSTANT;
?>
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ể define
vào phạm vi lớp học, và với const
bạn có thể. Không cần phải nói, bạn không thể sử dụng const
phạ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.
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 đó.
BAR
và \foo\BAR
chỉ 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à const
cũng không define()
giống như macro C ( #define
), thì PHP có thể có một số lý do.
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.
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
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?
Để thêm vào câu trả lời của NikiC. const
có 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()
.
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
const
nhanh hơn hai lần so vớidefine
. Về thời gian tải trang và sử dụng bộ nhớ: xem câu hỏi này và bài viết này ... Xem thêm một vài điều về bộ đệm opcode tại đây .