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:
RegistryCompilerturns normalized descriptor definitions into a validatedCompiledRegistryDescriptorResolverselects exactly oneProspectDescriptorDescriptorInstantiatorbuilds an object from that descriptorInMemoryRuntimeInstanceStorehandles singleton, scoped, and pooled runtime behavior
composer require liquidrazor/diregistryRequirements:
- PHP 8.3 or newer
- Composer autoloading
- a source of descriptor definitions before runtime
<?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
- 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.
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.
composer install
vendor/bin/phpunit