VOOZH about

URL: https://deepwiki.com/hypervel/container/3.3-service-binding

⇱ Service Binding | hypervel/container | DeepWiki


Loading...
Menu

Service Binding

Purpose and Scope

This document explains how to register services with the Hypervel Container. Service binding is the process of telling the container how to create instances of classes or resolve dependencies. This page covers the core registration methods (bind(), bindIf(), instance()), binding types, and precedence rules.

For information about resolving bound services, see Dependency Resolution. For advanced binding features like service decoration and aliases, see Extenders, Aliases & Method Bindings.


Core Binding Methods

The Container provides three primary methods for registering services, each with distinct behavior and use cases.

Method Overview

MethodPurposeOverwrites ExistingShared InstanceWhen to Use
bind()Register a bindingYesNo (creates new each time)Standard service registration
bindIf()Register only if not boundNoNoConditional registration, defaults
instance()Register existing instanceYesYes (always returns same instance)Pre-constructed objects, singletons

bind()

The bind() method registers a service definition with the container. It accepts an abstract identifier (typically an interface or class name) and a concrete implementation.

Signature:


Behavior:

  1. Clears any previously resolved instances via src/Container.php245
  2. If $concrete is null, uses $abstract as the concrete type
  3. Fires rebinding callbacks if the abstract was already bound src/Container.php254-256
  4. Stores the definition using the parent container's define() method src/Container.php258

Sources: src/Container.php243-259 src/Contracts/Container.php46-52

bindIf()

The bindIf() method conditionally registers a binding only if no binding exists for the given abstract type. This is useful for providing default implementations that can be overridden.

Signature:


Behavior:

  1. Checks if abstract is already bound using bound() src/Container.php304
  2. Only calls bind() if not already bound
  3. No action taken if binding already exists

Sources: src/Container.php302-307 src/Contracts/Container.php70-74

instance()

The instance() method registers an existing object instance as a shared singleton in the container. Every subsequent resolution will return the same instance.

Signature:


Behavior:

  1. Removes abstract alias mappings src/Container.php331
  2. Unsets any existing alias for the abstract src/Container.php333
  3. Wraps object instances in a closure src/Container.php338-340
  4. Fires rebinding callbacks if already bound src/Container.php342-344
  5. Stores the instance using define() src/Container.php346
  6. Returns the instance

Sources: src/Container.php329-349 src/Contracts/Container.php84-86


Binding Method Flow Diagram


Sources: src/Container.php243-259 src/Container.php302-307 src/Container.php329-349


Binding Types and Concrete Implementations

The $concrete parameter in bind() accepts three types of values, each enabling different resolution behaviors.

Null Concrete (Auto-Resolution)

When $concrete is null, the container uses the abstract type name as the concrete class to instantiate.


This is equivalent to:


Use Case: Simple class bindings where the abstract and concrete are the same.

Sources: src/Container.php250-252

String Concrete (Class Name)

When $concrete is a string, it represents a class name that the container will instantiate when resolving the abstract.


Use Case: Interface-to-implementation bindings, polymorphism, dependency inversion.

Sources: src/Container.php243-259

Closure Concrete (Factory)

When $concrete is a Closure, the container executes it to obtain the instance. The closure receives the container as a parameter.


Use Case: Complex object construction, conditional instantiation, configuration-based creation.

Sources: src/Container.php243-259


Concrete Types Comparison

Concrete TypeResolution BehaviorContainer InvolvementExample
nullInstantiates abstract class directlyFull (constructor injection)bind(Service::class)
StringInstantiates named classFull (constructor injection)bind(Interface::class, Impl::class)
ClosureExecutes factory functionPartial (closure receives container)bind(Service::class, fn($c) => new Service())
Object (via instance())Returns same instanceNone (pre-constructed)instance(Service::class, $object)

Binding Lifecycle and Internal Mechanisms

Stale Instance Management

When a service is rebound, the container must clear cached data to ensure subsequent resolutions use the new binding.


The dropStaleInstances() method src/Container.php648-651 removes:

  • Previously resolved instances from $resolvedEntries
  • Alias mappings for the abstract

Sources: src/Container.php245 src/Container.php648-651

Rebinding Callbacks

When a service that was already bound is rebound, the container fires registered rebinding callbacks. This allows dependent services to receive the new instance.

Flow:

  1. bind() checks if abstract is already bound src/Container.php254
  2. If bound, calls rebound() src/Container.php255
  3. rebound() resolves the new instance and fires all registered callbacks src/Container.php412-419

Sources: src/Container.php254-256 src/Container.php412-419

Definition Storage

Both bind() and instance() ultimately call define() from the parent HyperfContainer class to store the binding in the DefinitionSource.


Sources: src/Container.php258 src/Container.php346


Binding Precedence Rules

When multiple bindings target the same abstract, the container follows specific precedence rules.

Precedence Order

  1. Last Binding Wins: When bind() is called multiple times for the same abstract, the most recent binding takes precedence
  2. Instance Overwrites All: Calling instance() overwrites any previous bind() or instance() calls
  3. bindIf() Never Overwrites: bindIf() has no effect if any binding exists

Precedence Example Flow


Sources: src/Container.php243-259 src/Container.php302-307 src/Container.php329-349


Interaction with Aliases

Service bindings work seamlessly with the alias system. When an aliased name is used in binding operations, the container resolves it to the canonical abstract name.

Alias Resolution in Binding

The container does not automatically resolve aliases during binding operations. Aliases are resolved during retrieval operations (get(), make()), not during registration operations.

However, instance() explicitly removes alias mappings to prevent conflicts src/Container.php331-333

Binding vs Aliasing

OperationCreates New BindingCreates Alias MappingUse Case
bind(A, B)Yes (A → B)NoRegister service implementation
alias(A, B)NoYes (B → A)Create alternative name for existing binding
instance(A, $obj)Yes (A → $obj)No (removes existing aliases)Register singleton instance

Sources: src/Container.php331-333 src/Container.php374-383


Code Entity Mapping: Binding Methods


Sources: src/Container.php243-349 src/Container.php648-651


Binding Operation Comparison


Sources: src/Container.php243-259 src/Container.php302-307 src/Container.php329-349


Internal State Management

Affected Data Structures

Service binding operations modify several internal container arrays:

ArrayPurposeModified ByAccess Method
$resolvedEntriesCached resolved instancesdropStaleInstances()resolved()
$aliasesAlias → Abstract mappingsdropStaleInstances(), instance()isAlias(), getAlias()
$abstractAliasesAbstract → Aliases mappingsinstance() via removeAbstractAlias()Internal only
$reboundCallbacksRebinding event handlersNot directly by bind methodsgetReboundCallbacks()

Sources: src/Container.php28-52 src/Container.php648-651 src/Container.php354-367


Checking Binding Status

The container provides methods to inspect whether services are bound or resolved:

bound()

Checks if a binding exists for the given abstract, regardless of whether it has been resolved.


Implementation checks the DefinitionSource for the abstract name src/Container.php194-201

resolved()

Checks if an abstract has been resolved (instantiated) at least once.


Implementation checks the $resolvedEntries cache src/Container.php219-226

has()

PSR-11 compliant method that checks if the container can provide an entry for the identifier.


Returns true if the identifier is an alias or has a binding src/Container.php211-214

Sources: src/Container.php194-226 src/Contracts/Container.php22-38


Summary

Service binding is the foundation of dependency injection in Hypervel Container. The three core methods serve distinct purposes:

  • bind(): Standard service registration with automatic rebinding support
  • bindIf(): Conditional registration for default implementations
  • instance(): Singleton registration for pre-constructed objects

All bindings support three concrete types (null, string, Closure) and interact with the container's alias system, rebinding callbacks, and instance cache to provide a flexible and powerful registration mechanism.

Sources: src/Container.php243-349 src/Contracts/Container.php46-86