Dispara un evento cuando se llama a una función en una clase

¿Es posible en PHP desencadenar un evento siempre que se llame a una función de una clase, sin agregarla a todas las funciones de la clase?

Ejemplo:

 

AFAIK no hay construcciones de lenguaje nativo para esto. Si lo necesita para depuración, le aconsejaría que profundice en la extensión xdebug, especialmente en los rastros de funciones (¡increíble! 🙂

Otra idea sería implementar __call() en su clase y ajustar todos los métodos públicos. Pero esto requiere cambiar el código y tiene otros efectos secundarios:

(ejemplo simplificado)

 class Test { protected $listeners; public function __construct() { $this->listeners = array(); } private function a() { echo 'something'; } private function b() { echo 'something else'; } public function __call($fname, $args) { call_user_func_array(array($this, $fname), $args); foreach($this->listeners as $listener) { $listener->notify('fname was called'); } } public function addListener(Listener $listener) { $this->listeners[]= $listener; } } 

.

  class Listener { public function notify($message) { echo $message; } } 

Ejemplo:

  $t = new Test(); $l = new Listener(); $t->addListener($l); $t->a(); 

Esta es una tarea clásica para la progtwigción orientada a aspectos (AOP). PHP no tiene soporte nativo para AOP, sin embargo, hay algunos frameworks que hacen posible AOP en PHP. ¡Uno de estos es GO! Marco AOP PHP . También puede implementar AOP usando runkit .

Necesitas PHP SplObserver: desde PHP Doc

¡Esta es una tarea clásica para la dependency injection y la inicialización lenta! La dependencia es la conexión MySQL. Como primero debe estar disponible cuando se ejecuta la primera consulta, no es necesario inicializarla en “inicio”, sino solo entonces. Esto se llama inicialización lenta, y su implementación es extremadamente simple:

 class DbStuff { private $__conn = NULL; protected function _getConn() { if ( is_null( $this->__conn ) { $this->__conn = ... ; // init (MySQL) DB connection here // throw on errors! } return $this->__conn; } public function someQuery($arg1, $arg2) { $conn = $this->_getConn(); // MySQL query here: ... } } 

Toda la “refactorización” requerida es llamar a $this->_getConn() en cada método de consulta.

La progtwigción orientada a aspectos no es el instrumento para resolver esto, porque la conexión DB es una dependencia innata de la consulta, y no un aspecto de ella. El registro automático de todas las consultas ejecutadas fue un aspecto.

Un desencadenante creado en torno a PHP __call() tampoco es una buena opción; además de noquear las inspecciones modernas de IDE -que son excelentes para ver rápidamente si un módulo es $this->_getWhatever() complicaría innecesariamente las pruebas: un $this->_getWhatever() protegido $this->_getWhatever() puede ser sobrescrito fácilmente en un objeto de fachada de prueba, derivado de la clase a prueba: para devolver un objeto simulado o lo que sea. Con __call() , se necesita más código para el mismo propósito, lo que induce el riesgo de errores en el código que solo está ahí para la prueba (y debe estar absolutamente libre de errores)