Вступ
Типовий PHP-проєкт швидко перетворюється на «все в одному»: валідація, сесії, БД і HTML злипаються з роутером, і вимкнути непотрібне вже важко. Concept 2 для PHP 8.4+ побудований інакше — на PSR (HTTP, Container, Logging, …) і трьох шарах, які можна збирати поштучно:
- Core — лише контейнер, маршрутизація й dispatch: щоб HTTP-цикл існував без фреймворк-магії
- Extensions — окремі composer-пакети (валідація, view, БД, …): підключаєш, коли з’явився біль, а не «на всяк випадок»
- Stack — fluent API, який збирає обрані Extensions у providers: явний рецепт збірки замість прихованого global bootstrap
Додаток у Bootstrap обирає лише потрібні capabilities, передає їм явні параметри і реєструє результат у контейнері. Нічого не «вмикається само» через глобальний config: якщо capability немає в Stack — її сервісів немає в контейнері. Core лишається тонким; доменна логіка живе в Extensions.
Concept 2
Strict-typed PHP 8.4+, PSR-standardsproviders() ↑
Вперше з Concept 2?
Почніть з Огляду рецептів — покрокові рецепти Stack, починаючи з Перший HTTP-запит.
Що це не є
Concept 2 — не CMS і не framework, який нав’язує повний стек незалежно від задачі. Немає єдиного «увімкнути все»: ви явно збираєте Stack з потрібних Extensions.
Також Concept 2 — не «магія конфігів усередині пакетів». Extensions не читають глобальний config; значення (шляхи, flags, connection arrays) передає той код, який збирає Stack — зазвичай glue додатку.
Core · Extensions · Stack
Три шари мають чіткі межі відповідальності. Core забезпечує спільний runtime;
Extensions додають можливості; Stack — зручний спосіб скласти їх докупи без
ручного переліку десятків new XxxServiceProvider(...).
| Шар | Пакет | Роль |
|---|---|---|
| Core | php-concept/core-2 |
App, HttpKernel, RouteStrategy, базові argument resolvers |
| Extensions | php-concept/extension-* |
Http, Validation, Database, Session, View, Logger, … |
| Stack | php-concept/stack |
Fluent ConceptStack + bricks → list of providers |
Core
Пакет php-concept/core-2 — точка входу runtime. Типові частини:
App— створює League Container (з ReflectionContainer delegate) і запускає HTTP-обробкуHttpKernelServiceProvider— реєструє PSR-7ServerRequest, Router і завантаження route-файлівRouteStrategy— викликає handler маршруту: interceptors, підготовка request, resolve аргументів, invoke- Базові resolvers —
ServerRequestArgumentResolverіRouteParameterArgumentResolver - Контракти розширення —
ArgumentResolverInterface,RouteInterceptorInterface
Core не залежить від Extensions і не читає config. Порядок argument resolvers і список interceptors йому передають ззовні (через Stack / glue) — ядро лише виконує ланцюжок.
Extensions
Кожне розширення — окремий composer-пакет php-concept/extension-{name}.
У корені src/ — один entry point {Name}ServiceProvider;
публічні інтерфейси — у src/Contracts/; реалізації — у feature-директоріях.
Правила wiring:
- Конфігурація — через constructor params provider-а (шляхи, flags, масиви, optional factories)
- Extension не читає
ConfigInterfaceвсередині своїх класів - Сервіси extension отримують залежності через конструктор, а не через service locator на «чужі» типи
- Допускається
$container->get()лише власних контрактів або стабільних core/PSR типів у wiring provider-а
Приклади: Http (ResponseFactory, UrlGenerator), Validation + FormRequest, Casting, Session/CSRF, Database, View/Twig, Logger, DataMasker, Console. Детальні сторінки — у розділі «Розширення».
Stack
Пакет php-concept/stack дає fluent API ConceptStack.
Виклики на кшталт addHttp(), addView(),
addDatabase(), addLogging() одразу реєструють capability
(окремий end() не потрібен). Після збірки
$stack->providers() повертає упорядкований список ServiceProvider
для реєстрації в контейнері.
Stack — тонкий шар над Extensions: він знає, які providers і з якими параметрами створити, але сам config не читає. Усі значення (debug, шляхи до view, connection array, log file) передає викликаючий код як explicit arguments на brick-методи.
Окремі гілки можна тримати від кореня $stack
(наприклад, database + query logging), не змішуючи контекст fluent-ланцюжка.