Search by

vampyrian / container

Vampyrian

Package info

github.com/Vampyrian/container

Language:Shell

pkg:composer/vampyrian/container

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-09-29 17:31 UTC

This package is auto-updated.

Last update: 2026-09-29 17:42:53 UTC


README

A small dependency injection container for PHP with autowiring and singleton support. For learning purposes only.

Installation

composer require vampyrian/container

Getting the container

The container is a process-wide singleton. Get it either through the container() helper or directly from the class:

use Vampyrian\Container\Container\GenericContainer;
use function Vampyrian\Container\Container\container;

$container = container();
// or
$container = GenericContainer::getInstance();

Both return the same instance, so anything you register is visible everywhere in the process.

Autowiring

Classes don't have to be registered. When you ask for a class the container doesn't know about, it inspects the constructor and resolves each class-typed parameter recursively:

class Logger {}

class UserService
{
    public function __construct(public Logger $logger) {}
}

$service = container()->get(UserService::class);
// $service->logger is a Logger created by the container

Autowiring only works for constructor parameters typed with a class or interface that the container can itself resolve. Scalar parameters (string $dsn, int $port), untyped parameters and interfaces need an explicit registration.

Registering a factory

Use register() to tell the container how to build a class. The callback runs on every get() call, so each call returns a new instance:

container()->register(Mailer::class, fn () => new Mailer('smtp.example.com', 587));

$a = container()->get(Mailer::class);
$b = container()->get(Mailer::class);
// $a !== $b

This is also how you bind an interface to an implementation:

container()->register(CacheInterface::class, fn () => new RedisCache());

Registering a singleton

Use singleton() when the class should be created once and shared. The callback runs on the first get(), and later calls return the same instance:

container()->singleton(Database::class, fn () => new Database('mysql:host=localhost'));

$a = container()->get(Database::class);
$b = container()->get(Database::class);
// $a === $b

Resolving dependencies inside a callback

Callbacks receive the container as their argument, so you can resolve other services while building one:

use Vampyrian\Container\Interfaces\ContainerInterface;

container()->singleton(UserRepository::class, fn (ContainerInterface $c) => new UserRepository(
    $c->get(Database::class),
));

The argument is optional; callbacks that don't need it can omit it.

Chaining

register() and singleton() return the container, so calls can be chained:

container()
    ->singleton(Database::class, fn () => new Database('mysql:host=localhost'))
    ->register(Mailer::class, fn () => new Mailer('smtp.example.com', 587));

Running the tests

composer test

License

Released under the MIT License.