Extracción Dinámica de Dependencias con ReflectionFunctionAbstract en PHP
La inyección de dependencias es un patrón de diseño fundamental en el desarrollo moderno de PHP. Si bien generalmente se maneja a través de contenedores de inyección de dependencias, a veces necesitamos una solución más ligera para analizar y resolver dependencias de funciones o métodos de manera dinámica, sin depender de un contenedor completo. ReflectionFunctionAbstract
nos permite inspeccionar funciones y métodos y determinar sus dependencias de manera programática.
Este enfoque es especialmente útil en escenarios donde necesitas generar automáticamente la resolución de dependencias en tiempo de ejecución, como la creación de pipelines de procesamiento de datos o la implementación de middlewares personalizados.
<?php
/**
* Función de utilidad para resolver dependencias dinámicamente.
*
* @param ReflectionFunctionAbstract $reflection La función o método a analizar.
* @param array $providedDependencies Un array asociativo de dependencias ya resueltas (opcional).
* @return array Un array de dependencias resueltas.
* @throws ReflectionException Si una dependencia no se puede resolver.
*/
function resolveDependencies(ReflectionFunctionAbstract $reflection, array $providedDependencies = []): array
{
$dependencies = [];
foreach ($reflection->getParameters() as $parameter) {
$name = $parameter->getName();
$type = $parameter->getType();
if ($type === null) {
if(array_key_exists($name, $providedDependencies)) {
$dependencies[] = $providedDependencies[$name];
continue;
}
throw new ReflectionException("No se puede resolver la dependencia: {$name} (sin tipo especificado).");
}
$typeName = $type instanceof ReflectionNamedType ? $type->getName() : (string)$type; // PHP 7.1+
// Simulación de la resolución de dependencias (reemplazar con la lógica real).
if ($typeName === 'MyService') {
// Aquí iría la lógica para obtener una instancia de MyService, por ejemplo, desde un contenedor DI.
$dependencies[] = new MyService();
} elseif (array_key_exists($typeName, $providedDependencies)) {
$dependencies[] = $providedDependencies[$typeName];
} else {
throw new ReflectionException("No se puede resolver la dependencia: {$typeName}.");
}
}
return $dependencies;
}
class MyService {
public function doSomething() {
return "Hice algo!";
}
}
function myFunc(MyService $service, $parametroSinTipo) {
return $service->doSomething() . " " . $parametroSinTipo;
}
$reflection = new ReflectionFunction('myFunc');
try {
$resolvedDependencies = resolveDependencies($reflection, ['parametroSinTipo' => 'Valor del parámetro']);
$result = $reflection->invokeArgs($resolvedDependencies);
echo $result; // Imprime "Hice algo! Valor del parámetro"
} catch (ReflectionException $e) {
echo "Error: " . $e->getMessage();
}
El código anterior define una función resolveDependencies
que, dado un objeto ReflectionFunctionAbstract
, analiza los parámetros de la función o método. Intenta resolver cada parámetro basándose en su tipo declarado. En el ejemplo, simulamos la resolución de la dependencia MyService
. En una aplicación real, esto implicaría obtener una instancia del servicio desde un contenedor de inyección de dependencias o a través de alguna otra lógica de fábrica. El parámetro sin tipo explícito se resuelve mediante el array de dependencias provistas.
La función myFunc
demuestra cómo se puede utilizar esta técnica para inyectar dependencias resueltas dinámicamente. La invocación de $reflection->invokeArgs()
ejecuta la función con las dependencias inyectadas.
En resumen, ReflectionFunctionAbstract
ofrece una forma poderosa de analizar y resolver dependencias de funciones y métodos en tiempo de ejecución, permitiendo soluciones flexibles y dinámicas para la inyección de dependencias en PHP.
No hay comentarios:
Publicar un comentario