пятница, 17 июня 2022 г.

Константы и пространства имен в php

Сегодня поисследуем использование пространств имен (они же неймспейсы) для объявления констант и обращения к ним.

Как сказано в мануале:

классы (включая абстрактные и трейты), интерфейсы, функции и константы зависят от пространства имен.

То есть, если зарегистрировать константы с одинаковыми именами в нескольких неймспейсах, в том числе и глобальном, то за это ничего не будет, и обращение к каждой из констант будет работать без ошибок.

Проверим:

namespace FirstNs {
    const SUPER_VALUE = 'NS-1';
}

namespace SecondNs {
    const SUPER_VALUE = 'NS-2';
}

namespace {
    const SUPER_VALUE = 'NS-GLOBAL';
    var_dump(
        SUPER_VALUE,
        FirstNs\SUPER_VALUE,
        SecondNs\SUPER_VALUE,
    );
}

// Вывод:
// string(9) "NS-GLOBAL"
// string(4) "NS-1"
// string(4) "NS-2"

Ровно то, что нужно.

Но что если мы хотим определить константы методом define.

Не проблема, пробуем написать так:

namespace FirstNs {
    define('SUPER_VALUE', 'NS-1');
}

namespace SecondNs {
    define('SUPER_VALUE', 'NS-2');
}

namespace {
    define('SUPER_VALUE', 'NS-GLOBAL');
    var_dump(
        SUPER_VALUE,
        FirstNs\SUPER_VALUE,
        SecondNs\SUPER_VALUE,
    );
}

Запускаем и видим:

Warning: Constant SUPER_VALUE already defined in ...
Warning: Constant SUPER_VALUE already defined in ...
Fatal error: Uncaught Error: Undefined constant "FirstNs\SUPER_VALUE" in ...

Судя по всему, мы пытаемся три раза определить одну и ту же константу в глобальном неймспейсе. Что же делать?

А просто указать нужный неймспейс при определении константы, благо php это позволяет:

namespace FirstNs {
    define('FirstNs\\SUPER_VALUE', 'NS-1');
    // или
    define(__NAMESPACE__ . '\\SUPER_VALUE', 'NS-1');
    
}

namespace SecondNs {
    define('SecondNs\\SUPER_VALUE', 'NS-2');
}

namespace {
    define('SUPER_VALUE', 'NS-GLOBAL');
    var_dump(
        SUPER_VALUE,
        FirstNs\SUPER_VALUE,
        SecondNs\SUPER_VALUE,
    );
}

// Вывод:
// string(9) "NS-GLOBAL"
// string(4) "NS-1"
// string(4) "NS-2"

Можно даже пойти дальше и в одном неймспейсе определить константу другого неймспейса:

namespace FirstNs {
    define('SecondNs\\SUPER_VALUE', 'NS-2-1');
}

namespace SecondNs {
    define('FirstNs\\SUPER_VALUE', 'NS-1-2');
}

Делать так в продакшене категорически не рекомендуется.

Итак, сегодня мы разобрались с тем, как определять константы с учетом неймспейсов, используя как ключевое слово const, так и функцию define.

Комментариев нет:

Отправить комментарий