Hook Management
Overview
Hook management in the DomainFlow Container allows you to register custom callbacks (hooks) that execute before and after a service is resolved. This feature lets you inject custom logic such as logging, inspection, or post-resolution configuration into the dependency resolution process.
Key Concepts
Before Resolve Hooks:
These hooks execute before resolution. They receive the abstract identifier and a by-value copy of the parameter array, so they can inspect the request but cannot alter the parameters used by the container.
After Resolve Hooks:
These hooks execute after resolution, including when the requested value comes from the instance cache. They can modify or replace the value returned for that resolution.
Hook Registration:
The container provides two methods for hook registration:
| Method | Signature | Description |
|---|---|---|
addBeforeResolve | addBeforeResolve(callable $hook): void | Registers a hook to execute before service resolution. |
addAfterResolve | addAfterResolve(callable $hook): void | Registers a hook to execute after service resolution. |
Implementation Details
The container uses a dedicated trait (HookManagerTrait) to manage hooks. This trait maintains two internal arrays:
$beforeResolveHooks: An array of callbacks executed before a service is resolved.$afterResolveHooks: An array of callbacks executed after a service is resolved.
When a service is requested:
- The container iterates over the before resolve hooks, executing each with the service identifier and a copy of the parameter array.
- The service is resolved, either by building it or by reading an existing instance.
- Finally, the container processes the after resolve hooks, which can modify or replace the returned value.
Example Usage
Below is an example that demonstrates how to register and use hooks within the container:
// Create the container instance.
$container = new Container();
// Register a before resolve hook to inspect the resolution request.
$container->addBeforeResolve(function (string $abstract, array $parameters) {
echo "Resolving service: {$abstract}\n";
});
// Register an after resolve hook to modify the resolved object.
$container->addAfterResolve(function (mixed $instance, string $abstract, array $parameters): mixed {
// If the resolved service is an instance of SomeService, set a configuration flag.
if ($instance instanceof SomeService) {
$instance->configured = true;
}
// Return the modified instance (or null to keep the original).
return $instance;
});
// Bind a sample service.
$container->bind(SomeService::class, SomeService::class);
// Resolving the service triggers both hooks.
$service = $container->get(SomeService::class);
// The output includes the before resolve log, and the service instance is modified by the after resolve hook.
In this example:
- The before resolve hook logs the service identifier each time a service is requested. Its parameter array is not mutable from the hook.
- The after resolve hook checks if the resolved instance is of a certain type and adjusts its configuration accordingly.
Benefits
-
Customization:
Hooks allow you to inject custom behavior into the dependency resolution process without altering the core container logic. -
Separation of Concerns:
By isolating cross-cutting concerns (such as logging or additional configuration) into hooks, your service classes remain focused on their primary responsibilities. -
Flexibility:
Hooks can inspect requests, adjust the resolved value, or replace it entirely, offering high flexibility in managing service lifecycles.
Summary
Hook management in the DomainFlow Container enhances the dependency resolution process by enabling the execution of custom logic both before and after a service is built. This feature not only improves modularity by separating cross-cutting concerns but also provides advanced customization options to tailor the behavior of your application’s service resolution pipeline.