визначити () проти const


659

У PHP, коли ви використовуєте

define('FOO', 1);

і коли ви використовуєте

const FOO = 1;

?

Які основні відмінності між цими двома?


4
Про продуктивність (марна трата часу на мікрооптимізацію, як я) дивіться цю відповідь : у constдва рази швидше, ніж define. Про час завантаження сторінки та використання пам’яті: див. Це запитання та цю статтю ... Дивіться також щось про кеш опкоду тут .
Пітер Краус

2
Не дивіться лише на поточну прийняту відповідь, але, будь ласка, погляньте на stackoverflow.com/a/3193704/1412157, як це мало бути прийнятою відповіддю
ЛукаM

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. Це найкраще пояснення, яке я бачив, особливо частина, яку більшість людей забуває (компілювати проти виконання).
Джеймс

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: видаліть можливість оголошення констант, що не залежать від регістру. " для всіх, хто наважиться тут у майбутнє щодо чутливості до справ
Scuzzy

196

Поки PHP 5.3 constне можна було використовувати в глобальному масштабі. Ви можете використовувати це лише у класі. Це слід використовувати, коли ви хочете встановити якийсь постійний параметр або параметр, який відноситься до цього класу. А може, ви хочете створити якусь перерахунок.

defineможе використовуватися з тією ж метою, але вона може бути використана лише в глобальному масштабі. Його слід використовувати лише для глобальних налаштувань, які впливають на всю програму.

Приклад хорошого constвикористання - позбутися від магічних чисел. Погляньте на константи PDO . Коли вам потрібно вказати тип вибору, ви введете PDO::FETCH_ASSOC, наприклад. Якщо конкурси не використовувались, ви, в кінцевому підсумку, введете щось на зразок 35(або все FETCH_ASSOC, що визначено як). Це не має сенсу для читача.

Прикладом хорошого defineвикористання може бути вказівка ​​кореневого шляху вашої програми або номер версії бібліотеки.


12
Можливо, варто згадати про використання constпросторів імен.
салат

31
Слід також зазначити, що PHP5.3 може дуже використовувати const у глобальному масштабі.
Гордон

5.2 також. Краса consts vs. визначає, що ви повинні префіксувати їх назвою класу. Використання їх робить код читабельнішим і красивішим. І це бонус для мене.
дохідливий

1
@ryeguy, а як бути після PHP 5.3, де const можна використовувати в усьому світі так само, як визначити?
andho

1
@andho, крейдуй інший танець PHP "крок вперед", "крок назад", танець "вдосконалення". Він. :)
Контракт професора Фолкена порушено

37

Я знаю, що на це вже відповіли, але жодна з нинішніх відповідей не згадує проміжок часу і те, як це впливає на константи та визначає.

За станом на PHP 5.3, consts та визначає здебільшого подібні. Однак є деякі важливі відмінності:

  • Consts не можна визначити з виразу. 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].

=== ОНОВЛЕННЯ ===

Майбутній PHP 5.6 дозволить трохи більше гнучкості const. Тепер ви зможете визначити consts у виразах, за умови, що ці вирази складаються з інших consts або з літералів. Це означає, що наступне повинно діяти з 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;

Ви все одно не зможете визначити consts з точки зору змінних або функцій повернень, хоча, так

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 може бути використане для створення константи просторового простору імен, не тільки класів
Аліреза Рахмані Халілі

16

Відповідь NikiC найкраща, але дозвольте мені додати неочевидний застереження при використанні просторів імен, щоб вас не зачепило несподівана поведінка. Слід пам’ятати, що визначення завжди знаходяться у глобальному просторі імен, якщо ви явно не додаєте простір імен як частину ідентифікатора визначення. Що не очевидно в тому, що ідентифікатор простору імен перетворює глобальний ідентифікатор. Тому :

<?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просто не ті самі константи. Я погоджуюсь, що це дійсно заплутано, але якщо ви також вважаєте, що такі речі, як логіка простору імен, відповідають цій схемі, і що ні те, constні define()таке, як макрос C ( #define), PHP може мати виправдання.
Sz.

1
Поняття const саме так, як воно повинно поводитися - ви знаходитесь у просторі імен! Ви хочете, щоб не було ідентифікатора простору імен, а потім створити його поза простором імен. Це також робить його узгодженим з const, визначеним у класі, навіть якщо він використовує інший синтаксис. Так, визначення також відповідає, по-іншому.
Джерард ONeill

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)

Для створення змінних констант використовуйте def () так:

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 визначається під час компіляції, і як nikic станам не можна призначити вираз, як може визначити (). Але також const's не можна умовно оголосити (з тієї ж причини). тобто. Ви не можете цього зробити:

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

Тоді як ви можете з define (). Таким чином, це насправді не зводиться до особистих переваг, є правильний і неправильний спосіб використання обох.

Як осторонь ... Я хотів би бачити якийсь клас const, якому можна призначити вираз, свого роду 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.