Константы
Объявление констант
Константы -- значения, которые нельзя изменить после определения. В 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()для проверки перед определением.