определить() против const

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

define('FOO', 1);

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

const FOO = 1;

?

Каковы основные различия между этими двумя?

Ответ 1

Начиная с 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);
    }
    
  • const всегда чувствительны к регистру, тогда как define() позволяет вам определять нечувствительные к регистру константы, передавая true в качестве третьего аргумента:

    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');
    
  • Начиная с 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 and valid in PHP 7.0
    

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

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

Резюме

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

Ответ 2

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

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

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

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

Ответ 3

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

Как и в случае 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;

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

Ответ 4

Я считаю, что с 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;
?>

Ответ 5

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

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

Вы не можете define в области видимости класса, и с помощью const вы можете. Излишне говорить, что вы не можете использовать const вне области видимости.

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

Ответ 6

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

Ответ 7

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

  • Вы можете объединить свои константы с помощью пространств имен.
  • Вы можете использовать ключевое слово "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

Ответ 8

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

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

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

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

Ответ 9

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

class Foo {
    const BAR = 1;

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

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

Ответ 10

Никто ничего не говорит о php-doc, но для меня это тоже очень важный аргумент в пользу предпочтения const:

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

Ответ 11

С помощью определения ключевого слова константа вы получите все возможности
нечувствителен, но с ключевым словом 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