Различие между PHP getenv() и $_ENV

Переменные среды играют важную роль в современной разработке, в частности, для управления конфиденциальными данными, такими как ключи API или специфические конфигурации среды. В PHP существует два основных способа доступа к этим переменным: функция 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 или виртуальный хостинг. Понимая эти тонкости и следуя рекомендациям, можно избежать коварных багов и обеспечить лучшую переносимость кода.

Сталкивались ли вы с подобными проблемами или хотите поделиться советами?

Комментарии


Дополнительные материалы

Предыдущая Статья

Руководство по вебхукам в Laravel

Следующая Статья

Кэширование аутентифицированных пользователей в Laravel