miércoles, 25 de junio de 2025

Implementando Programación Orientada a Aspectos (AOP) en PHP con Interceptores Dinámicos

Implementando Programación Orientada a Aspectos (AOP) en PHP con Interceptores Dinámicos

La Programación Orientada a Aspectos (AOP) es un paradigma que permite modularizar preocupaciones transversales, como el logging, la seguridad o la gestión de transacciones, separándolas de la lógica principal de la aplicación. En PHP, la implementación nativa de AOP es limitada, pero podemos simularla utilizando interceptores dinámicos con funciones como __call() y el uso de closures.

El siguiente ejemplo muestra cómo interceptar las llamadas a métodos de una clase para, por ejemplo, registrar información antes y después de la ejecución de cada método. Usaremos una clase proxy que "envuelve" la clase original y aplica la lógica del aspecto.


<?php

class TargetClass {
    public function doSomething($arg1, $arg2) {
        echo "Realizando algo con: " . $arg1 . ", " . $arg2 . "<br>";
        return "Resultado: " . $arg1 . " + " . $arg2;
    }

    public function doSomethingElse() {
        echo "Realizando otra cosa.<br>";
        return "Otro resultado";
    }
}

class AspectInterceptor {
    private $target;
    private $beforeAdvice;
    private $afterAdvice;

    public function __construct($target, callable $beforeAdvice, callable $afterAdvice) {
        $this->target = $target;
        $this->beforeAdvice = $beforeAdvice;
        $this->afterAdvice = $afterAdvice;
    }

    public function __call($name, $arguments) {
        // Before Advice
        call_user_func($this->beforeAdvice, $name, $arguments);

        // Ejecutar el método original
        $result = call_user_func_array([$this->target, $name], $arguments);

        // After Advice
        call_user_func($this->afterAdvice, $name, $arguments, $result);

        return $result;
    }
}

// Ejemplo de uso
$target = new TargetClass();

$beforeAdvice = function($methodName, $arguments) {
    echo "Interceptando llamada a: " . $methodName . " con argumentos: " . implode(", ", $arguments) . "<br>";
};

$afterAdvice = function($methodName, $arguments, $result) {
    echo "Después de ejecutar " . $methodName . ". Resultado: " . $result . "<br>";
};

$interceptor = new AspectInterceptor($target, $beforeAdvice, $afterAdvice);

$interceptor->doSomething("valor1", "valor2");
$interceptor->doSomethingElse();

?>
    

En este ejemplo, AspectInterceptor actúa como el proxy. El método mágico __call() intercepta todas las llamadas a métodos no definidos en la clase AspectInterceptor. Antes de invocar el método original de la clase TargetClass, se ejecuta el beforeAdvice (en este caso, una closure que registra la llamada al método). Después, se ejecuta el método original y, finalmente, se ejecuta el afterAdvice (otra closure que registra el resultado del método).

Este enfoque permite separar la lógica de la clase principal (TargetClass) de la lógica de la interceptación (logging, seguridad, etc.). Se puede modificar o agregar nuevos aspectos sin modificar la clase original.

No hay comentarios:

Publicar un comentario