Avatar ·

define() или const в PHP: в чем разница и что лучше использовать для констант?

Всем привет! Я начинающий PHP-разработчик, пишу свой первый проект на чистом PHP (без фреймворков). Столкнулся с вопросом: как правильно объявлять константы? В учебниках и на Stack Overflow видел два способа: через define() и через const. Например: ```php // Способ 1 define('SITE_NAME', 'Мой сайт'); define('MAX_LOGIN_ATTEMPTS', 5); // Способ 2 const SITE_NAME = 'Мой сайт'; const MAX_LOGIN_ATTEMPTS = 5; ``` Оба работают, но я не понимаю, в чем между ними принципиальная разница. Когда я гуглил, то нашел упоминания про PSR-1 и PSR-12, но там написано общими словами: "используйте const". Но почему? define() ведь тоже работает. Еще я заметил, что в старых проектах (PHP 5) везде используется define(), а в современных (PHP 8) — const. Это просто дело вкуса или есть технические причины? Конкретно меня интересует: 1. Можно ли const использовать внутри классов и вне классов? 2. Работают ли оба варианта с массивами? 3. Есть ли разница в производительности? 4. Что говорят современные стандарты PSR? Буду благодарен за подробное объяснение с примерами. Хочется разобраться раз и навсегда, чтобы не гадать в будущем. <<>>

Основные различия между define() и const в PHP

Разница между этими двумя способами объявления констант действительно существенная, и выбор зависит от контекста использования. Давайте разберем все по порядку.

1. Время определения (compile time vs runtime)

Это ключевое отличие:

  • const — определяется на этапе компиляции (compile time). Это значит, что константу нельзя объявить внутри условного оператора, цикла или функции. Она существует с момента загрузки файла.
  • define() — выполняется во время выполнения (runtime). Поэтому define() можно использовать внутри циклов, условий, функций — где угодно.
// Работает
define('MY_CONST', 'value');
if (true) {
    define('MY_OTHER_CONST', 'value2');
}

// Ошибка! const нельзя использовать внутри блока if
if (true) {
    const MY_CONST = 'value'; // Parse error
}

2. Область видимости

const по умолчанию работает в пространстве имен (namespace), а define() — всегда в глобальном пространстве, если не указано иное.

namespace MyApp\Config;

// Эта константа будет MyApp\Config\DB_HOST
const DB_HOST = 'localhost';

// А эта всегда будет DB_PORT в глобальном пространстве
define('DB_PORT', 3306);

3. Использование в классах

const можно использовать внутри классов для объявления констант класса. define() — нет.

class User {
    const MAX_AGE = 120;
    
    public function getMaxAge() {
        return self::MAX_AGE;
    }
}

// Обращение
echo User::MAX_AGE; // 120

4. Типы данных

Оба могут хранить скалярные типы (int, float, string, bool) и null. Но:

  • С PHP 5.6: const может хранить простые выражения (константы + операторы)
  • С PHP 7.0: define() может хранить массивы
  • С PHP 7.0: const может хранить массивы
// Оба работают с PHP 7+
define('COLORS', ['red', 'green', 'blue']);
const COLORS = ['red', 'green', 'blue'];

// Но const не может использовать сложные выражения
const SITE = 'http://' . $_SERVER['HTTP_HOST']; // Ошибка!
define('SITE', 'http://' . $_SERVER['HTTP_HOST']); // Работает

5. Производительность

const немного быстрее, потому что обрабатывается на этапе компиляции. Но разница настолько микроскопическая, что в реальных проектах ее можно не учитывать. Главное — читаемость и соответствие стандартам.

Что говорят PSR-1 и PSR-12?

Стандарты PSR-1 и PSR-12 рекомендуют использовать const для констант, не связанных с классами. Это сделано для единообразия кода и потому что const работает на уровне пространства имен, что лучше для автозагрузки и современных архитектур.

Рекомендация

Используйте const по умолчанию — это современный, предсказуемый и соответствующий стандартам способ. К define() обращайтесь только в особых случаях:

  • Когда нужно объявить константу внутри условия или цикла
  • Когда константа зависит от runtime-значения (например, из базы данных или $_SERVER)
  • Для обратной совместимости со старым кодом

Пример правильного подхода в современном PHP:

namespace App\Config;

class Database {
    const HOST = 'localhost';
    const PORT = 3306;
    const NAME = 'myapp';
}

// Для runtime-значений
if (getenv('APP_ENV') === 'development') {
    define('DEBUG_MODE', true);
} else {
    define('DEBUG_MODE', false);
}
<<>>

Дополнительные нюансы: define() с регистронезависимостью и глобальные константы

В PHP существует еще один малоизвестный, но полезный аргумент для define() — третий параметр $case_insensitive. Он позволяет создавать регистронезависимые константы:

define('MY_CONST', 'value', true);
echo MY_CONST;  // 'value'
echo my_const;  // 'value' (тоже работает!)

Это может быть удобно для легаси-кода или при интеграции с системами, где регистр не фиксирован. Однако учтите:

  • Этот параметр объявлен устаревшим с PHP 7.3 и будет удален в PHP 9.
  • Регистронезависимые константы работают медленнее.
  • const никогда не поддерживает регистронезависимость.

Еще один важный момент: define() всегда создает константу в глобальном пространстве имен, если вы явно не укажете неймспейс в имени. Это может привести к конфликтам имен:

namespace MyProject;

// Неожиданность: эта константа будет глобальной, а не в MyProject!
define('VERSION', '1.0');

// А это уже правильный способ для define с неймспейсом:
define(__NAMESPACE__ . '\VERSION', '1.0');

В то время как const автоматически привязывается к текущему пространству имен. Именно поэтому PSR рекомендует const — он менее подвержен ошибкам при работе с неймспейсами.

Итог: если вы пишете новый код на PHP 7.4+, используйте const. define() оставьте для специфических ситуаций, когда константа должна быть глобальной или зависеть от условий выполнения.