mykemeynell / reflection
Tiny PHP reflection implementation
Requires
- php: >=8.3
- psr/container: ^2.0
Requires (Dev)
- laravel/pint: ^1.30
- pestphp/pest: ^4.7|^5.1
This package is not auto-updated.
Last update: 2026-08-28 01:17:43 UTC
README
Reflector is a dependency injection container for PHP powered by auto-wiring and reflection.
It supports auto-wiring, contextual bindings, singletons, runtime parameter overrides, circular dependency detection, and PSR-11 compliance.
Features
- Auto-Wiring: Resolves class constructor dependencies automatically using reflection.
- PSR-11 Compliance: Implements
Psr\Container\ContainerInterface(getandhas). - Contextual Binding: Configure different implementations for specific classes using
when()->needs()->give(). - Singletons: Share instances across multiple resolutions.
- Parameter Overrides: Pass runtime parameters as associative arrays or named arguments.
- Circular Dependency Detection: Detects recursive dependency chains and throws descriptive exceptions.
- Helper Function: Global
app()helper for quick access and resolution.
Requirements
- PHP 8.3 or higher
psr/container ^2.0
Installation
composer require mykemeynell/reflection
Quick Start
use mykemeynell\Reflection\Application\Container; $container = new Container(); class Database {} class UserRepository { public function __construct(public Database $db) {} } $userRepository = $container->make(UserRepository::class);
Usage
Auto-Wiring
Classes with type-hinted constructor dependencies resolve without manual configuration:
class Logger {} class OrderService { public function __construct(public Logger $logger) {} } $service = $container->make(OrderService::class);
Default parameter values are used when no argument is supplied:
class HttpClient { public function __construct(public int $timeout = 30) {} } $client = $container->make(HttpClient::class); // $client->timeout === 30
Bindings
Interface to Implementation
$container->bind(MailerInterface::class, SmtpMailer::class); $mailer = $container->make(MailerInterface::class);
Closure Factory
$container->bind(MailerInterface::class, function (Container $app, array $params = []) { return new SmtpMailer($params['key'] ?? 'default'); }); $mailer = $container->make(MailerInterface::class, ['key' => 'custom-key']);
Singletons & Shared Instances
Register a singleton to return the same instance on subsequent resolutions:
$container->singleton(Database::class); $db1 = $container->make(Database::class); $db2 = $container->make(Database::class); // $db1 === $db2
Register an existing instance:
$config = new AppConfig(); $container->instance(AppConfig::class, $config);
Contextual Bindings
Inject different implementations based on the consumer class:
$container->when(DirectDispatcher::class) ->needs(TransportInterface::class) ->give(HttpTransport::class); $container->when(CustomerDispatcher::class, OutletDispatcher::class) ->needs(TransportInterface::class) ->give(QueueTransport::class);
give() also accepts a closure or a concrete instance:
$container->when(ReportGenerator::class) ->needs(StorageInterface::class) ->give(fn (Container $app) => new S3Storage('bucket-name'));
Parameter Overrides
Override constructor parameters during resolution:
class ApiService { public function __construct( public HttpClient $client, public string $apiKey, public int $timeout = 30 ) {} } $service = $container->make(ApiService::class, [ 'apiKey' => 'my-token', 'timeout' => 60, ]);
Circular Dependency Detection
Circular dependencies are detected automatically during resolution:
class ServiceA { public function __construct(public ServiceB $b) {} } class ServiceB { public function __construct(public ServiceA $a) {} } $container->make(ServiceA::class); // Throws ContainerException: Circular dependency detected while resolving [ServiceA]: ServiceA -> ServiceB -> ServiceA.
PSR-11 Compliance
Reflector implements Psr\Container\ContainerInterface:
use Psr\Container\ContainerInterface; function bootstrap(ContainerInterface $container): void { if ($container->has(Router::class)) { $router = $container->get(Router::class); } }
PSR-11 exception classes:
mykemeynell\Reflection\Exceptions\NotFoundException(implementsPsr\Container\NotFoundExceptionInterface)mykemeynell\Reflection\Exceptions\ContainerException(implementsPsr\Container\ContainerExceptionInterface)mykemeynell\Reflection\Exceptions\DependencyNotSpecifiedException(implementsPsr\Container\ContainerExceptionInterface)
Helper Function
Import the app helper function:
use function mykemeynell\Reflection\Helpers\app; // Retrieve container instance $container = app(); // Resolve service $mailer = app(MailerInterface::class); // Resolve with parameters $service = app(ApiService::class, apiKey: 'token', timeout: 45); // Resolve closure $result = app(fn (Container $app) => $app->make(Logger::class));
Testing
Run tests:
composer test
Check code style:
composer lint:check
Format code style:
composer lint
License
MIT License. See LICENSE for details.