phpnomad/php-di-integration

PHP-DI integration for PHPNomad — compilable container, config repo, and registry backed by PHP-DI.

Maintainers

Package info

github.com/phpnomad/php-di-integration

pkg:composer/phpnomad/php-di-integration

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-05-06 02:41 UTC

This package is auto-updated.

Last update: 2026-05-06 02:46:52 UTC


README

PHP-DI-backed implementations of PHPNomad's InstanceProvider/HasBindings, ConfigStrategy, and Registry interfaces. An opt-in upgrade for consumers that want compilable, fast resolution while preserving PHPNomad's runtime extensibility.

Why

PHPNomad ships with an intentionally minimal default container. For distributed plugins (WordPress installs, etc.) where boot tax compounds across requests, this integration swaps in PHP-DI with build-time compilation — emitting a plain PHP class that opcache loads for free, eliminating per-request reflection cost.

The trade is a vendor dependency on php-di/php-di and a build-step that emits the compiled container. The runtime API matches PHPNomad's existing contract, so consumer code that already uses InstanceProvider, HasBindings, ConfigStrategy, or the Registry traits doesn't change.

Installation

composer require phpnomad/php-di-integration

Usage

As a suite (most common)

Add the suite Initializer to your bootstrapper:

use PHPNomad\Integrations\PhpDi\Container\CompiledContainerLoader;
use PHPNomad\Integrations\PhpDi\Initializer as PhpDiInitializer;
use PHPNomad\Loader\Bootstrapper;

$container = CompiledContainerLoader::load($tier); // tier identifies the compiled artifact
(new Bootstrapper(
    $container,
    new PhpDiInitializer(),    // Container + Config + Registry sub-initializers
    new YourCoreInitializer(),
    // ...
))->load();

CompiledContainerLoader::load($tier) returns a PhpDiContainer wrapping either a build-time-compiled \DI\Container subclass (fast path) or a runtime-built \DI\ContainerBuilder (fallback when no compiled artifact is present). The runtime path is identical to non-compiled PHP-DI behavior.

Piecemeal composition

Power users that only want one of the three concerns can compose sub-initializers directly. Container must come first since Config and Registry depend on InstanceProvider:

use PHPNomad\Integrations\PhpDi\Container\Initializer as ContainerInitializer;
use PHPNomad\Integrations\PhpDi\Config\Initializer as ConfigInitializer;

(new Bootstrapper(
    $container,
    new ContainerInitializer(),
    new ConfigInitializer(),
    // skip Registry — keep PHPNomad's simple registry impl
    new YourCoreInitializer(),
))->load();

Build-time compilation

Wire Compiler::compileForTier() into your build step. Run it after composer install (and after any vendor-prefixing step like Strauss) so the compiled output references runtime class names correctly:

use PHPNomad\Integrations\PhpDi\Container\Compiler;

$initializers = [
    new \PHPNomad\Integrations\PhpDi\Initializer(),
    new YourCoreInitializer(),
    // ...recurse into Loaders to flatten sub-initializers...
];

Compiler::compileForTier(
    tier:      'lite',
    outDir:    __DIR__ . '/build/lib/Compiled/PhpDiContainer',
    initializers: $initializers,
);

This emits a class at <outDir>/Lite.php that the runtime loader will prefer over the runtime-built container. Per-tier compilation is supported — pass different tier identifiers and initializer sets for builds that ship different binding configurations (e.g., free vs paid plugin tiers).

Boot order

Container must boot before Config and Registry, because the latter two resolve through InstanceProvider. The suite Initializer encodes this; piecemeal users must honor it manually.

Runtime overrides

The compiled container is not immutable. PHP-DI's set() against a built container takes precedence over compiled bindings, so tier switches, test bindings, and third-party extensions keep working at runtime. Compiled containers reject Definition objects via set() at runtime — the adapter's bind() and bindFactory() handle this transparently (eager-resolving raw values when the underlying container is compiled).

Multi-abstract bind semantics

This integration mirrors PHPNomad's simple Container::bind() semantics exactly: when you bind one concrete to multiple abstracts in a single call, all abstracts share the resulting instance. Each abstract aliases to the concrete independently — a later bind() that re-points one abstract leaves the others pointing at the original concrete. Self-binding (bind(Foo::class, Foo::class)) is special-cased to autowire directly rather than alias to itself.

Requirements

  • PHP 8.2+
  • PHPNomad 2.x or 3.x
  • php-di/php-di ^7.0

License

MIT