mykemeynell/reflection

There is no license information available for the latest version (v2.0.0) of this package.

Tiny PHP reflection implementation

Maintainers

Package info

github.com/mykemeynell/Reflection

pkg:composer/mykemeynell/reflection

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v2.0.0 2026-08-27 15:40 UTC

This package is not auto-updated.

Last update: 2026-08-28 01:17:43 UTC


README

CI/CD (main) CI/CD (dev) PHP Version PSR-11 Compliant License

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 (get and has).
  • 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 (implements Psr\Container\NotFoundExceptionInterface)
  • mykemeynell\Reflection\Exceptions\ContainerException (implements Psr\Container\ContainerExceptionInterface)
  • mykemeynell\Reflection\Exceptions\DependencyNotSpecifiedException (implements Psr\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.

Author

Myke Meynell (hi@myke.codes)