define () против const - PullRequest
       31

define () против const

624 голосов
/ 15 марта 2010

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

define('FOO', 1);

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

const FOO = 1;

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

Ответы [ 11 ]

990 голосов
/ 07 июля 2010

Начиная с 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 s всегда чувствительны к регистру, тогда как 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, valid in PHP 7.0
    

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

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

Резюме

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

196 голосов
/ 15 марта 2010

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

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

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

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

37 голосов
/ 26 сентября 2011

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

Начиная с 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].

=== ОБНОВЛЕНИЕ ===

Предстоящий PHP 5.6 позволит немного больше гибкости с 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 RND = mt_rand();
const CONSTVAR = $var;

все еще будет отсутствовать.

22 голосов
/ 30 июня 2010

Я считаю, что в 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;
?>
19 голосов
/ 15 марта 2010

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

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

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

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

15 голосов
/ 18 мая 2012

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

11 голосов
/ 07 февраля 2013

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

  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
5 голосов
/ 05 апреля 2017

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

class Foo {
    const BAR = 1;

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

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

5 голосов
/ 08 июля 2010

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

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

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

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

3 голосов
/ 23 декабря 2017

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

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