Dependency Injection (Container)#

TL;DR

Create → Register → Resolve

use Infocyph\InterMix\DI\Container;

$c = Container::instance();             // ① create
$c->definitions()->bind('answer', 42);  // ② register
echo $c->get('answer');                 // ③ resolve  → 42

Why bother with a DI-Container?#

Manual wiring is fine—until the tenth place you instantiate the same class, or the day you must swap an implementation in production only. InterMix automates construction, honours interfaces, supports environment-specific overrides and gives you sugar for 1-liners.

15-second “Hello World” with constructor autowire#

class Greeter
{
    public function __construct(private Clock $clock) {}

    public function greet(string $name): string
    {
        return sprintf(
            'Hello %s — %s',
            $name,
            $this->clock->now()->format('c')
        );
    }
}

interface Clock { public function now(): DateTimeImmutable; }
class SystemClock implements Clock
{
    public function now(): DateTimeImmutable { return new DateTimeImmutable(); }
}
use Infocyph\InterMix\DI\Container;

$c = Container::instance()
    ->definitions()->bind(Clock::class, SystemClock::class)->end();

echo $c->get(Greeter::class)->greet('Alice');
// → “Hello Alice — 2025-06-18T12:34:56+00:00”

Creating & naming containers#

Use Container::instance('alias') for explicit named containers. Each alias returns an isolated registry. Use distinct aliases for tests, CLI workers, micro-modules, etc.

Container Features#

  • Scoped servicesenterScope(), leaveScope(), withinScope() for request/fiber isolation

  • Dependency graph exportexportGraph() for debugging and analysis

  • Environment-specific bindingssetEnvironment() for different deployment configs

  • Debug tracingdebug() and tracer() for development insight

  • Service locationfindByTag() for tagged service discovery

  • Container lockinglock() to prevent runtime modifications

  • Multiple container instancesContainer::instance($alias) for isolated contexts

Modifying behaviour with options()->setOptions()#

  • injection – reflection autowiring engine

  • methodAttributes / propertyAttributes – enable #[Infuse]

  • defaultMethod – method to call when none supplied

  • lazyLoading – defer heavy construction until first use

$c->options()->setOptions(
    injection: true,
    methodAttributes: true,
    propertyAttributes: true,
    defaultMethod: 'handle'
);

Common quick patterns (copy-paste as you learn the rest)#

Register a class with predefined constructor args

$c->registration()->registerClass(Db::class, [
    'dsn' => 'mysql://root@localhost/db',
    'flags' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
]);

Register a bootstrap method

$c->registration()->registerMethod(App::class, 'boot');

Tag & iterate

$c->definitions()->bind('L1', fn()=>new ListenerA, tags:['event']);
foreach ($c->findByTag('event') as $id => $listener) {
    $listener->handle();
}

Scope isolation

$c->enterScope('request-123');
// scoped services now unique to this request
$c->leaveScope();

Dive in Details#

Dive into the detailed sub-chapters. Happy mixing! Questions? Open an issue or drop by the discussion board.