VOOZH about

URL: https://deepwiki.com/hypervel/http/4.2-route-dependency-injection

⇱ Route Dependency Injection | hypervel/http | DeepWiki


Loading...
Menu

Route Dependency Injection

Purpose and Scope

This document explains the route dependency injection system implemented by the RouteDependency class. This system automatically resolves parameters for route handlers (both controller methods and closures) by combining route parameters, default values, and dependency injection container bindings. It enables type-hinted controller method parameters to be automatically injected from the DI container, while also supporting explicit route parameter binding.

For information about how routes are matched and dispatched, see Core Middleware & Request Lifecycle. For details on the request and response objects that can be injected, see Request Object & Contract and Response Object & Contract.

Sources: src/RouteDependency.php1-176 src/CoreMiddleware.php127-152


System Overview

The RouteDependency class is instantiated by CoreMiddleware and serves as the bridge between route parameters, PHP reflection metadata, and the dependency injection container. When a route is matched, it resolves all parameters needed to invoke the handler, whether that handler is a closure or a controller method.


Sources: src/CoreMiddleware.php40-46 src/CoreMiddleware.php127-152 src/RouteDependency.php40-46


RouteDependency Class Structure

The RouteDependency class manages parameter resolution and provides extension points through after-resolving callbacks.

PropertyTypePurpose
$containerContainerInterfaceResolves type-hinted dependencies from the DI container
$normalizerNormalizerInterfaceConverts string route parameters to typed values
$methodDefinitionCollectorMethodDefinitionCollectorInterfaceExtracts parameter metadata from controller methods
$closureDefinitionCollectorClosureDefinitionCollectorInterfaceExtracts parameter metadata from closures
$resolvedDefinitionsarrayCaches parameter definitions to avoid repeated reflection
$afterResolvingCallbacksarray<class-string, list<callable>>Callbacks to execute after resolving specific types
$resolvedCallbacksarrayCached callback lookups per class
$resolvingCallbacksRegisteredboolTracks if any after-resolving callbacks are registered

Sources: src/RouteDependency.php18-44


Parameter Resolution Process

When CoreMiddleware needs to invoke a route handler, it requests parameter resolution from RouteDependency. The process differs slightly for controller methods versus closures, but both follow the same resolution algorithm.

Controller Method Resolution Flow


Sources: src/RouteDependency.php108-115 src/RouteDependency.php134-140 src/RouteDependency.php156-175 src/CoreMiddleware.php137-151

Closure Resolution Flow

Closure resolution follows the same pattern but uses ClosureDefinitionCollectorInterface and caches definitions by object hash rather than class/method signature.

Sources: src/RouteDependency.php122-129 src/RouteDependency.php145-151 src/CoreMiddleware.php130-134


Parameter Resolution Algorithm

The getDependencies() method implements the core resolution logic with a clear priority order:

Resolution Priority


Parameter Sources Table

PrioritySourceMethodExample
1Route Parameters (by index)$arguments[$index]/users/{id}$arguments[0]
2Route Parameters (by name)$arguments[$definition->getMeta('name')]$arguments['id']
3Default Values$definition->getMeta('defaultValue')function show($id = 1)
4DI Container$container->get($definition->getName())function show(Request $request)
5Nullable Typesnull if $definition->allowsNull()function show(?User $user)

Sources: src/RouteDependency.php156-175

Type Conversion

When a route parameter is matched (priority 1 or 2), the value is denormalized to the expected type using the NormalizerInterface:


This converts string URL segments to the appropriate PHP types (int, bool, etc.) based on the parameter's type hint.

Sources: src/RouteDependency.php161


Definition Collection and Caching

To avoid repeated reflection on every request, RouteDependency caches parameter definitions in the $resolvedDefinitions array.

Method Definition Caching


Key Points:

  • Method definitions are keyed by "{$controller}::{$action}" signature
  • Closure definitions are keyed by spl_object_hash($closure)
  • Definitions are stored as ReflectionType[] arrays
  • Cache persists for the lifetime of the worker process

Sources: src/RouteDependency.php134-151 src/RouteDependency.php21


After-Resolving Callbacks

The after-resolving callback system allows custom logic to execute after specific types are resolved from the DI container. This is useful for modifying objects or performing additional setup.

Callback Registration


Constraints:

  • The class must exist (checked at registration time)
  • Callbacks are registered globally and apply to all routes
  • Multiple callbacks can be registered for the same class

Sources: src/RouteDependency.php48-62

Callback Execution

After all parameters are resolved, CoreMiddleware calls fireAfterResolvingCallbacks() to execute any registered callbacks:


Callback Signature:


Sources: src/RouteDependency.php64-101 src/CoreMiddleware.php131 src/CoreMiddleware.php144

Callback Lookup Optimization

The system optimizes callback lookups by:

  1. Checking $resolvingCallbacksRegistered flag to short-circuit if no callbacks exist
  2. Caching the merged callback list per class name in $resolvedCallbacks
  3. Supporting inheritance - callbacks registered for interfaces or parent classes apply to subclasses

Sources: src/RouteDependency.php86-101


Integration with CoreMiddleware

CoreMiddleware integrates RouteDependency during route handler invocation in its handleFound() method:

For Closures


For Controller Methods


Key Integration Points:

  • RouteDependency is instantiated in CoreMiddleware constructor
  • Route parameters from DispatchedRoute::parameters() are passed to resolution methods
  • After-resolving callbacks are fired before handler invocation
  • Resolved parameters are unpacked with ... operator when calling handlers

Sources: src/CoreMiddleware.php40-46 src/CoreMiddleware.php127-152


Error Handling

The parameter resolution system throws InvalidArgumentException in two scenarios:

1. Non-Existent Class in Callback Registration


2. Unresolvable Required Parameter


This occurs when a required parameter (non-nullable, no default value) cannot be resolved from any source.

Sources: src/RouteDependency.php53-54 src/RouteDependency.php169-170


Complete Resolution Example

Consider a controller method with multiple parameter types:

Controller method signature:
public function update(Request $request, int $id, UserRepository $repo, ?string $name = null)

Resolution Process:

ParameterTypeResolutionSource
$requestRequestFrom DI container$container->get(Request::class)
$idintFrom route parameter$arguments['id'] → normalized to int
$repoUserRepositoryFrom DI container$container->get(UserRepository::class)
$name?stringDefault valuenull (default from signature)

Execution Flow:

  1. CoreMiddleware::handleFound() calls getMethodParameters('Controller', 'update', ['id' => '123'])
  2. getMethodDefinitions() returns cached or collected definitions
  3. getDependencies() iterates parameters:
    • $request: Not in route params → container has Request → resolve from container
    • $id: Found in route params → normalize '123' to int 123
    • $repo: Not in route params → container has UserRepository → resolve from container
    • $name: Not in route params → has default value → use null
  4. fireAfterResolvingCallbacks() executes any callbacks for Request or UserRepository
  5. Returns [$requestInstance, 123, $repoInstance, null]
  6. Controller method invoked with these parameters

Sources: src/RouteDependency.php108-175 src/CoreMiddleware.php137-151