Easy📖Теория5 min

Константы

define, const, магические константы, типизированные константы классов

Константы

Объявление констант

Константы -- значения, которые нельзя изменить после определения. В PHP два способа объявления: define() и const.

define() vs const

<?php
declare(strict_types=1);

// define() — runtime declaration
define('MAX_RETRIES', 3);
define('API_URL', 'https://api.example.com');

// const — compile-time declaration
const API_VERSION = '2.0';
const TIMEOUT = 30;

Ключевые различия

Свойство const define()
Момент определения Compile-time Runtime
В условных блоках Нельзя Можно
В namespace Да, с учётом namespace Всегда глобальная
Выражения в значении PHP 5.6+ простые Любые
Массивы PHP 5.6+ PHP 7.0+
<?php
declare(strict_types=1);

// define() can be conditional — useful for environment config
$env = getenv('APP_ENV') ?: 'development';

if ($env === 'production') {
    define('DEBUG', false);
    define('LOG_LEVEL', 'error');
} else {
    define('DEBUG', true);
    define('LOG_LEVEL', 'debug');
}

// const CANNOT be conditional — compile-time only
// if (true) {
//     const FOO = 'bar'; // Parse error!
// }

Области видимости констант

<?php
declare(strict_types=1);

namespace App\Config;

// const respects namespace
const DB_HOST = 'localhost';
// Full name: App\Config\DB_HOST

// define() is ALWAYS global
define('GLOBAL_KEY', 'abc123');
// Full name: GLOBAL_KEY (no namespace prefix)

// Accessing namespaced constant
echo \App\Config\DB_HOST;  // 'localhost'
echo GLOBAL_KEY;            // 'abc123'

Ловушка экзамена: const внутри namespace создаёт константу с полным именем (включая namespace). define() всегда создаёт глобальную константу, даже если вызван внутри namespace. Для создания именованной константы через define() нужно указать полное имя: define('App\Config\DB_HOST', 'localhost').

Константы классов

Классовые константы определяются внутри класса и доступны через ClassName::CONSTANT:

<?php
declare(strict_types=1);

class HttpStatus
{
    public const OK = 200;
    public const CREATED = 201;
    public const NOT_FOUND = 404;
    public const SERVER_ERROR = 500;

    // Access modifiers (PHP 7.1+)
    private const INTERNAL_CODE = 'X-001';
    protected const BASE_URL = '/api';
}

echo HttpStatus::OK;        // 200
echo HttpStatus::NOT_FOUND;  // 404
// echo HttpStatus::INTERNAL_CODE; // Error: private!

Константы в интерфейсах

<?php
declare(strict_types=1);

interface Cacheable
{
    // Interface constants are always public
    const DEFAULT_TTL = 3600;
    const MAX_TTL = 86400;
}

class UserCache implements Cacheable
{
    public function getTtl(): int
    {
        return self::DEFAULT_TTL; // 3600
    }

    // PHP 8.1+: can override interface constants
    // const DEFAULT_TTL = 7200; // Override allowed
}

Наследование и final

<?php
declare(strict_types=1);

class Base
{
    const VERSION = '1.0';

    // PHP 8.1+: final constants cannot be overridden
    final public const FRAMEWORK = 'PHP';
}

class Child extends Base
{
    const VERSION = '2.0'; // Override — allowed

    // const FRAMEWORK = 'Node'; // Fatal error: cannot override final constant
}

echo Child::VERSION;   // '2.0'
echo Child::FRAMEWORK; // 'PHP'

Типизированные константы классов (PHP 8.3+)

PHP 8.3 добавил поддержку явной типизации константам классов:

<?php
declare(strict_types=1);

class Config
{
    public const string APP_NAME = 'MyApp';
    public const int MAX_RETRIES = 3;
    public const float TIMEOUT = 30.0;
    public const bool DEBUG = false;
    protected const array ALLOWED_HOSTS = ['localhost', '127.0.0.1'];

    // Union types work too
    public const string|int VERSION = '2.0';
}

interface HasLimit
{
    // Typed constants in interfaces
    public const int MAX_ITEMS = 100;
}

class ItemService implements HasLimit
{
    // Must match type from interface
    public const int MAX_ITEMS = 50; // OK: same type, different value
    // public const string MAX_ITEMS = 'fifty'; // TypeError!
}

Запомни: Типизированные константы (PHP 8.3+) обеспечивают контроль типов при наследовании. Если интерфейс объявляет const int MAX, то реализация не может изменить тип на string. Это предотвращает ошибки при рефакторинге.

Магические константы

Магические константы изменяют значение в зависимости от контекста использования. Их восемь плюс ::class:

<?php
declare(strict_types=1);

echo __LINE__;      // Current line number (e.g., 5)
echo __FILE__;      // Full path to current file
                    // /var/www/app/src/Service.php
echo __DIR__;       // Directory of current file
                    // /var/www/app/src
echo __FUNCTION__;  // Current function name
echo __CLASS__;     // Current class name (with namespace)
echo __METHOD__;    // Current method name (Class::method)
echo __NAMESPACE__; // Current namespace
echo __TRAIT__;     // Current trait name

Практические примеры

<?php
declare(strict_types=1);

namespace App\Service;

trait Loggable
{
    public function log(string $message): void
    {
        echo sprintf(
            "[%s::%s at %s:%d] %s\n",
            __CLASS__,      // App\Service\OrderService (resolved at use site)
            __FUNCTION__,   // log
            __FILE__,       // /var/www/app/src/Service/OrderService.php
            __LINE__,       // current line number
            $message,
        );
    }
}

class OrderService
{
    use Loggable;

    public function process(): void
    {
        echo __CLASS__;     // App\Service\OrderService
        echo __METHOD__;    // App\Service\OrderService::process
        echo __NAMESPACE__; // App\Service

        $this->log('Processing order');
    }
}

::class -- разрешение имени класса

<?php
declare(strict_types=1);

namespace App\Entity;

class User {}

echo User::class;  // 'App\Entity\User' (FQCN)
echo self::class;  // Current class FQCN (inside class only)

// PHP 8.0+: works on instances
$user = new User();
echo $user::class; // 'App\Entity\User'

Ловушка экзамена: __CLASS__ внутри трейта разрешается в имя класса, который использует трейт, а не имя самого трейта. Для получения имени трейта используйте __TRAIT__. Все магические константы, кроме __CLASS__ и __TRAIT__, разрешаются на этапе компиляции.

Предопределённые константы

PHP предоставляет множество встроенных констант:

Константы типов и ограничений

<?php
declare(strict_types=1);

// Version info
echo PHP_VERSION;        // '8.4.3'
echo PHP_MAJOR_VERSION;  // 8
echo PHP_MINOR_VERSION;  // 4
echo PHP_RELEASE_VERSION; // 3
echo PHP_VERSION_ID;     // 80403

// Integer limits
echo PHP_INT_MAX;   // 9223372036854775807 (64-bit)
echo PHP_INT_MIN;   // -9223372036854775808
echo PHP_INT_SIZE;  // 8 (bytes on 64-bit system)

// Float limits
echo PHP_FLOAT_MAX;     // 1.7976931348623E+308
echo PHP_FLOAT_MIN;     // 2.2250738585072E-308
echo PHP_FLOAT_EPSILON; // 2.2204460492503E-16
echo PHP_FLOAT_DIG;     // 15

// Special values
echo PHP_EOL;               // "\n" or "\r\n" (OS-dependent)
echo DIRECTORY_SEPARATOR;   // "/" or "\" (OS-dependent)
echo PATH_SEPARATOR;        // ":" or ";" (OS-dependent)

Системные константы

<?php
declare(strict_types=1);

echo PHP_SAPI;       // 'cli', 'fpm-fcgi', 'apache2handler'
echo PHP_OS;         // 'Linux', 'Darwin', 'WINNT'
echo PHP_OS_FAMILY;  // 'Linux', 'Darwin', 'Windows' (PHP 7.2+)
echo PHP_MAXPATHLEN; // 4096 (max filesystem path length)

// Boolean and null constants (case-insensitive)
var_dump(TRUE);   // bool(true)
var_dump(FALSE);  // bool(false)
var_dump(NULL);   // NULL

Константы ошибок

<?php
declare(strict_types=1);

// Error level constants (bitmask)
E_ERROR;            // 1    — Fatal errors
E_WARNING;          // 2    — Runtime warnings
E_NOTICE;           // 8    — Runtime notices
E_DEPRECATED;       // 8192 — Deprecation notices
E_ALL;              // All errors and warnings

// Common error reporting setup
error_reporting(E_ALL);
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);

Новые константы PHP 8.5+

<?php
declare(strict_types=1);

// PHP 8.5+ new constants
echo PHP_BUILD_DATE;     // Date when PHP was built
echo PHP_BUILD_PROVIDER; // Who built the PHP binary (e.g., 'ondrej')

Константы в Enums (PHP 8.1+)

Перечисления могут содержать константы наряду с кейсами:

<?php
declare(strict_types=1);

enum Season: string
{
    case Spring = 'spring';
    case Summer = 'summer';
    case Autumn = 'autumn';
    case Winter = 'winter';

    // Constants in enums
    const array WARM = [self::Spring, self::Summer];
    const array COLD = [self::Autumn, self::Winter];

    public function isWarm(): bool
    {
        return in_array($this, self::WARM, true);
    }
}

echo Season::Spring->value; // 'spring'
var_dump(Season::Spring->isWarm()); // true
var_dump(Season::WARM); // [Season::Spring, Season::Summer]

Запомни: Кейсы enum и константы enum -- разные вещи. Кейсы (case) определяют экземпляры перечисления, а константы (const) -- обычные значения. Константа может содержать массив кейсов для группировки.

defined() и constant()

Проверка существования и динамический доступ

<?php
declare(strict_types=1);

// Check if constant is defined
if (defined('APP_ENV')) {
    echo constant('APP_ENV');
}

// Dynamic constant access with constant()
$constName = 'PHP_VERSION';
echo constant($constName); // e.g., '8.4.3'

// Useful for class constants with dynamic names
$class = 'HttpStatus';
$code = 'NOT_FOUND';
echo constant("{$class}::{$code}"); // 404

Проверка константы класса

<?php
declare(strict_types=1);

class Config
{
    public const string APP_NAME = 'MyApp';
}

// Check class constant existence
echo defined('Config::APP_NAME') ? 'exists' : 'not found'; // exists
echo defined('Config::MISSING') ? 'exists' : 'not found';   // not found

// Reflection alternative (more info)
$ref = new ReflectionClass(Config::class);
$constants = $ref->getConstants(); // ['APP_NAME' => 'MyApp']

Устаревшее: переопределение констант (PHP 8.5)

Начиная с PHP 8.5, повторное определение константы через define() вызывает предупреждение об устаревании:

<?php
declare(strict_types=1);

define('FOO', 1);
echo FOO; // 1

// PHP < 8.5: silently overwrites (bad!)
// PHP 8.5+: Deprecated warning!
define('FOO', 2); // Deprecated: Constant FOO already defined

// const never allowed redeclaration
// const BAR = 1;
// const BAR = 2; // Fatal error: Cannot redefine constant BAR

Ловушка экзамена: До PHP 8.5 define() молча перезаписывал существующую константу. С PHP 8.5 это deprecated. const никогда не позволял переопределение -- всегда Fatal Error. Используйте defined() для проверки перед определением.


Вопросы с экзамена ZCE

Проверь себя

5 из 19
🧪

Какой модификатор запрещает переопределение константы класса в наследниках?

🧪

Что добавил PHP 8.3 для констант классов?

🧪

Могут ли enum содержать обычные константы (не case)?

🧪

Что вернёт `PHP_EOL` на Linux?

🧪

Можно ли использовать `const` внутри `if` блока?

Связанные темы