Различие между PHP getenv()
и $_ENV
getenv
и суперглобальная переменная $_ENV
. Хотя они могут показаться взаимозаменяемыми, но ведут себя по-разному и могут создавать проблемы при неправильном использовании.Различие между getenv
и $_ENV
getenv
Функция getenv
напрямую обращается к системным переменным среды. Это означает, что она взаимодействует с окружением, в котором выполняется PHP процесс, независимо от конфигураций, специфичных для PHP.
putenv('MY_SECRET_KEY=MY_VALUE');
echo getenv('MY_SECRET_KEY'); // Выводит: MY_VALUE
$_ENV
С другой стороны, суперглобальная переменная $_ENV
зависит от конфигурации php.ini
файла. В частности, она заполняется только в том случае, если директива variables_order
содержит букву E
. В некоторых средах (например, в конфигурациях по умолчанию на некоторых серверах) $_ENV
может быть пустой.
putenv('MY_SECRET_KEY=MY_VALUE');
echo $_ENV['MY_SECRET_KEY']; // Может не работать
Требуется настройка в файле php.ini
:
variables_order = "GPCS" # Добавьте "E" для включения $_ENV
Директива variables_order
Директива variables_order
в php.ini
управляет тем, какие суперглобалы PHP инициализирует и в каком порядке. Она принимает строку букв, каждая из которых представляет категорию переменных:
G
: переменныеGET
(например,$_GET
из URL).P
: переменныеPOST
(например,$_POST
из форм).C
: переменные cookie (например,$_COOKIE
).S
: переменные сеанса (например,$_SESSION
).E
: переменные среды (например,$_ENV
).
Пример конфигурации
Полная конфигурация
variables_order = "GPCSE"
- Все суперглобалы инициализированы.
$_ENV
будет заполнена переменными среды системы.
Частичная конфигурация
variables_order = "GPCS"
- Инициализируются только
$_GET
,$_POST
,$_COOKIE
и$_SESSION
. $_ENV
остаётся незаполненной.
Реальный пример: Рабочие процессы GitHub и автоматизированные тесты
При использовании GitHub Actions для автоматизации проекта я столкнулся с проблемой во время выполнения тестов, требующих секретные ключи, настроенные в GitHub. Мой код попытался получить эти значения через $_ENV
, но потерпел неудачу.
После изучения ситуации я понял, что $_ENV
в этом окружении пуст. Однако использование getenv
позволило получить доступ к переменным без проблем.
Это заставило меня углубиться в изучение того, как работают getenv
и $_ENV
.
Исходный (проблемный) код:
$secretKey = $_ENV['SECRET_KEY'] ?? null;
if (!$secretKey) {
throw new Exception('Secret key not found');
}
Рабочее решение:
$secretKey = getenv('SECRET_KEY');
if (!$secretKey) {
throw new Exception('Secret key not found');
}
Компонент vlucas/phpdotenv
Этот вопрос заставил задуматься, как популярные библиотеки вроде vlucas/phpdotenv
работают с переменными среды. Любопытствуя, решил поглубже разобраться, как это работает.
Библиотека использует умный, многослойный подход для обеспечения максимальной совместимости с различными настройками PHP. При загрузке .env
файла она не останавливается на одном способе сделать переменные доступными. Он напрямую заполняет суперглобальную переменную $_ENV
, присваивая ей каждую пару ключ/значение из файла, а также использует встроенную функцию PHP putenv()
для внедрения этих переменных в окружение системы. Это означает, что они будут мгновенно доступны и через getenv()
.
В зависимости от конфигурации phpdotenv
может также заполнять $_SERVER
, обеспечивая гибкость независимо от того, как именно код обращается к переменным среды. Такая конструкция делает его надёжным решением для сред, где конфигурация PHP вами не контролируется.
putenv()
и потокобезопасность
При использовании putenv()
следует помнить, что она изменяет глобальное окружение для всего процесса, что может привести к возникновению условий гонки в многопоточных приложениях.
Это не представляет проблемы в однопоточной среде, но в многопоточной среде может привести к непредсказуемому поведению.
Рекомендации
- Используйте
getenv
для доступа к переменным среды: Особенно в средах, где нет полного контроля над конфигурацией PHP (например, CI/CD, виртуальный хостинг и т.д.). - Тестируйте в целевом окружении: Различия между локальным и удалённым окружением часто являются источником труднодиагностируемых багов.
- Использовать
putenv()
настоятельно не рекомендуется из-за того, что эта функция не является потокобезопасной. - Проверьте конфигурацию
php.ini
: Если требуется использовать$_ENV
, убедитесь, чтоvariables_order
включаетE
или… - При необходимости заполните
$_ENV
вручную:$_ENV
можно заполнить самостоятельно следующим образом:foreach ($values as $key => $value) {
$_ENV[$key] = $value;
}
Заключение
Хотя getenv
и $_ENV
кажутся похожими, их различия могут привести к проблемам, особенно в таких контекстах, как конвейеры CI/CD или виртуальный хостинг. Понимая эти тонкости и следуя рекомендациям, можно избежать коварных багов и обеспечить лучшую переносимость кода.
Сталкивались ли вы с подобными проблемами или хотите поделиться советами?