2009-09-03 11 views
5

J'ai une classe avec des méthodes statiques, et je voudrais intercepter des appels de méthode avant que les méthodes ne soient appelées.Intercepter des appels à des méthodes en PHP

Donc, si j'appelle

$model = DataMapper::getById(12345); 

alors je veux une méthode DataMapper à appeler avant que cette méthode est appelée, puis éventuellement cette méthode d'interception peut ensuite appeler l'auto :: getById (12 345). Y a-t-il un moyen de faire cela?

J'implémente Memcache sur mon serveur, c'est pourquoi je veux intercepter les appels de méthode. Je ne veux pas que les méthodes statiques interrogent la base de données si des modèles sont déjà mis en cache, et je ne veux pas non plus devoir modifier, de manière redondante, des centaines de méthodes de mappeur différentes pour prendre en charge memcache.

Je cours PHP 5.2.6.

Répondre

1

This'd faire le travail: Triggering __call() in PHP even when method exists

Juste Déclarez vos méthodes statiques comme protected ils sont donc inaccessibles en dehors de la classe et obtenir la méthode magique __callStatic() pour les invoquer.

Edit: oups, vous avoir besoin 5.3 pour le faire ...

+0

Oh, zut. J'ai oublié que j'avais déjà posé exactement la même question. * canards * Merci. –

+0

Hahah, oh wow ... Je n'ai même pas remarqué que c'était toi. Ironique. – brianreavis

0

Je suppose que vous auriez pu créer un peu de magie avec runkit, mais vous devez compiler l'extension de cvs, depuis le dernière version ne supporte pas 5.2.x

exemple:

<?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

Donc, c'est juste une autre extension PHP comme les autres? Quel type de performance devrais-je prendre si je devais utiliser runkit de cette manière? –

+0

Voir l'exemple ajouté à ma réponse ... – goddva

+0

Je n'ai pas vu de problèmes de performances de vitesse - Cependant, je n'ai pas de code runkit en production .. Vous devriez utiliser runkit dans les cas où vous n'avez pas d'options .. :) – goddva

1

Ceci est un exemple où vous pouvez envisager d'amerrissage méthodes statiques en faveur du polymorphisme. Si vos données mappeur était une interface que vous pourriez alors avoir deux implémentations, l'une pour la base de données et un pour 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

Je suis venu avec un moyen d'intercepter les appels de méthode en PHP - Check it out. C'est juste un exemple basique, et les classes qui veulent être interceptibles doivent "opter" - vous ne pouvez pas interférer avec le comportement des classes qui n'implémentent pas les deux méthodes magiques.

Je ne sais pas si cela répond à vos besoins - mais ce modèle peut être mis en œuvre sans hacks de génération de code ou de l'exécution bytecode, et ça doit être un plus ;-)

Questions connexes