waffle-commons/container

Container component for Waffle framework.

Maintainers

Package info

github.com/waffle-commons/container

pkg:composer/waffle-commons/container

Statistics

Installs: 87

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

0.1.0-beta2.1 2026-05-30 18:57 UTC

README

Discord PHP Version Require PHP CI codecov Latest Stable Version Latest Unstable Version Total Downloads Packagist License

Waffle Container Component

Release: v0.1.0-beta2 ย |ย  CHANGELOG.md PSR Compliance: PSR-11 (Psr\Container\ContainerInterface)

A strict PSR-11 service container with reflection-based autowiring, circular-dependency detection, and worker-mode resettability. Core services (the PSR-11 ContainerInterface itself) are locked from override after registration.

๐Ÿ“ฆ Installation

composer require waffle-commons/container

๐Ÿงฑ Surface

Class Role
Waffle\Commons\Container\Container The container. Implements Waffle\Commons\Contracts\Container\ContainerInterface (PSR-11 + ResettableInterface).
Waffle\Commons\Container\Autowire Reflection-based autowiring helper used by Container::build() to resolve constructor parameters.
Waffle\Commons\Container\Exception\ContainerException Thrown for retrieval / resolution failures.
Waffle\Commons\Container\Exception\NotFoundException Thrown when get($id) cannot resolve the identifier.

๐Ÿš€ Usage

use Waffle\Commons\Container\Container;

$container = new Container([
    // Direct instance
    LoggerInterface::class => new StreamLogger(),

    // Class string โ€” autowired via reflection on first get()
    UserService::class => UserService::class,

    // Factory closure
    'app.config' => static fn() => new Config(__DIR__ . '/config', 'prod'),
]);

$logger = $container->get(LoggerInterface::class);
$exists = $container->has(UserService::class);

$container->set('db.cache', new ArrayCache());

The exact public signature, verbatim from Waffle\Commons\Contracts\Container\ContainerInterface:

public function get(string $id): mixed;
public function has(string $id): bool;
public function set(string $id, object|callable|string $concrete): void;
public function reset(): void; // from ResettableInterface

๐Ÿ” Worker-mode reset

Container implements ResettableInterface. After each request, the kernel calls reset() so the container drops its instance cache while keeping the registered definitions, preventing user-context leaks across FrankenPHP worker requests.

๐Ÿ›ก๏ธ Locked core services

The constant Container::CORE_SERVICES lists identifiers that must not be redefined once registered. The PSR-11 ContainerInterface itself is in that list โ€” any attempt to override it after the container is built throws ContainerException.

๐Ÿ”„ Circular-dependency detection

Container::get($id) tracks the resolution stack in $resolving and throws ContainerException if a cycle is detected before infinite recursion can occur.

๐Ÿ˜ PHP 8.5 features used

  • final class Container โ€” no subclassing.
  • Typed properties throughout.
  • Typed constants for service registries: private const CORE_SERVICES = [...];.
  • #[\Override] on every method that overrides PSR-11.

๐Ÿงญ Architectural boundary (mago guard)

An active dependency perimeter is enforced on every CI run by vendor/bin/mago guard (bundled into composer mago; zero baselines). The rules live in mago.toml under [guard.perimeter] โ€” a forbidden use statement fails the build, not a reviewer.

Production code under Waffle\Commons\Container may depend only on:

  • Waffle\Commons\Container\** โ€” itself
  • Waffle\Commons\Contracts\** โ€” the shared contracts package, the only Waffle dependency permitted
  • Psr\** โ€” PSR interfaces (PSR-11)
  • @global + Psl\** โ€” PHP core and the PHP Standard Library

Test code under WaffleTests\Commons\Container is unrestricted (@all). Structural rules are guarded too: interfaces must be named *Interface, Exception\** classes must end in *Exception, and any Enum\** namespace may hold only enum declarations.

Contract-first, component-agnostic by construction: components compose through waffle-commons/contracts, never directly through one another.

๐Ÿงช Testing

docker exec -w /waffle-commons/container waffle-dev composer tests

๐Ÿ“„ License

MIT โ€” see LICENSE.md.