2009-09-03 22 views
5

Tengo una clase con métodos estáticos, y me gustaría interceptar llamadas a métodos antes de llamar a los métodos.Interceptar llamadas a métodos en PHP

Así que si me llaman

$model = DataMapper::getById(12345); 

entonces quiero algún método en DataMapper a ser llamado antes de llamar a este método, y luego opcionalmente este método interceptando posteriormente puede llamar self :: getById (12345). ¿Hay alguna forma de hacer esto?

Estoy implementando Memcache en mi servidor, así que es por eso que quiero interceptar llamadas a métodos. No quiero que los métodos estáticos consulten la base de datos si los modelos ya están en la memoria caché, y tampoco quiero tener que modificar cientos de diferentes métodos del asignador, de forma redundante, para admitir la Memcache.

Estoy ejecutando PHP 5.2.6.

Respuesta

1

This'd hacer el trabajo: Triggering __call() in PHP even when method exists

Sólo declaran sus métodos estáticos como protected por lo que son inaccesibles fuera de la clase y obtener el método mágico __callStatic() invocarlos.

Editar: Uy, que voy a necesitar 5,3 a hacerlo ...

+0

Oh, caramba. Olvidé que ya había hecho esta misma pregunta exacta. * patos * Gracias. –

+0

Hahah, oh wow ... Ni siquiera noté que eras tú. Irónico. – brianreavis

0

supongo que se podría haber creado un poco de magia con runkit, pero lo que se necesita para compilar la extensión de CVS, ya que la última versión no es compatible con 5.2.x

ejemplo:

<?php 

/* Orig code */ 
class DataMapper { 
    static public function getById($value) { 
    echo "I'm " . __CLASS__ . "\n"; 
    } 
} 


/* New Cache Mapper */ 
class DataMapper_Cache { 
    static public function getById($value) { 
    echo "I'm " . __CLASS__ . "\n"; 
    } 
} 


// Running before rename and adopt 
DataMapper::getById(12345); 

// Do the renaming and adopt 
runkit_method_rename('DataMapper', 'getById', 'getById_old'); 
runkit_class_adopt('DataMapper','DataMapper_Cache'); 

// Run the same code.. 
DataMapper::getById(12345); 

?> 

Output: 
    I'm DataMapper 
    I'm DataMapper_Cache 
+0

Entonces, ¿esta es solo otra extensión de PHP como cualquier otra? ¿Qué tipo de golpe de rendimiento tomaría si tuviera que usar Runkit de esta manera? –

+0

Ver el ejemplo agregado a mi respuesta ... – goddva

+0

No he visto ningún problema de rendimiento de velocidad. Sin embargo, no tengo ningún código de ejecución en producción. Debería usar runkit en los casos en que no tenga ninguna opción. :) – goddva

1

Este es un ejemplo donde es posible que desee considerar abandonando los métodos estáticos en favor de polimorfismo. Si los datos del mapeador era una interfaz entonces usted podría tener dos implementaciones, uno para la base de datos y otro para Memcache:

interface DataMapper { 
    public function getById($id); 
    // other data mapper methods 
} 

class DataMapper_DB implements DataMapper { 

    public function getById($id) { 
     // retrieve from db 
    } 
    // other methods 
} 

class DataMapper_Memcache implements DataMapper { 

    private $db;   

    public function __construct(DataMapper_DB $db, $host, ...) { 
     $this->db = $db; 
     // other set up 
    } 

    public function getById($id) { 

     // if in memcache return that 

     // else 
     $record = $this->db->getById($id); 

     // add record to memcache 

     return $record 
    } 
    //other methods 
} 
1

yo sólo ocurrió una manera de interceptar las llamadas a métodos en PHP - Check it out.

Es solo un ejemplo básico, y las clases que quieren ser interceptables tienen que "participar" - no se puede interferir con el comportamiento de las clases que no implementan los dos métodos mágicos.

No sé si esto se adapte a sus necesidades - pero este patrón se puede implementar sin generación de código o código de bytes de ejecución hacks, y que tiene que ser un punto a favor ;-)

Cuestiones relacionadas