визначити () проти 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.