define () против const

516

Довольно простой вопрос: в PHP, когда вы используете

define('FOO', 1);

и когда вы используете

const FOO = 1;

В чем основные отличия между этими двумя?

  • 3
    Что касается производительности (пустая трата времени с микрооптимизацией, как я), посмотрите этот ответ : const в два раза быстрее, чем define . О времени загрузки страницы и использовании памяти: см. Этот вопрос и эту статью ... Смотрите также кое-что о кеше кода операции здесь .
  • 1
    Не смотрите только на текущий принятый ответ, но посмотрите на stackoverflow.com/a/3193704/1412157, поскольку он должен был быть принятым ответом
Показать ещё 1 комментарий
Теги:
const
constants

9 ответов

875
Лучший ответ

В 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, invalid previously
    define('BIT_5', 1 << 5); // always valid
    
  • const принимает имя простой константы, тогда как define() принимает любое выражение как имя. Это позволяет делать такие вещи:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • const всегда чувствительны к регистру, тогда как define() позволяет определить нечувствительные к регистру константы, передав true в качестве третьего аргумента:

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

Итак, это была плохая сторона вещей. Теперь рассмотрим причину, по которой я лично всегда использую 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');
    
  • Так как константы PHP 5.6 const также могут быть массивами, а define() еще не поддерживает массивы. Однако массивы будут поддерживаться в обоих случаях в PHP 7.

    const FOO = [1, 2, 3];    // valid in PHP 5.6
    define('FOO', [1, 2, 3]); // invalid in PHP 5.6, valid in PHP 7.0
    
  • Поскольку const являются языковыми конструкциями и определены во время компиляции, они немного быстрее, чем define() s.

    Хорошо известно, что PHP define() медленны при использовании большого числа констант. Люди даже придумали такие вещи, как apc_load_constants() и hidef чтобы обойти это.

    const сделать определение констант примерно в два раза быстрее (на машинах разработки с XDebug включен еще больше). Время поиска с другой стороны не изменяется (поскольку оба константных типа используют одну и ту же таблицу поиска): Demo.

Наконец, обратите внимание, что const также может использоваться в классе или интерфейсе для определения константы класса или константы интерфейса. define не может использоваться для этой цели:

class Foo {
    const BAR = 2; // valid
}
// but
class Baz {
    define('QUX', 2); // invalid
}

Резюме

Если вам не нужен какой-либо условный или экспрессивный определение, используйте const вместо define() - просто для удобства чтения!

  • 1
    Как я знаю, в PHP 5.6 вы получите возможность использовать простые скалярные выражения даже с конструкцией языка const - см. Wiki.php.net/rfc/const_scalar_exprs
  • 4
    Еще одним преимуществом использования const является отсутствие кавычек, что означает, что он отформатирован так же, как и в вашей IDE.
Показать ещё 6 комментариев
185

Пока PHP 5.3, const не может использоваться в глобальной области. Вы можете использовать это только из класса. Это следует использовать, если вы хотите установить какой-либо константный параметр или параметр, относящийся к этому классу. Или, возможно, вы хотите создать какой-то перемычек.

define может использоваться с той же целью, но его можно использовать только в глобальной области. Его следует использовать только для глобальных настроек, которые влияют на все приложение.

Примером хорошего использования const является избавление от магических чисел. Взгляните на константы PDO. Когда вам нужно указать тип выборки, вы должны набрать PDO::FETCH_ASSOC, например. Если consts не были использованы, вы в конечном итоге набрали бы что-то вроде 35 (или другое FETCH_ASSOC определено как). Это не имеет смысла для читателя.

Примером хорошего использования define может быть, указав корневой путь вашего приложения или номер версии библиотеки.

  • 12
    Возможно, стоит упомянуть использование const с пространствами имен.
  • 31
    Следует также отметить, что PHP5.3 может очень широко использовать const в глобальной области видимости.
Показать ещё 3 комментария
34

Я знаю, что это уже ответили, но ни один из текущих ответов не упоминает об именах и о том, как он влияет на константы и определяет.

Как и в случае PHP 5.3, константы и определения аналогичны в большинстве случаев. Тем не менее, существуют некоторые важные отличия:

  • Константы не могут быть определены из выражения. 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 в терминах выражений, если эти выражения состоят из других констант или литералов. Это означает, что должно быть справедливо следующее: 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 RND = mt_rand();
const CONSTVAR = $var;

по-прежнему будет отсутствовать.

  • 7
    Я не мог удержаться от вопроса: вы сознательно определили FORTY_TWO как 54?
  • 7
    «Шесть на девять? Сорок два? Я всегда говорил, что во вселенной что-то в корне не так» Посмотрите работы Дугласа Адамса, если вам нужно полное объяснение.
Показать ещё 2 комментария
22

Я считаю, что с PHP 5.3 вы можете использовать const вне классов, как показано здесь во втором примере:

http://www.php.net/manual/en/language.constants.syntax.php

<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';

echo CONSTANT;
?>
13

define Я использую для глобальных констант.

const Я использую для констант класса.

Вы не можете define в поле класса, а с помощью const можете. Разумеется, вы не можете использовать const область внешнего класса

Кроме того, с const он фактически становится членом класса, с define он будет перенесен в глобальную область.

  • 6
    Как отмечалось в других ответах, const можно использовать вне классов в PHP 5.3+
  • 0
    Для создания константы пространства имен можно использовать только ключевое слово const, а не только классы.
12

Большинство из этих ответов неверны или только рассказывают половину истории.

  • Вы можете объединить свои константы с помощью пространств имен.
  • Вы можете использовать ключевое слово "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 теперь обрабатывается по-другому.
  • 3
    PHP 7 может работать с const WEAKNESS = 4+5+6;
12

Ответ 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 на самом деле не гарантирует этого.

  • 0
    Да, но BAR и \foo\BAR просто не совпадают. Я согласен, что это действительно сбивает с толку, но если вы также считаете, что такие вещи, как логика пространства имен, являются непротиворечивыми, и что ни const ни define() не похожи на макрос C ( #define ), то у PHP может быть некоторое оправдание.
  • 0
    Понятие const - это именно то, как оно должно вести себя - вы находитесь в пространстве имен! Вы хотите получить его без идентификатора пространства имен, а затем создать его вне пространства имен. Это также делает его совместимым с определением const в классе, даже если он использует другой синтаксис. Да, определение тоже соответствует, по-другому.
5

Да, константы определены во время компиляции, и поскольку никическим состояниям нельзя назначить выражение, как define(). Но и const нельзя условно объявить (по той же причине). то есть. Вы не можете этого сделать:

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

В то время как вы можете с define(). Таким образом, это действительно не соответствует личным предпочтениям, есть правильный и неправильный способ использования обоих.

Как в стороне... Я хотел бы увидеть какой-то класс const, которому может быть присвоено выражение, своего рода define(), который может быть выделен для классов?

2

Добавить ответ NikiC. const можно использовать в классах следующим образом:

class Foo {
    const BAR = 1;

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

Вы не можете сделать это с помощью define().

Ещё вопросы

Сообщество Overcoder
Наверх
Меню