idrinth / quickly
A fast dependency injection container featuring build time resolution.
Requires
- php: ^8.4
- psr/container: ^2.0.2
Requires (Dev)
- phpunit/phpunit: ^12.3.7
This package is auto-updated.
Last update: 2025-09-07 20:52:40 UTC
README
A fast dependency injection container for PHP featuring build-time resolution and PSR-11 compliance.
Features
- β PSR-11 Compliant - Fully compatible with PSR-11 Container Interface
- β‘ Build-time Resolution - Pre-compile dependency graphs for maximum performance
- π§ Autowiring - Automatic dependency resolution using reflection
- π Environment Injection - Direct injection of environment variables
- π Factory Pattern Support - Flexible object creation with custom factories
- π€ Lazy Initialization - Defer object creation until needed
- π Circular Dependency Detection - Prevents infinite dependency loops
- π Validation Tools - Command-line tools for configuration validation
- π Expandable -a fallback container to the container handles cases not covered by it
Requirements
- PHP 8.4 or higher
- PSR Container 2.0.2+
Installation
composer require idrinth/quickly
Quick Start
Basic Usage
use Idrinth\Quickly\EnvironmentFactory; // Create container factory $factory = new EnvironmentFactory(); $container = $factory->createContainer(); // Get services $myService = $container->get(MyService::class);
With Reflection (Development Mode)
Set the DI_USE_REFLECTION=true
environment variable to enable automatic dependency resolution:
// Your environment $_ENV['DI_USE_REFLECTION'] = 'true'; // Container will automatically resolve dependencies $container = $factory->createContainer(); $service = $container->get(SomeService::class);
Dependency Injection Attributes
Environment Variable Injection
use Idrinth\Quickly\DependencyInjection\EnvironmentInject; class DatabaseService { public function __construct( #[EnvironmentInject('DATABASE_URL')] private string $databaseUrl, #[EnvironmentInject('DB_TIMEOUT')] private int $timeout = 30 ) {} }
Factory-based Resolution
use Idrinth\Quickly\DependencyInjection\ResolveWithFactory; use Idrinth\Quickly\DependencyInjection\Factory; class MyFactory implements Factory { public function pickImplementation(string $parameter, string $key, string $forClass): string { return ConcreteImplementation::class; } } class ServiceConsumer { public function __construct( #[ResolveWithFactory(MyFactory::class, 'implementation-key')] private SomeInterface $service ) {} }
Lazy Initialization
use Idrinth\Quickly\DependencyInjection\LazyInitialization; #[LazyInitialization] class ExpensiveService { }
Command Line Tools
Quickly provides several CLI commands accessible via vendor/bin/quickly
:
Build Configuration (Functional)
vendor/bin/quickly build [filepath]
Creates an optimized production configuration file for maximum performance.
Validate Configuration (WIP)
vendor/bin/quickly validate [filepath]
Validates your dependency injection configuration for errors.
Help
vendor/bin/quickly help
Shows available commands and usage information.
Configuration
Manual Configuration
use Idrinth\Quickly\DependencyInjection\Container; use Idrinth\Quickly\DependencyInjection\Definitions\ClassObject; use Idrinth\Quickly\DependencyInjection\Definitions\Environment; $container = new Container( environments: $_ENV, constructors: [ MyService::class => [ new ClassObject(Dependency::class), new Environment('CONFIG_VALUE') ] ], classAliases: [ 'MyInterface' => 'ConcreteImplementation' ] );
Generated Configuration
For production use, generate optimized configuration:
// .quickly/generated.php (example) return [ 'constructors' => [ // Pre-resolved constructor dependencies ], 'factories' => [ // Factory mappings ], 'classAliases' => [ // Interface to implementation mappings ] ];
Compiled Configuration
About twice as fast as even the generated configuration, this is your best option in most cases.
Have a look at .quickly/entrypoints.php for configuring entry points without having to add any Attributes.
<?php namespace Idrinth\Quickly\Built\DependendyInjection; use Exception; use Idrinth\Quickly\DependencyInjection\FallbackFailed; use Psr\Container\ContainerInterface; final class Container implements ContainerInterface { private readonly array $defined; private readonly array $environments; private array $built = []; public function __construct(array $environments, private readonly ContainerInterface $fallbackContainer) { foreach (array ( ) as $variableName => $environment) { if (isset($environments[$environment])) { $this->environments["Environment:$variableName"] = $environments[$environment]; } } $this->defined = [ 'Idrinth\Quickly\CommandLineOutput'=>true, 'Idrinth\Quickly\CommandLineOutputs\Colorless'=>true, 'Idrinth\Quickly\Commands\Build'=>true, 'Idrinth\Quickly\Commands\Help'=>true, 'Idrinth\Quickly\Commands\Validate'=>true, ]; } public function get(string $id): string|object { if (isset($this->built[$id])) { return $this->built[$id]; } return $this->built[$id] = match ($id) { 'Idrinth\Quickly\CommandLineOutput'=>$this->get('Idrinth\Quickly\CommandLineOutputs\Colorless'), 'Idrinth\Quickly\CommandLineOutputs\Colorless'=>new \Idrinth\Quickly\CommandLineOutputs\Colorless(), 'Idrinth\Quickly\Commands\Build'=>new \Idrinth\Quickly\Commands\Build($this->get('Idrinth\Quickly\CommandLineOutputs\Colorless')), 'Idrinth\Quickly\Commands\Help'=>new \Idrinth\Quickly\Commands\Help($this->get('Idrinth\Quickly\CommandLineOutputs\Colorless')), 'Idrinth\Quickly\Commands\Validate'=>new \Idrinth\Quickly\Commands\Validate($this->get('Idrinth\Quickly\CommandLineOutputs\Colorless')), default => $this->fallBackOn($id), }; } private function fallBackOn(string $id): object { try { return $this->fallbackContainer->get($id); } catch (Exception $e) { throw new FallbackFailed("Couldn't fall back on {$id}", previous: $e); } } public function has(string $id): bool { return isset($this->defined[$id]) || isset($this->environments[$id]) || $this->fallbackContainer->has($id); } }
Environment Variable Mapping
Environment variables are automatically converted to camelCase for injection:
DATABASE_URL
βdatabaseUrl
API_KEY
βapiKey
REDIS_HOST
βredisHost
Error Handling
Quickly provides comprehensive exception handling with PSR-11 compliant exceptions for different error scenarios. All exceptions implement either Psr\Container\ContainerExceptionInterface
or Psr\Container\NotFoundExceptionInterface
.
Configuration & Setup Errors
-
InvalidClassName
- Invalid or empty class name provided in configuration- Extends:
InvalidArgumentException
- Implements:
Psr\Container\ContainerExceptionInterface
- Extends:
-
InvalidDependency
- Invalid dependency definition in constructor arguments- Extends:
InvalidArgumentException
- Implements:
Psr\Container\ContainerExceptionInterface
- Extends:
-
DependencyTypeUnknown
- Unknown dependency definition type encountered- Extends:
InvalidArgumentException
- Implements:
Psr\Container\ContainerExceptionInterface
- Extends:
Resolution & Runtime Errors
-
DependencyNotFound
- Service not registered in container- Extends:
OutOfBoundsException
- Implements:
Psr\Container\NotFoundExceptionInterface
- Extends:
-
DependencyUnbuildable
- Cannot construct service due to runtime issues- Extends:
UnexpectedValueException
- Implements:
Psr\Container\ContainerExceptionInterface
- Extends:
-
CircularDependency
- Circular dependency detected during resolution- Extends:
DependencyUnbuildable
- Implements:
Psr\Container\ContainerExceptionInterface
(inherited)
- Extends:
-
FallbackFailed
- Fallback container failed to provide dependency- Extends:
DependencyUnbuildable
- Implements:
Psr\Container\ContainerExceptionInterface
(inherited)
- Extends:
Build-time Errors
DependencyUnresolvable
- Dependency cannot be resolved at build time- Extends:
DependencyUnbuildable
- Implements:
Psr\Container\ContainerExceptionInterface
(inherited)
- Extends:
Factory-specific Errors
NoImplementationFound
- Factory cannot resolve implementation for given parameters- Extends:
UnexpectedValueException
- Implements:
Psr\Container\NotFoundExceptionInterface
- Extends:
Exception Hierarchy
InvalidArgumentException
βββ InvalidClassName
βββ InvalidDependency
βββ DependencyTypeUnknown
OutOfBoundsException
βββ DependencyNotFound
UnexpectedValueException
βββ DependencyUnbuildable
β βββ CircularDependency
β βββ DependencyUnresolvable
β βββ FallbackFailed
βββ NoImplementationFound
All exceptions are PSR-11 compliant and provide detailed error messages to help with debugging dependency injection issues.
Advanced Features
Circular Dependency Detection
// This will throw CircularDependency exception class ServiceA { public function __construct(ServiceB $serviceB) {} } class ServiceB { public function __construct(ServiceA $serviceA) {} }
Singleton Behavior
All services are automatically singletons - the same instance is returned for subsequent requests:
$service1 = $container->get(MyService::class); $service2 = $container->get(MyService::class); // $service1 === $service2
Testing
Run the test suite:
composer test
Or with PHPUnit directly:
vendor/bin/phpunit
Benchmarks
Idrinth/php-dependency-injection-benchmark contains up to date benchmarks with comparisons to competitors.
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
BjΓΆrn 'Idrinth' BΓΌttner
Built with β€οΈ for high-performance PHP applications.