简体   繁体   English

拦截对PHP中方法的调用

[英]Intercepting calls to methods in PHP

I have a class with static methods, and I would like to intercept method calls before the methods are called. 我有一个静态方法的类,我想在调用方法之前拦截方法调用。

So if I call 所以,如果我打电话

$model = DataMapper::getById(12345);

then I want some method in DataMapper to be called before this method is called, and then optionally this intercepting method can subsequently call self::getById(12345). 然后我希望在调用此方法之前调用DataMapper中的某个方法,然后可选地,此拦截方法可以随后调用self :: getById(12345)。 Is there a way to do this? 有没有办法做到这一点?

I am implementing Memcache on my server, so that is why I want to intercept method calls. 我正在我的服务器上实现Memcache,所以这就是我想拦截方法调用的原因。 I don't want the static methods to query the database if models are already cached, and I also don't want to have to modify hundreds of different mapper methods, redundantly, to support memcache. 如果模型已经被缓存,我不希望静态方法查询数据库,我也不想冗余地修改数百种不同的映射器方法来支持memcache。

I am running PHP 5.2.6. 我正在运行PHP 5.2.6。

This'd do the job: Triggering __call() in PHP even when method exists 这样做: 即使方法存在,也在PHP中触发__call()

Just declare your static methods as protected so they're inaccessible outside the class and get the __callStatic() magic method to invoke them. 只需将静态方法声明为protected这样它们就无法在类外部访问,并获得__callStatic()魔术方法来调用它们。

Edit: oops, you'll be needing 5.3 to do it... 编辑:哎呀,你需要5.3来做...

This is one example where you might want to consider ditching static methods in favor of polymorphism. 这是一个您可能想要考虑抛弃静态方法以支持多态的示例。 If your data-mapper was an interface then you could have two implementations, one for the database and one for memcache: 如果你的数据映射器是一个接口,那么你可以有两个实现,一个用于数据库,一个用于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
}

I just came up with a way to intercept method calls in PHP - Check it out . 我想出了一种方法来拦截PHP中的方法调用 - 检查出来

It's just a basic example, and classes that want to be interceptible have to "opt in" - you can't interfere with the behavior of classes that don't implement the two magic methods. 这只是一个基本的例子,想要易受影响的类必须“选择加入” - 你不能干扰那些没有实现两种魔术方法的类的行为。

I don't know if this meets your needs - but this pattern can be implemented without code generation or runtime bytecode hacks, and that's gotta be a plus ;-) 我不知道这是否符合您的需求 - 但这种模式可以在没有代码生成或运行时字节码黑客的情况下实现,而且这是一个加分;-)

I guess you could have created some magic with runkit , but you would need to compile the extension from cvs, since the latest version does not support 5.2.x 我想你可以用runkit创建一些魔法,但你需要从cvs编译扩展,因为最新版本不支持5.2.x

Example: 例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM