cloud-castle / env
Загрузчик окружения для PHP 8.1+: dotenv-совместимый разбор с модификаторами оболочки, каскад .env/.env.local/.env.<окружение>, компиляция в PHP-кэш, типизированное чтение (числа, списки, JSON, размеры, длительности, перечисления), схема конфигурации с генерацией .env.example, маскирование секретов,
Package info
pkg:composer/cloud-castle/env
Requires
- php: >=8.1
- ext-openssl: *
Requires (Dev)
- deptrac/deptrac: ^3.0 || ^4.0
- devcoder-xyz/php-dotenv: ^3.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- infection/infection: ^0.29 || ^0.33
- josegonzalez/dotenv: ^3.2
- m1/env: ^2.2
- php-parallel-lint/php-parallel-lint: ^1.4
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- symfony/dotenv: ^6.4 || ^7.0
- vimeo/psalm: ^6.0
- vlucas/phpdotenv: ^5.6
- webmozart/assert: ^1.11
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-15 06:16:44 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Env
Загрузчик окружения для PHP 8.1+: совместимый с dotenv разбор с модификаторами оболочки (
${VAR:-по умолчанию},${VAR:?сообщение}), каскад окружений (.env→.env.local→.env.prod), компиляция в PHP-кэш, типизированное чтение (числа, списки, JSON, размеры512M, длительности1h30m, перечисления), схема конфигурации с генерацией.env.example, маскирование секретов и шифрование файла окружения AES-256-GCM. Без внешних пакетов в зависимостях.
Установка
composer require cloud-castle/env
Требуется PHP 8.1+ и штатное расширение ext-openssl (шифрование хранилища).
Быстрый старт
<?php
use CloudCastle\Env\Env;
use CloudCastle\Env\Schema\Schema;
use CloudCastle\Env\Schema\VariableType;
// Каскад .env / .env.local / .env.prod с кэшем на продакшне.
Env::bootEnv('/app/.env', 'prod');
// Контракт окружения: падаем на старте, а не на первом запросе пользователя.
Env::assertSchema(Schema::fromArray([
'APP_ENV' => ['required' => true, 'allowed' => ['dev', 'test', 'prod']],
'APP_KEY' => ['required' => true, 'secret' => true, 'description' => 'Ключ подписи'],
'DB_PORT' => ['type' => VariableType::Integer, 'default' => '5432'],
'UPLOAD_MAX' => ['type' => VariableType::Bytes, 'default' => '8M'],
'SESSION_TTL' => ['type' => VariableType::Duration, 'default' => '1h'],
]));
// Типизированное чтение — без ручного приведения строк.
$debug = Env::getBool('APP_DEBUG', false);
$port = Env::getInt('DB_PORT', 5432);
$upload = Env::getBytes('UPLOAD_MAX'); // 512M → 536870912
$ttl = Env::getSeconds('SESSION_TTL'); // 1h30m → 5400
$hosts = Env::getList('CACHE_HOSTS'); // a,b,c → ['a', 'b', 'c']
$limits = Env::getArray('RATE_LIMITS'); // JSON → массив
Возможности
- Совместимый разбор
.env: кавычки, экранирование, многострочные значения, комментарии, префиксexport; результат совпадает сvlucas/phpdotenv,symfony/dotenvиjosegonzalez/dotenv(проверяется интероп-тестами). - Интерполяция с модификаторами оболочки:
${VAR},${VAR:-умолчание},${VAR:+замена},${VAR:?сообщение}, ссылки на переменные ниже по файлу и обнаружение циклов. Подстановка команд$(…)— только с явным исполнителем. - Каскад окружений
.env→.env.local→.env.<окружение>с честными приоритетами: реальные переменные процесса файлами не затираются. - Компиляция в PHP-кэш: продакшн не читает и не разбирает текст на каждом запросе.
- Типизированное чтение:
getInt,getFloat,getBool,getList,getArray,getBytes,getSeconds,getMap,getEnum. - Схема конфигурации: проверка окружения на старте, типизированные значения,
генерация
.env.example, поиск переменных вне контракта. - Хранилище под задачу:
$_ENV,$_SERVER,putenv, константы, переменные Apache или изолированная память; иммутабельность и белый список изменяемых имён. - Безопасность: маскирование секретов в дампах, шифрование файла AES-256-GCM,
права
0600на генерируемые файлы, значения не попадают в сообщения об ошибках. - Инструменты: сравнение с эталоном, трассировка происхождения переменных,
выгрузка в
env/shell/json/phpи консольная утилитаcloud-castle-env.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически из честных сравнительных прогонов (benchmarks/compare.php, benchmarks/quality.php) на одинаковых операциях и
одинаковых правилах анализаторов для всех участников, без Xdebug.
_PHP 8.1.34. Участники: cloud-castle/env v1.1.3, symfony/dotenv v6.4.42, vlucas/phpdotenv v5.6.4, josegonzalez/dotenv 3.2.0, m1/env 2.2.0, phpdevcommunity/dotenv 3.0.1, parse_ini_string PHP 8.1.34._
1. Функциональность
| Возможность | CloudCastle | symfony | vlucas | josegonzalez | m1 | phpdevcommunity | parse_ini_string |
|---|---|---|---|---|---|---|---|
| Разбор пар КЛЮЧ=значение | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Кавычки и экранирование | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Многострочные значения в кавычках | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Инлайн-комментарии | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Интерполяция ${VAR} между переменными | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Модификаторы ${VAR:-по умолчанию} и ${VAR:+замена} | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Обязательная ссылка ${VAR:?сообщение} | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Ссылки на переменные, объявленные ниже | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Обнаружение циклических ссылок | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Подстановка команд $(…) с явным разрешением | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Загрузка из строки без обращения к диску | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ |
| Каскад .env / .env.local / .env.<окружение> | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Компиляция окружения в PHP-кэш | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Иммутабельная загрузка (не затирает окружение) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Мутабельная перезагрузка поверх окружения | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Изолированное хранилище в памяти | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Выбор приёмников: $_ENV, $_SERVER, putenv | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Адаптер переменных Apache | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Определение констант вместо переменных | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| Белый список изменяемых переменных | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Типизированное чтение (int/float/bool/список) | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Чтение JSON-массива из переменной | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Размеры с суффиксами (512M, 1.5G) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Длительности с суффиксами (1h30m, 7d) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Карты пар «ключ=значение» в одной переменной | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Чтение перечислений (backed enum) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Проверка обязательных переменных и их значений | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Схема конфигурации как контракт окружения | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Генерация .env.example из схемы | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Выявление переменных вне схемы | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Сравнение файла окружения с эталоном | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Трассировка происхождения переменных | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Выгрузка в env / shell / json / php | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Маскирование секретов в выгрузке | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Шифрование файла окружения | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Фильтры имён (префикс, регистр, переименование) | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| Разбор URL на составные переменные | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| Консольная утилита из коробки | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Нулевые внешние пакеты в зависимостях | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Всего | 🏆 39 | 17 | 13 | 12 | 8 | 4 | 5 |
2. Безопасность и корректность
| Свойство | CloudCastle | symfony | vlucas | josegonzalez | m1 | phpdevcommunity | parse_ini_string |
|---|---|---|---|---|---|---|---|
| Иммутабельность окружения по умолчанию | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Содержимое файла не выполняет код без разрешения | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Белый список изменяемых переменных | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Проверка значений до старта приложения | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Отказ при некорректной кодировке файла | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Типизированные исключения пакета | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Значения не попадают в сообщения об ошибках | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Маскирование секретов в дампах | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Шифрование файла окружения (AES-256-GCM) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Права 0600 на создаваемые файлы | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Нулевые внешние пакеты (меньше поверхность атаки) | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Всего | 🏆 11 | 3 | 6 | 5 | 3 | 2 | 2 |
3. Качество кода
замечания анализаторов на 1000 строк кода (меньше — лучше) и доля файлов со строгой типизацией (больше — лучше); ко всем участникам применяются одинаковые правила.
| Метрика | CloudCastle | symfony | vlucas | josegonzalez | m1 | phpdevcommunity | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Ошибок синтаксиса на 1000 строк | 0,0 | 0,0 | 0,0 | 0,0 | 0,0 | 0,0 | ничья |
| Нарушений PSR-12 на 1000 строк | 0,0 | 100,3 | 8,9 | 5,1 | 18,4 | 41,7 | 🏆 CloudCastle |
| Запахов кода на 1000 строк | 0,0 | 41,2 | 6,5 | 10,2 | 6,8 | 4,6 | 🏆 CloudCastle |
| Ошибок PHPStan (max) на 1000 строк | 0,0 | 117,3 | 7,9 | 267,9 | 83,2 | 41,7 | 🏆 CloudCastle |
| Файлов с устаревшими конструкциями на 1000 строк | 0,0 | 7,2 | 11,4 | 13,7 | 6,8 | 32,4 | 🏆 CloudCastle |
| Известных уязвимостей пакета | 0,0 | 0,0 | 0,0 | 0,0 | 0,0 | 0,0 | ничья |
| Файлов со строгой типизацией, % | 100,0 | 0,0 | 100,0 | 0,0 | 0,0 | 0,0 | ничья |
| Сигнатур с типом возврата, % | 100,0 | 100,0 | 0,0 | 0,0 | 0,0 | 57,1 | ничья |
| Побед по метрикам | 🏆 8 | 3 | 3 | 2 | 2 | 2 |
4. Производительность: разбор файла .env
Разбор .env из 12 переменных, 100 000 раз (минимум из 4 прогонов, без Xdebug).
| Решение | Значение (мс) | 🏆 Победитель |
|---|---|---|
| parse_ini_string¹ | 213,9 | базовый уровень |
| 🏆 CloudCastle | 2 209,9 | лучший результат |
| m1 | 3 537,2 | аналог |
| josegonzalez | 4 544,5 | аналог |
| phpdevcommunity | 4 612,3 | аналог |
| symfony | 7 151,9 | аналог |
| vlucas | 10 638,3 | аналог |
¹ Базовый уровень — нативные средства PHP без полноты решения; показан для контекста и не участвует в определении победителя среди библиотек.
5. Производительность: чтение переменной окружения
Загрузка файла окружения и чтение 12 значений, 10 000 раз (минимум из 4 прогонов).
| Решение | Значение (мс) | 🏆 Победитель |
|---|---|---|
| parse_ini_string¹ | 77,2 | базовый уровень |
| 🏆 CloudCastle | 236 | лучший результат |
| m1 | 344,9 | аналог |
| symfony | 384,4 | аналог |
| josegonzalez | 457,3 | аналог |
| phpdevcommunity | 458,2 | аналог |
| vlucas | 1 062,3 | аналог |
¹ Базовый уровень — нативные средства PHP без полноты решения; показан для контекста и не участвует в определении победителя среди библиотек.
6. Память: одна загрузка конфигурации
Память одной загрузки 12 переменных (изолированный процесс, только целевая библиотека).
| Решение | Значение (байт) | 🏆 Победитель |
|---|---|---|
| 🏆 phpdevcommunity | 792 | лучший результат |
| CloudCastle | 1 568 | аналог |
| symfony | 1 568 | аналог |
| vlucas | 1 568 | аналог |
| parse_ini_string¹ | 1 568 | базовый уровень |
| josegonzalez | 2 488 | аналог |
| m1 | 3 096 | аналог |
¹ Базовый уровень — нативные средства PHP без полноты решения; показан для контекста и не участвует в определении победителя среди библиотек.
7. Память: десять тысяч независимых наборов (синтетический предел)
Память 10 000 удерживаемых независимых наборов переменных (изолированный процесс, содержимое уникально на каждой итерации).
| Решение | Значение (КБ) | 🏆 Победитель |
|---|---|---|
| 🏆 phpdevcommunity | 10 828 | лучший результат |
| josegonzalez | 14 326 | аналог |
| CloudCastle | 15 829 | аналог |
| symfony | 15 829 | аналог |
| vlucas | 15 829 | аналог |
| parse_ini_string¹ | 15 829 | базовый уровень |
| m1 | 20 329 | аналог |
¹ Базовый уровень — нативные средства PHP без полноты решения; показан для контекста и не участвует в определении победителя среди библиотек.
8. Утечки памяти
Рост памяти за 20 циклов по 5 000 разборов (изолированный процесс, после сборки мусора).
| Решение | Значение (КБ) | 🏆 Победитель |
|---|---|---|
| 🏆 CloudCastle | 0 | лучший результат |
| 🏆 symfony | 0 | лучший результат |
| 🏆 vlucas | 0 | лучший результат |
| 🏆 phpdevcommunity | 0 | лучший результат |
| parse_ini_string¹ | 0 | базовый уровень |
| josegonzalez | 120 | аналог |
| m1 | 120 | аналог |
¹ Базовый уровень — нативные средства PHP без полноты решения; показан для контекста и не участвует в определении победителя среди библиотек.
Коротко о плюсах и минусах
Сильные стороны:
- Функционал — объединение возможностей аналогов. Разбор, интерполяция с модификаторами, каскад окружений, кэш, типизированное чтение, схема, фильтры, маскирование, шифрование и консоль — в одном пакете; по таблице возможностей пакет покрывает всё, что умеют пять сравниваемых аналогов вместе взятые.
- Скорость. Быстрее всех сравниваемых библиотек и на разборе файла, и на полном цикле «загрузить и прочитать»: разбор идёт одним проходом по строке, без промежуточных объектов на каждое значение.
- Безопасность. Содержимое файла не выполняет код (в отличие от
symfony/dotenv, где подстановка команд включена всегда), иммутабельность по умолчанию, белый список изменяемых переменных, проверка кодировки, маскирование секретов, шифрование файла и права0600на всё, что пакет создаёт. - Качество кода. PHPStan max, Psalm errorLevel 1, PHPMD, PHPCS, Rector и Deptrac — без замечаний; покрытие тестами 100%, мутационный MSI 100% (все мутанты убиты).
- Без утечек памяти. Повторные разборы не наращивают память (подтверждено сравнительным тестом утечек), состояние между вызовами не накапливается.
- Без внешних пакетов. Только PHP 8.1+ и штатный
ext-openssl: поверхность атаки и вес вендора минимальны.
Слабые стороны (честно):
- Память на синтетическом сценарии. При удержании десяти тысяч независимых
наборов пакет расходует столько же, сколько
symfony/dotenv,vlucas/phpdotenvи нативныйparse_ini_string, но больше, чемphpdevcommunity/dotenvиjosegonzalez/dotenv: те приводят значения к скалярам (числа, пустые строки), а пакет сохраняет исходные строковые значения — иначеgetString()возвращал бы не то, что написано в файле. На реальном приложении с единственной загрузкой окружения разница неощутима (1568 байт против 792 у самого экономного). - Возраст и распространённость. Пакет моложе
vlucas/phpdotenvиsymfony/dotenv, у него меньше звёзд и установок, а значит — меньше готовых рецептов в интернете и меньше сторонних интеграций.
Когда применять
- Приложение с несколькими окружениями — основной сценарий: каскад
.env, профиль окружения, проверка по схеме на старте и компиляция кэша на деплое. - Сервисы, где конфигурация попадает в логи и тикеты (финтех, обработка персональных данных) — маскирование секретов в дампах и исключения без значений.
- Конфигурация рядом с кодом, но без раскрытия значений — зашифрованный
.env.vaultв репозитории и ключ из секрет-хранилища. - Строгие требования к старту — схема как контракт: приложение не поднимется с
неполным или некорректным окружением, а
.env.exampleгенерируется из того же описания и не отстаёт от кода. - Долгоживущие процессы (RoadRunner, Swoole, воркеры очередей) — иммутабельное хранилище исключает случайную мутацию общего окружения.
- Если нужен только разбор
.envв массив и ничего больше — подойдёт иm1/env: он меньше по объёму кода, хотя и медленнее. - Проект на Symfony, где уже подключён
symfony/dotenv— там загрузка окружения встроена в каркас; этот пакет полезен как самостоятельный слой вне фреймворка или когда нужны схема, шифрование и маскирование.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
composer test:mutation # мутационное тестирование (MSI 100%)
composer docs:sync # пересборка сравнительных таблиц, wiki и бейджей
Полный список команд с описаниями: composer run-script --list.
Документация
- Возможности по страницам: wiki/docs/ru/Features.md
- Сравнение с аналогами: wiki/docs/ru/Comparison.md
- Справочник API и руководство: https://cloud-castle.gitverse.page/env/
- Wiki проекта: https://gitverse.ru/cloud-castle/env/wiki
- Репозиторий: https://gitverse.ru/cloud-castle/env
- История изменений: CHANGELOG.md
- Обновление версий: UPGRADING.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Политика безопасности: SECURITY.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano