我有一个静态方法的类,我想在调用方法之前拦截方法调用。
所以,如果我打电话
$model = DataMapper::getById(12345);
然后我希望在调用此方法之前调用DataMapper中的某个方法,然后可选地,此拦截方法可以随后调用self :: getById(12345)。有没有办法做到这一点?
我在我的服务器上实现Memcache,所以这就是我想拦截方法调用的原因。如果模型已经被缓存,我不希望静态方法查询数据库,我也不想冗余地修改数百种不同的映射器方法来支持memcache。
我正在运行PHP 5.2.6。
答案 0 :(得分:1)
这样做了: Triggering __call() in PHP even when method exists
只需将您的静态方法声明为protected
,这样它们就无法在课堂外访问,并获得__callStatic()
魔术方法来调用它们。
修改:哎呀,你需要5.3来做...
答案 1 :(得分:1)
这是一个例子,你可能想要考虑抛弃静态方法以支持多态。如果你的数据映射器是一个接口,那么你可以有两个实现,一个用于数据库,一个用于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
}
答案 2 :(得分:1)
我想出了一种方法来拦截PHP中的方法调用 - Check it out。
这只是一个基本的例子,想要易受影响的类必须“选择加入” - 你不能干扰那些没有实现这两种魔术方法的类的行为。
我不知道这是否符合您的需求 - 但是这种模式可以在没有代码生成或运行时字节码黑客的情况下实现,而且这必须是一个加分; - )
答案 3 :(得分:0)
我猜你可以用runkit创建一些魔法,但你需要从cvs编译扩展,因为最新版本不支持5.2.x
示例:
<?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