Skip to content

LiquidRazor/DIRegistry

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DI Registry

DI Registry is a PHP 8.3+ library for descriptor-driven dependency resolution and instantiation.

It is intentionally strict:

  • descriptors are explicit data, not executable configuration
  • resolution keys are limited to contract or class path
  • resolution is deterministic or it fails
  • runtime instances are stored outside descriptor metadata
  • scalar and configuration values are provided explicitly through a value provider

The library is built from four concrete runtime pieces:

  • RegistryCompiler turns normalized descriptor definitions into a validated CompiledRegistry
  • DescriptorResolver selects exactly one ProspectDescriptor
  • DescriptorInstantiator builds an object from that descriptor
  • InMemoryRuntimeInstanceStore handles singleton, scoped, and pooled runtime behavior

Installation

composer require liquidrazor/diregistry

Requirements:

  • PHP 8.3 or newer
  • Composer autoloading
  • a source of descriptor definitions before runtime

Quick Start

<?php

declare(strict_types=1);

use LiquidRazor\DIRegistry\Bootstrap\RegistryCompiler;
use LiquidRazor\DIRegistry\Contract\DependencyValueProviderInterface;
use LiquidRazor\DIRegistry\Descriptor\DependencyDescriptor;
use LiquidRazor\DIRegistry\Instantiator\DescriptorInstantiator;
use LiquidRazor\DIRegistry\Resolver\DescriptorResolver;
use LiquidRazor\DIRegistry\Runtime\InMemoryRuntimeInstanceStore;
use LiquidRazor\DIRegistry\Value\RuntimeContext;
use LiquidRazor\DIRegistry\Enum\Environment;

interface MailerInterface
{
}

final class SmtpMailer implements MailerInterface
{
    public function __construct(public string $dsn)
    {
    }
}

final class NewsletterService
{
    public function __construct(public MailerInterface $mailer)
    {
    }
}

final class ArrayValueProvider implements DependencyValueProviderInterface
{
    public function __construct(private array $values)
    {
    }

    public function canProvide(DependencyDescriptor $dependency, RuntimeContext $context): bool
    {
        return array_key_exists($dependency->name, $this->values);
    }

    public function provide(DependencyDescriptor $dependency, RuntimeContext $context): mixed
    {
        return $this->values[$dependency->name];
    }
}

$definitions = [
    [
        'id' => 'service.mailer.smtp',
        'classPath' => SmtpMailer::class,
        'contracts' => [MailerInterface::class],
        'source' => 'config/services.php',
        'lifecycle' => 'singleton',
        'environments' => ['prod'],
        'priority' => 0,
        'isDefault' => true,
        'constructionStrategy' => 'constructor',
        'dependencies' => [
            [
                'name' => 'dsn',
                'position' => 0,
                'kind' => 'scalar',
                'target' => 'mailer.dsn',
                'required' => true,
                'nullable' => false,
                'hasDefault' => false,
            ],
        ],
    ],
    [
        'id' => 'service.newsletter',
        'classPath' => NewsletterService::class,
        'contracts' => [],
        'source' => 'config/services.php',
        'lifecycle' => 'transient',
        'environments' => ['prod'],
        'priority' => 0,
        'isDefault' => false,
        'constructionStrategy' => 'constructor',
        'dependencies' => [
            [
                'name' => 'mailer',
                'position' => 0,
                'kind' => 'contract',
                'target' => MailerInterface::class,
                'required' => true,
                'nullable' => false,
                'hasDefault' => false,
            ],
        ],
    ],
];

$registry = (new RegistryCompiler())->compile($definitions, 'build-2026-03-26');
$resolver = DescriptorResolver::forRegistry($registry);
$instantiator = DescriptorInstantiator::forRuntime(
    $resolver,
    new ArrayValueProvider(['dsn' => 'smtp://localhost']),
    new InMemoryRuntimeInstanceStore(),
);

$context = new RuntimeContext(Environment::Prod);
$descriptor = $resolver->resolveClassPath(NewsletterService::class, $context->environment);
$service = $instantiator->instantiate($descriptor, $context);

What this example shows:

  • the compiler computes descriptor checksums and validates the full descriptor set
  • contract dependencies are resolved through the resolver
  • scalar dependencies come only from DependencyValueProviderInterface
  • singleton reuse is handled by the runtime store, not by registry mutation

Key Constraints

  • No alias system.
  • No autowiring.
  • No fallback from one environment to another.
  • No best-effort choice when multiple candidates remain tied.
  • No automatic handling of scalar or config dependencies.
  • No runtime mutation of compiled registry contents.

Documentation

Start with Documentation Home.

Recommended entry points:

  • Overview: design constraints, architecture, and library fit.
  • Getting Started: installation, first registry compilation, and first resolution.
  • Usage Guide: concrete runtime wiring and operational behavior.
  • Reference: public contracts, descriptors, enums, and exceptions.
  • Validation & Debug: compile checks, debug validation, and troubleshooting.

Development

composer install
vendor/bin/phpunit

About

The DI Registry is an indexed, in-memory repository of validated instantiation prospects

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages