define () กับ const


659

ใน PHP คุณใช้งานเมื่อใด

define('FOO', 1);

และเมื่อไหร่ที่คุณจะใช้

const FOO = 1;

?

อะไรคือความแตกต่างที่สำคัญระหว่างสองสิ่งนี้?


4
เกี่ยวกับผลการดำเนินงาน (เสียเวลากับไมโครเพิ่มประสิทธิภาพเป็นฉัน) ดูคำตอบนี้ : เป็นครั้งที่สองได้เร็วกว่าconst defineเกี่ยวกับเวลาในการโหลดหน้าเว็บและการใช้หน่วยความจำ: ดูคำถามนี้และบทความนี้ ... ดูเพิ่มเติมบางอย่างเกี่ยวกับแคช opcode ที่นี่
Peter Krauss

2
อย่ามองเฉพาะคำตอบที่ได้รับการยอมรับในปัจจุบัน แต่โปรดดูที่stackoverflow.com/a/3193704/1412157ตามที่ควรได้รับคำตอบที่ได้รับ
LucaM

1
เพิ่งเห็นการแจ้งเตือนสำหรับความคิดเห็นของคุณ ฉันได้อัพเดตคำตอบที่ยอมรับแล้ว
danjarvis

คำตอบ:


1039

ในฐานะของ PHP 5.3 มีสองวิธีในการกำหนดค่าคงที่ : อาจใช้constคำหลักหรือใช้define()ฟังก์ชั่น:

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

ความแตกต่างพื้นฐานระหว่างทั้งสองวิธีคือการconstกำหนดค่าคงที่ในเวลารวบรวมในขณะที่defineกำหนดไว้ในเวลาทำงาน สิ่งนี้ทำให้เกิดconstข้อเสียส่วนใหญ่ ข้อเสียบางประการconstคือ:

  • constไม่สามารถใช้เพื่อกำหนดค่าคงที่แบบมีเงื่อนไข เพื่อกำหนดค่าคงที่ส่วนกลางนั้นจะต้องมีการใช้ในขอบเขตด้านนอก:

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

    ทำไมคุณถึงต้องการทำเช่นนั้น? แอปพลิเคชันทั่วไปอย่างหนึ่งคือการตรวจสอบว่ามีการกำหนดค่าคงที่แล้ว:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • constยอมรับเกลาคงที่ (จำนวนสตริงหรือคงที่อื่น ๆ เช่นtrue, false, null, __FILE__) ในขณะที่define()ใช้เวลาการแสดงออกใด ๆ เนื่องจาก PHP 5.6 นิพจน์คงที่ได้รับอนุญาตในconstเช่นกัน:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
    
  • constใช้ชื่อค่าคงที่ธรรมดาในขณะที่define()ยอมรับการแสดงออกใด ๆ เป็นชื่อ สิ่งนี้อนุญาตให้ทำสิ่งนี้:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • consts จะdefine()คำนึงถึงขนาดตัวพิมพ์เสมอในขณะที่อนุญาตให้คุณกำหนดค่าคงที่ที่ไม่คำนึงถึงขนาดตัวพิมพ์โดยการส่งผ่านtrueเป็นอาร์กิวเมนต์ที่สาม (หมายเหตุ: การกำหนดค่าคงที่ที่ไม่ต้องคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ถูกคัดค้านเมื่อ PHP 7.3.0)

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

นั่นคือสิ่งที่ไม่ดี ตอนนี้เรามาดูเหตุผลว่าทำไมฉันจึงใช้ส่วนตัวเป็นการส่วนตัวconstเว้นแต่จะมีเหตุการณ์ใดเหตุการณ์หนึ่งข้างต้นเกิดขึ้น:

  • constเพียงแค่อ่านดีกว่า มันเป็นโครงสร้างภาษาแทนฟังก์ชั่นและยังสอดคล้องกับวิธีที่คุณกำหนดค่าคงที่ในคลาส
  • constเป็นโครงสร้างภาษาสามารถวิเคราะห์แบบคงที่โดยใช้เครื่องมืออัตโนมัติ
  • constกำหนดค่าคงที่ในเนมสเปซปัจจุบันในขณะdefine()ที่ต้องผ่านชื่อเนมสเปซแบบเต็ม:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • เนื่องจากconstค่าคงที่PHP 5.6 ยังสามารถเป็นอาร์เรย์ในขณะที่define()ยังไม่รองรับอาร์เรย์ อย่างไรก็ตามอาร์เรย์จะรองรับทั้งสองกรณีใน 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
    

สุดท้ายโปรดทราบว่าconstสามารถใช้ภายในคลาสหรือส่วนต่อประสานเพื่อกำหนดค่าคงที่ของคลาสหรือค่าคงที่ส่วนต่อประสาน defineไม่สามารถใช้เพื่อจุดประสงค์นี้:

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

สรุป

หากคุณไม่ต้องการคำจำกัดความตามเงื่อนไขหรือนิพจน์ใด ๆ ให้ใช้consts แทนdefine()s - เพื่อความสะดวกในการอ่าน!


1
อย่างที่ฉันทราบด้วย PHP 5.6 คุณจะได้รับความเป็นไปได้ที่จะใช้นิพจน์สเกลาร์อย่างง่ายแม้กับโครงสร้างconstภาษา - ดูwiki.php.net/rfc/const_scalar_exprs
mabe.berlin

6
ข้อดีอีกอย่างของการใช้constคือการไม่มีเครื่องหมายคำพูดหมายความว่ามันถูกจัดรูปแบบเหมือนกับที่ใช้ใน IDE ของคุณ
rybo111

3
นี่ควรเป็นสิ่งที่อยู่ในเอกสาร PHP มันเป็นคำอธิบายที่ดีที่สุดที่ฉันเคยเห็นโดยเฉพาะในส่วนที่คนส่วนใหญ่ลืม (คอมไพล์กับรันไทม์)
James

4
define('a', $_GET['param']);, const b = a;การทำงานอย่างสมบูรณ์และได้รับความคุ้มค่าในขณะที่const c = $_GET['param'];ไม่ถูกต้อง คือconstรวบรวมเวลาจริงๆ? ฉันแทบจะไม่คิดอย่างนั้น ... (ทดสอบบน PHP 7.0.7)
mcserep

1
wiki.php.net/rfc/case_insensitive_constant_deprecation " ใน PHP 8.0: ลบความเป็นไปได้ของการประกาศค่าคงที่ case-insensitive. " สำหรับคนอื่น venturing ที่นี่ในอนาคตเกี่ยวกับกรณีความไว
Scuzzy

196

จนถึง PHP 5.3 constไม่สามารถใช้งานได้ในขอบเขตส่วนกลาง คุณสามารถใช้สิ่งนี้จากภายในชั้นเรียนเท่านั้น ควรใช้เมื่อคุณต้องการตั้งค่าตัวเลือกคงที่หรือการตั้งค่าที่เกี่ยวข้องกับคลาสนั้น หรือบางทีคุณต้องการสร้าง enum บางชนิด

defineสามารถใช้เพื่อจุดประสงค์เดียวกัน แต่สามารถใช้ได้ในขอบเขตส่วนกลางเท่านั้น ควรใช้สำหรับการตั้งค่าทั่วไปที่มีผลกับแอปพลิเคชันทั้งหมดเท่านั้น

ตัวอย่างของconstการใช้งานที่ดีคือกำจัดตัวเลขเวทย์มนตร์ ลองดูที่ค่าคงที่ของ PDO เมื่อคุณต้องการระบุประเภทการดึงข้อมูลคุณจะต้องพิมพ์PDO::FETCH_ASSOCเช่น หาก consts ไม่ได้ใช้คุณจะจบลงด้วยการพิมพ์สิ่งที่ต้องการ35(หรือสิ่งที่FETCH_ASSOCถูกกำหนดให้เป็น) สิ่งนี้ไม่สมเหตุสมผลสำหรับผู้อ่าน

ตัวอย่างของdefineการใช้งานที่ดีอาจเป็นการระบุรูทพา ธ ของแอปพลิเคชันของคุณหรือหมายเลขเวอร์ชันของไลบรารี


12
มันอาจจะคุ้มค่าที่จะกล่าวถึงการใช้งานconstกับ namespaces
salathe

31
ควรสังเกตว่า PHP5.3 สามารถใช้ const ในขอบเขตทั่วโลกได้อย่างมาก
Gordon

5.2 ก็ได้เช่นกัน ความสวยงามของ consts vs. การกำหนดคือคุณต้องขึ้นต้นด้วยชื่อคลาส การใช้มันจะทำให้โค้ดอ่านง่ายขึ้นและสวยขึ้น และนั่นคือโบนัสสำหรับฉัน
lucifurious

1
@ryeguy แต่จะเป็นอย่างไรหลังจาก PHP 5.3 ซึ่ง const สามารถใช้ทั่วโลกเช่นเดียวกับ define?
andho

1
@andho, เขียนอีกอันสำหรับการเต้น PHP ในหนึ่งก้าวไปข้างหน้า, ถอยหลังหนึ่งก้าว, การเต้นรำของ "การปรับปรุง" เขา. :)
ศ. Falken ผิดสัญญา

37

ฉันรู้ว่าคำตอบนี้ได้ตอบไปแล้ว แต่ไม่มีคำตอบใด ๆ ในปัจจุบันที่กล่าวถึงการกำหนดชื่อและวิธีการที่มีผลต่อค่าคงที่และการกำหนด

ในฐานะของ PHP 5.3, const และการกำหนดจะคล้ายกันในส่วนใหญ่ อย่างไรก็ตามยังมีความแตกต่างที่สำคัญบางประการ:

  • ไม่สามารถกำหนด Const ได้จากนิพจน์ const FOO = 4 * 3;ไม่ทำงาน แต่ทำงานdefine('CONST', 4 * 3);ได้
  • ชื่อที่ส่งผ่านdefineต้องมีเนมสเปซที่จะกำหนดภายในเนมสเปซนั้น

รหัสด้านล่างควรแสดงถึงความแตกต่าง

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

namespace {
    var_dump(get_defined_constants(true));
}

['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3]เนื้อหาของผู้ใช้ย่อยอาร์เรย์จะเป็น

=== UPDATE ===

ที่จะเกิดขึ้น PHP 5.6 constจะช่วยให้มีความยืดหยุ่นมากขึ้นอีกนิดด้วย ตอนนี้คุณจะสามารถกำหนด consts ในรูปของนิพจน์โดยที่นิพจน์เหล่านั้นประกอบด้วย const อื่นหรือตัวอักษร ซึ่งหมายความว่าข้อมูลต่อไปนี้ควรมีผลตั้งแต่ 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;

คุณยังคงไม่สามารถกำหนด const ในรูปของตัวแปรหรือฟังก์ชันส่งคืนได้ดังนั้น

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

จะยังคงออก


8
ฉันไม่สามารถต้านทานการถาม: คุณมีคำจำกัดความFORTY_TWOเป็น 54 หรือไม่?
Punchlinern

9
"หกถึงเก้าสิบสี่" ฉันมักจะพูดว่ามีบางสิ่งผิดปกติกับจักรวาล "ลองดูผลงานของดักลาสอดัมส์ถ้าคุณต้องการคำอธิบายแบบเต็ม
GordonM

2
โอ้ ฉันรู้ว่า 42 คือชีวิตคำตอบจักรวาลและทุกสิ่ง แต่ฉันคิดถึงหกโดยเก้าส่วน ขอบคุณสำหรับคำอธิบาย!
Punchlinern


20

define ฉันใช้ค่าคงที่ทั่วโลก

const ฉันใช้ค่าคงที่ของคลาส

คุณไม่สามารถdefineเข้าสู่ขอบเขตการเรียนได้และconstสามารถทำได้ คุณไม่สามารถใช้constขอบเขตนอกชั้นเรียนได้

นอกจากนี้เมื่อconstมันกลายเป็นสมาชิกของคลาสและด้วยdefineจะถูกส่งไปยังขอบเขตทั่วโลก


8
ตามที่ระบุไว้ในคำตอบอื่น ๆ const สามารถใช้นอกชั้นเรียนใน PHP 5.3+
MrWhite

เฉพาะคำหลัก const เท่านั้นที่สามารถใช้เพื่อสร้างค่าคงที่เนมสเปซไม่เพียง แต่คลาสเท่านั้น
Alireza Rahmani Khalili

16

คำตอบของ NikiC นั้นดีที่สุด แต่ให้ฉันเพิ่มข้อแม้ที่ไม่ชัดเจนเมื่อใช้ namespaces เพื่อที่คุณจะได้ไม่ติดกับพฤติกรรมที่ไม่คาดคิด สิ่งที่ต้องจำคือการกำหนดให้อยู่ในเนมสเปซส่วนกลางเสมอเว้นแต่คุณจะเพิ่มเนมสเปซเป็นส่วนหนึ่งของตัวระบุกำหนดอย่างชัดเจน สิ่งที่ไม่ชัดเจนเกี่ยวกับสิ่งนั้นคือตัวระบุเนมที่มีค่ามากกว่าตัวระบุทั่วโลก ดังนั้น:

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

ผลิต:

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

สิ่งที่ฉันทำให้ความคิด const ทั้งหมดสับสนโดยไม่จำเป็นเนื่องจากความคิดของ const ในหลายภาษาอื่น ๆ คือว่ามันจะเหมือนกันทุกที่ที่คุณอยู่ในรหัสของคุณและ PHP ไม่รับประกันจริง ๆ ว่า


1
ใช่ แต่BARและ\foo\BARเป็นเพียงการไม่ได้ค่าคงที่เดียวกัน ฉันเห็นมันจริงๆสับสน แต่ถ้าคุณยังพิจารณาสิ่งที่ต้องการตรรกะ namespacing เป็นที่สอดคล้องกันด้วยวิธีนี้และว่าไม่ว่าจะconstมิได้define()เป็นเช่น C มาโคร ( #define) แล้ว PHP สามารถมีข้ออ้างบาง
Sz.

1
ความคิด const เป็นว่าวิธีที่มันควรประพฤติ - คุณอยู่ใน namespace เป็นคนแรก! คุณต้องการโดยไม่มีตัวระบุเนมสเปซจากนั้นสร้างนอกเนมสเปซซึ่งจะทำให้มันสอดคล้องกับ const ที่ถูกกำหนดในคลาสแม้ว่ามันจะใช้ไวยากรณ์ที่แตกต่างกัน ใช่คำจำกัดความก็มีความสอดคล้องเช่นกันในวิธีที่ต่างออกไป
เจอราร์ดโอนีล

12

คำตอบส่วนใหญ่ผิดหรือบอกเพียงครึ่งเดียวเท่านั้น

  1. คุณสามารถกำหนดขอบเขตค่าคงที่ของคุณโดยใช้เนมสเปซ
  2. คุณสามารถใช้คีย์เวิร์ด "const" นอกนิยามคลาสได้ อย่างไรก็ตามเช่นเดียวกับในคลาสค่าที่กำหนดโดยใช้คีย์เวิร์ด "const" ต้องเป็นนิพจน์คงที่

ตัวอย่างเช่น:

const AWESOME = 'Bob'; // Valid

ตัวอย่างที่ไม่ดี:

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

ในการสร้างค่าคงที่ตัวแปรให้ใช้ define () ดังนี้:

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

1
PHP> = 5.6 มีการเปลี่ยนแปลงบางอย่างใน Zend Engine Compiler และ const จะได้รับการจัดการในลักษณะอื่นทันที
Ankit Vishwakarma

6

ใช่ const ถูกกำหนดในเวลารวบรวมและเป็นรัฐนิกิกไม่สามารถกำหนดนิพจน์ได้ดังที่ define () สามารถทำได้ แต่ยังไม่สามารถประกาศ const ได้ตามเงื่อนไข (ด้วยเหตุผลเดียวกัน) กล่าวคือ คุณไม่สามารถทำสิ่งนี้:

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

ในขณะที่คุณสามารถกำหนด () ดังนั้นมันไม่ได้ลงไปที่การตั้งค่าส่วนตัวมีวิธีที่ถูกต้องและผิดที่จะใช้ทั้งสอง

นอกเหนือจาก ... ฉันต้องการเห็นกลุ่มคลาสบางกลุ่มที่สามารถกำหนดนิพจน์ได้ประเภท define () ที่สามารถแยกออกเป็นคลาสได้หรือไม่


5

เพื่อเพิ่มคำตอบของ NikiC constสามารถใช้ภายในชั้นเรียนในลักษณะดังต่อไปนี้:

class Foo {
    const BAR = 1;

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

define()คุณไม่สามารถทำเช่นนี้กับ


4

ไม่มีใครพูดอะไรเกี่ยวกับ php-doc แต่สำหรับฉันนั่นก็เป็นข้อโต้แย้งที่สำคัญมากสำหรับการตั้งค่าของconst:

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

0

ด้วยการกำหนดค่าคงที่คำหลักคุณจะได้รับสิ่งอำนวยความสะดวกของตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ แต่ด้วยคำหลัก const ที่คุณไม่ได้ทำ

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.