Конфигурация
Каталога config/ в Winter нет. Значения живут в .env,
состав приложения — атрибутами на классе-точке входа, а всё остальное описывается
обычными классами, которые находит сканер. Регистрировать их нигде не нужно.
Три уровня
Настройка разнесена по трём местам, и деление между ними простое.
| Где | Что там | Пример |
|---|---|---|
.env |
Значения, меняющиеся от окружения к окружению | адрес базы, уровень логов |
| Класс приложения | Из чего состоит приложение | #[EnableWeb], #[EnableScheduler] |
| Классы-конфигураторы | Поведение, выраженное кодом | CORS, параметры сервера, бины |
Почему нет конфиг-файлов. То, что является значением, живёт в окружении и меняется без пересборки. То, что является решением — какую реализацию подставить, как собрать объект, какие источники разрешить, — выражается кодом, где работают типы и подсказки редактора. Промежуточного слоя из массивов в PHP-файлах здесь нет намеренно.
.env — значения
Файл создаётся из шаблона командой php call cfg init и содержит три строки:
WINTER_KEY=<сгенерированный ключ>
TIME_ZONE=UTC
DEBUG=true| Переменная | По умолчанию | Что задаёт |
|---|---|---|
WINTER_KEY |
— | Секрет проекта: подписи, токены. Генерируется на месте |
TIME_ZONE |
UTC |
Часовой пояс по умолчанию |
DEBUG |
false |
Режим разработки |
Что именно меняет `DEBUG`
Это не только «показывать ошибки». Переменная переключает четыре вещи:
- отображение ошибок — при
falsePHP их прячет, и упавший скрипт молчит; - тело ответа при ошибке — стектрейс и отладочные данные уходят клиенту только
при
true; - кеш списка классов — при
falseпроект сканируется один раз и результат ложится вdi.php; приtrueкеш не используется вовсе; - прокси
#[Async]— приtrueперегенерируются, если исходник изменился.
В проде — только false. При true наружу утекают внутренности приложения.
Логирование
| Переменная | По умолчанию | Что задаёт |
|---|---|---|
LOG_LEVEL |
не задан — вывод выключен | Минимальный уровень записи |
LOG_OUTPUT |
auto |
auto, stdout, stderr, file, syslog, null |
LOG_FORMAT |
line |
line или json |
LOG_FILE |
storage/log/<канал>.log |
Путь при LOG_OUTPUT=file |
LOG_FILE_MAX |
30 |
Сколько файлов хранить при ротации |
LOG_COLOR |
auto |
auto, always, never |
Любую из них можно задать отдельно для канала — префиксом LOG_{КАНАЛ}_:
LOG_LEVEL=info
LOG_HTTP_LEVEL=warning # от запросов — только проблемы
LOG_SYS_OUTPUT=file # системные события в файлПодробнее — на странице Логирование.
Веб-сервер
Действуют, только когда приложение объявляет #[EnableWeb].
| Переменная | Что задаёт |
|---|---|
SERVER_PROFILE |
Профиль памяти: stable, balance, performance, stress |
SERVER_WORKERS |
Число процессов-обработчиков |
SERVER_TASKS |
Число процессов под фоновые задачи Swoole |
SERVER_MAX_CONCURRENCY |
Одновременных запросов на воркер |
SERVER_MAX_CONNECTIONS |
Одновременных соединений |
SERVER_MAX_REQUEST |
Запросов до замены воркера |
SERVER_MAX_REQUEST_GRACE |
Разброс, чтобы воркеры не перезапускались разом |
SERVER_MAX_REQUEST_SIZE |
Наибольший размер запроса в байтах |
SERVER_REQUEST_TIMEOUT |
Дедлайн запроса в секундах |
SERVER_IDLE_TIMEOUT |
Через сколько закрыть молчащее соединение |
SERVER_MEMORY_LIMIT |
Лимит памяти каждого воркера |
SERVER_MEMORY_TRIM |
Когда возвращать неиспользуемую память системе |
Что означает каждая и как они связаны между собой — на странице
Настройка веб-слоя. Адрес и порт переменными не задаются: они
приходят флагами --host и --port.
Прочее
| Переменная | Что задаёт |
|---|---|
WINTER_BANNER |
off убирает баннер при запуске |
PPA_POOL_TELEMETRY |
Интервал публикации статистики пула соединений; 0 выключает |
Переменные базы данных объявляете вы
Ядро не читает DB_HOST и подобные — за подключение отвечает ваш класс
конфигурации, и какие переменные он спросит, решаете вы. Принято брать их через
env(), см. раздел База данных.
Манифест приложения
Из чего состоит приложение — объявляется атрибутами на классе-точке входа:
#[EnableWeb]
#[EnableScheduler]
#[EnableProcess(\Main\Process\QueueWorker::class)]
final class Application extends WinterApplication
{
public static function main(array $argv): never
{
parent::run($argv);
}
}Все доступные атрибуты и их сочетания — на странице Состав приложения.
Единственный хук — configure()
Он нужен, только если раскладка проекта нестандартная: этот метод выполняется до скана и решает, где сканеру искать.
use Flytachi\Winter\Kernel\App\ApplicationArguments;
use Flytachi\Winter\Kernel\Kernel;
protected static function configure(ApplicationArguments $args): void
{
Kernel::init(
pathRoot: __DIR__,
pathResource: __DIR__ . '/assets',
pathStorage: '/var/lib/my-app',
);
}Без переопределения пути выводятся из расположения класса приложения, и для обычной раскладки трогать его не нужно.
Классы-конфигураторы
Всё остальное описывается обычными классами. Их не нужно нигде регистрировать — сканер находит их сам, по реализованному интерфейсу или по атрибуту.
| Что настроить | Чем |
|---|---|
Привязки контейнера, фабрики, значения из .env |
#[Configuration] с методами #[Bean] |
| CORS и параметры веб-сервера | Класс, наследующий WebConfigurerAdapter |
| Дополнительные каналы логов | Класс, реализующий LoggingConfigurer |
| Подключение плагинов | Атрибут #[Import] на классе приложения |
| Диагностические эндпоинты | Атрибут #[EnableActuator] |
#[Configuration]
final class AppConfig
{
#[Bean]
public function cache(#[Value('REDIS_URL')] string $url): CacheInterface
{
return new RedisCache($url);
}
}Каждый из них разобран на своей странице: Внедрение зависимостей, Настройка веб-слоя, Логирование, Пакеты.
Порядок загрузки
Один и тот же для всех точек входа — и для сервера, и для консольной команды:
1. configure() — пути, .env, часовой пояс, логирование
2. Контейнер — создаётся пустым
3. Один обход проекта:
· классы с областью видимости → контейнер
· #[Configuration] / #[Bean] → фабрики
· WebConfigurer, LoggingConfigurer → собираются
· граф областей видимости → проверка
4. Проверка конфликтов #[Singleton] ↔ #[Request]
5. Применение найденного: логи, CORS, плагины, актуатор
6. Дальше — либо сервер, либо консольная командаОбход проекта один, а не по разу на каждый вид конфигурации. Отсюда два следствия:
- порядок объявления классов-конфигураторов не важен — они собираются за один проход и применяются после него;
- новый конфигуратор подхватывается перезапуском, как и всё остальное.
Конфликт областей ловится здесь
Шаг 4 обходит граф зависимостей и отказывается поднимать приложение, если
#[Singleton] держит внутри #[Request]-объект: иначе данные первого запроса
замёрзли бы в нём на всё время жизни воркера. В логе будет цепочка A → $prop: B.
Обслуживание ключа
php call cfg key -g # сгенерировать новый
php call cfg key -s # показать текущий
php call cfg env -s # показать все переменные окруженияДальше
- Состав приложения — что объявляют атрибуты
#[Enable*] - Внедрение зависимостей —
#[Configuration]и#[Bean] - Настройка веб-слоя — CORS и параметры сервера
- Структура проекта — где что лежит