scriptmancer / kiler
A lightweight, attribute-based dependency injection container for PHP
Requires
- php: ^8.1
- psr/container: ^2.0
Requires (Dev)
- pestphp/pest: ^2.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
README
Kiler is a lightweight, feature-rich dependency injection container for PHP applications. It provides a simple yet powerful way to manage dependencies and services in your application.
Features
- π Simple and intuitive API
- π Support for both dynamic and compiled containers
- π·οΈ Service registration with attributes
- π Interface-based dependency injection
- π·οΈ Service tagging and grouping
- π Singleton and factory services
- π¦ PSR-11 Compliance & Framework Compatibility
Kiler implements the PSR-11 Container Interface, making it compatible with any library or framework that supports PSR-11 containers. You can use Kiler as a drop-in DI container for custom projects or integrate it with popular frameworks (such as Laravel, Symfony, Slim, etc.) as long as they support PSR-11 or allow custom containers.
- Service Providers: Extend
AbstractServiceProvider
for modular service registration and boot logic. - Optional Priority & Dependencies: Providers can optionally override
getPriority()
andgetDependencies()
for advanced initialization order control. - No Framework Lock-in: Kiler does not require any framework-specific code, ensuring portability and reusability.
Installation
composer require scriptmancer/kiler
Quick Start
use Scriptmancer\Kiler\Container; use Scriptmancer\Kiler\Attributes\Service; // Define a service #[Service] class Database { public function __construct( private readonly string $dsn = 'mysql:host=localhost;dbname=test' ) {} } // Get container instance $container = Container::getInstance(); // Register service $container->register(Database::class); // Use service $db = $container->get(Database::class);
Service Registration
Using Attributes
use Scriptmancer\Kiler\Attributes\Service; #[Service( implements: DatabaseInterface::class, group: 'database', tags: ['storage', 'persistence'], singleton: true )] class Database implements DatabaseInterface { // ... }
Manual Registration
$container->register(Database::class, 'db'); $container->registerFactory('db.factory', fn() => new Database());
Interface Resolution
interface LoggerInterface { public function log(string $message): void; } #[Service(implements: LoggerInterface::class)] class FileLogger implements LoggerInterface { public function log(string $message): void { // ... } } // Resolve interface to implementation $logger = $container->get(LoggerInterface::class);
Service Groups and Tags
// Register service with group and tags $container->register(Database::class); // Get all services in a group $databaseServices = $container->getServicesByGroup('database'); // Get all services with a tag $storageServices = $container->getServicesByTag('storage');
Compiled Container
For production environments, Kiler provides a compiled container that improves performance:
use Scriptmancer\Kiler\Container; use Scriptmancer\Kiler\ContainerCompiler; // In development $container = Container::getInstance(); $container->register(Database::class); // Compile container $compiler = new ContainerCompiler('/path/to/cache', 'App\\Bootstrap'); $containerPath = $compiler->compile($container); // In production $container = new App\Bootstrap\Container(); $db = $container->get(Database::class);
Event System
Kiler integrates with event systems through the EventDispatcherInterface
:
use Scriptmancer\Kiler\Event\EventDispatcherInterface; $container->setEventDispatcher($eventDispatcher);
Available events:
container.service.registered
: Fired when a service is registeredcontainer.service.resolved
: Fired when a service is resolved
Service Providers
A service provider is a class responsible for registering related services in the container. You can create your own providers by extending the AbstractServiceProvider
class.
use Scriptmancer\Kiler\AbstractServiceProvider; use Scriptmancer\Kiler\Container; class MyServiceProvider extends AbstractServiceProvider { public function register(Container $container): void { // Register your services here } public function boot(Container $container): void { // Perform initialization after all services are registered } } $container->addServiceProvider(new DatabaseServiceProvider()); $container->registerProviders();
Best Practices
- Use attributes for service configuration
- Register services in service providers
- Use interface-based dependency injection
- Compile container for production
- Use groups and tags for service organization
- Keep services stateless when possible
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Credits
Kiler is part of the NazΔ±m Framework project.