Dependency Injection Container eli DI-container tekee WordPress-pluginista huomattavasti modulaarisemman, testattavamman ja helpommin ylläpidettävän. Vaikka WordPress perustuu pitkälti globaaleihin funktioihin ja hookeihin, moderni plugin-kehitys hyötyy selkeästä service-rakenteesta ja dependency injection -mallista.
Ilman DI-containeria pluginit muuttuvat helposti:
- vaikeasti testattaviksi
- tiukasti kytketyiksi
- sekaviksi singleton-rakenteiksi
- hankaliksi laajentaa
Hyvin rakennettu container taas mahdollistaa:
- service registrationin
- automaattisen dependency resolutionin
- lazy loadingin
- paremman arkkitehtuurin
Mitä dependency injection tarkoittaa
Huono tapa:
class OrderService {
public function create() {
$mailer = new Mailer();
}
}Ongelma:
- luokka luo omat riippuvuutensa
- vaikea testata
- vaikea vaihtaa implementaatiota
Parempi:
class OrderService {
public function __construct(Mailer $mailer) {
$this->mailer = $mailer;
}
}Nyt riippuvuus injektoidaan ulkopuolelta.
Mikä DI-container tekee
Container hallitsee servicejä:
Container
├── Mailer
├── Logger
├── API Client
└── OrderServiceContainer:
- luo objektit
- ratkaisee riippuvuudet
- hallitsee lifecycleä
Miksi DI-container kannattaa WordPressissä
WordPressissä ongelmat usein johtuvat:
- globaalista tilasta
- singleton-spagetista
- hookien hajautumisesta
DI-container auttaa rakentamaan:
- modulaarisen pluginin
- service-pohjaisen arkkitehtuurin
- testattavan koodin
1. Yksinkertainen custom container
Perusmalli:
class Container {
protected $services = [];
public function set($key, $resolver) {
$this->services[$key] = $resolver;
}
public function get($key) {
return $this->services[$key]($this);
}
}2. Service registration
$container->set('mailer', function() {
return new Mailer();
});3. Dependency resolution
$container->set('order_service', function($c) {
return new OrderService(
$c->get('mailer')
);
});4. Plugin bootstrap
Tyypillinen rakenne:
plugin.php
src/
services/
container/Bootstrap:
$container = new Container();
require 'services.php';
$app = $container->get('app');
$app->boot();5. Hook registration serviceinä
Huono:
add_action(...);
add_action(...);
add_action(...);ripoteltuna kaikkialle.
Parempi:
class UserHooks {
public function register() {
add_action('init', [$this, 'boot']);
}
}6. Hook service containerissa
$container->set('user_hooks', function() {
return new UserHooks();
});Bootissa:
$container->get('user_hooks')->register();7. Lazy loading
Container voi luoda servicet vasta tarvittaessa.
Hyöty:
- pienempi memory footprint
- nopeampi bootstrap
8. Singleton vs shared services
Moni container tukee shared servicejä:
$container->singleton('logger', function() {
return new Logger();
});Tällöin sama instanssi palautetaan aina.
9. Interface-pohjainen arkkitehtuuri
Paras käytäntö:
interface MailerInterface {}Implementaatio:
class SMTPMailer implements MailerInterface {}Container:
$container->set(
MailerInterface::class,
fn() => new SMTPMailer()
);10. Testattavuus
DI tekee mockauksen helpoksi:
$mailer = $this->createMock(MailerInterface::class);Ilman dependency injectionia tämä on vaikeaa.
11. Autowiring
Modernit containerit tukevat reflection-pohjaista autowiringia.
Esimerkkejä:
- PHP-DI
- Symfony Container
- Laravel Container
$container->get(OrderService::class);Container ratkaisee dependencyt automaattisesti.
12. WordPress + PHP-DI
Suosittu ratkaisu:
composer require php-di/php-diKäyttö:
$container = new \DI\Container();13. Service provider -malli
Hyvä rakenne isoihin plugineihin:
AuthServiceProvider
APIServiceProvider
AdminServiceProviderJokainen rekisteröi omat servicensä.
14. Configuration injection
Älä käytä:
get_option() kaikkiallaParempi:
new APIClient($config);15. Event-driven plugin architecture
DI-container toimii hyvin yhdessä event-driven mallin kanssa:
Event Dispatcher
↓
Subscribers
↓
Services16. Anti-patternit
Huonoja käytäntöjä:
- globaali
$containerkaikkialla - service locator abuse
- liian monimutkainen container pienessä pluginissa
- singleton-spagetti
- WordPress-funktiot business logicassa
17. Performance huomioitavaa
Liian raskas container voi hidastaa bootstrapia.
Optimoi:
- lazy loading
- cached definitions
- ei reflectionia productionissa tarvittaessa
18. Paras plugin-rakenne
Moderni WordPress-plugin:
src/
├── Application
├── Services
├── Infrastructure
├── Hooks
├── API
├── Domain
└── Container19. Milloin DI-container kannattaa
Hyvä idea kun:
- plugin kasvaa suureksi
- useita servicejä
- paljon integraatioita
- testattavuus tärkeää
- useita kehittäjiä
Ei välttämättä tarpeen:
- pienissä utility plugineissa
Yhteenveto
Dependency injection container tuo WordPress-plugin-kehitykseen modernin sovellusarkkitehtuurin. Sen avulla pluginit voidaan rakentaa modulaarisesti, testattavasti ja ilman globaalia spagettia.
Kun servicet, hookit ja integraatiot erotetaan selkeiksi dependencyiksi, WordPress-pluginista tulee huomattavasti helpompi ylläpitää ja skaalata pitkällä aikavälillä.