Dependency Injection - Wstrzykiwanie zależności
Dokumentacja jest stale rozwijana i aktualizowana wraz z postępem projektu. Ponieważ powstaje ona równolegle z kodem, niektóre sekcje mogą tymczasowo odnosić się do wcześniejszych wersji systemu - są one sukcesywnie dostosowywane do bieżącego stanu aplikacji. Jeśli zauważysz nieaktualne informacje, zgłoś to lub załóż Issue / Pull Request.
Dokumentacja
# Dependency Injection - Wstrzykiwanie zależności
# Przegląd
DbM Framework wykorzystuje lekki kontener wstrzykiwania zależności (DependencyContainer) do zarządzania usługami aplikacji.
Kontener umożliwia:
- Ręczną rejestrację usług
- Udostępnianie instancji za pomocą
singleton - Automatyczne rozwiązywanie zależności (autowiring)
- Organizowanie modułów za pośrednictwem dostawców usług
Plik konfiguracyjny usługi:
application/services.php
# Rejestracja usługi
Usługi są rejestrowane wewnątrz:
return function (DependencyContainer $container): void {
// tutaj usługi
};
# singleton() vs set()
# singleton (zalecane)
Tworzy współdzieloną instancję (jedną na cykl życia żądania):
$container->singleton(Logger::class, fn() => new Logger());
lub krócej:
$container->singleton(RouteCollection::class);
# set
Tworzy nową instancję za każdym razem (lub niestandardową logikę):
$container->set(DatabaseInterface::class, fn() =>
isConfigDatabase() ? DatabaseFactory::createDatabase() : null
);
# Przykładowa konfiguracja
$container->singleton(Request::class);
$container->singleton(SessionManager::class);
$container->singleton(CookieManager::class);
$container->singleton(
FlashBag::class,
fn($c) => new FlashBag($c->get(SessionManager::class))
);
# Rozwiązywanie zależności
# Wstrzykiwanie konstruktorów
Zależności są automatycznie wstrzykiwane do konstruktorów:
class IndexController
{
public function __construct(
private IndexService $service,
private FlashBag $flash
) {}
}
Nie jest wymagane ręczne $container->get().
# Przykład kontrolera
class IndexController extends BaseController
{
public function __construct(
private readonly IndexService $service,
private readonly FlashBag $flash
) {}
public function index(): ResponseInterface
{
$this->flash->set('Aplikacja jest gotowa');
return $this->render('index/start.phtml', [
'meta' => $this->service->getMetaIndex(),
]);
}
}
# Automatyczne łączenie
Kontener automatycznie rozwiązuje:
- Zależności konstruktora
- Argumenty akcji kontrolera
# Przykład
public function show(Request $request): ResponseInterface
Jeśli Request jest zarejestrowany → zostanie wstrzyknięty automatycznie.
# Dynamiczne Rozwiązywanie
Nadal możesz ręcznie rozwiązywać usługi:
$container->get(SomeService::class);
Jeśli klasa:
- istnieje
- ma rozwiązywalne zależności
zostanie utworzona automatycznie.
# Integracja z routingiem
Kontener DI jest głęboko zintegrowany z routingiem:
ControllerResolvertworzy kontroleryActionArgumentResolverwstrzykuje argumenty metodyRouterkoordynuje pełny cykl życia żądania
# Moduły (Dostawcy Usług)
Moduły mogą rejestrować własne usługi:
ModuleServiceProvider::register($container);
Umożliwia to modułową architekturę i izolację funkcji.
# Integracja szablonów
Usługi można udostępniać szablonom:
$view->setGlobal(
'headerNavigation',
fn() => $this->container
->get(NavigationUtility::class)
->getHeader($request->getUri()->getPath())
);
# Użycie w szablonie
{% $headerNavigation = $this->headerNavigation(); %}
{% if (is_array($headerNavigation)): %}
# Grupy usług podstawowych
# HTTP
RequestSessionManagerCookieManager
# Routing
RouterRouteCollectionRouteMatcherControllerResolverActionArgumentResolver
# Widok
TemplateEngineFlashBag
# Bezpieczeństwo
AccessGuardCsrfTokenManager
# Lokalizacja
LanguageServiceTłumaczenieTranslationLoader
# Infrastruktura
LoggerFileSystemPHPMailerSender
# Najlepsze praktyki
- Używaj
singleton()dla większości usług - Używaj
set()dla usług dynamicznych lub opcjonalnych - Preferuj wstrzykiwanie przez konstruktor zamiast ręcznego
get() - Utrzymuj usługi bezstanowe, gdy jest to możliwe
- Jawnie rejestruj ważne usługi (unikaj nadużywania automatycznego rozstrzygania)
# Kiedy używać set() zamiast singleton()
Używaj set(), gdy:
- Usługa może zwrócić
null - Usługa zależy od warunków środowiska wykonawczego
- Za każdym razem potrzebujesz nowej instancji
# Podsumowanie
Kontener DI DbM zapewnia:
- Wysoką wydajność (brak intensywnego skanowania odbiciowego)
- Pełną kontrolę nad tworzeniem usług
- Automatyczne rozstrzyganie zależności
- Przejrzystą architekturę z modułami
DI DbM to: nie Laravel, nie Symfony tylko lekki, kontrolowany container.
Łączy prostotę z elastycznością, dzięki czemu nadaje się zarówno do małych aplikacji, jak i złożonych systemów modułowych.