PHP 5中的方法拦截。*

时间:2010-04-22 19:59:09

标签: php interceptor xml-parsing

我正在为PHP实现一个Log系统,我有点卡住了。

所有配置都在XML文件中定义,该文件声明要记录的每个方法。 XML被很好地解析并转换为多维数组(classname => array of methods)。到目前为止,非常好。

我们举一个简单的例子:

#A.php
class A {
    public function foo($bar) {
        echo ' // Hello there !';
    }

public function bar($foo) {
    echo " $ù$ùmezf$z !";
}
}

#B.php
class B {
public function far($boo) {
    echo $boo;  
}
}

现在,假设我有这个配置文件:

<interceptor>
<methods class="__CLASS_DIR__A.php">
        <method name="foo">
    <log-level>INFO</log-level>
    <log-message>Transaction init</log-message>
        </method>
</methods>  
<methods class="__CLASS_DIR__B.php">
        <method name="far">
    <log-level>DEBUG</log-level>
    <log-message>Useless</log-message>
        </method>
</methods>
</interceptor>

我想要 AT RUNTIME ON (一旦XML解析器完成了他的工作)就是:

#Logger.php (its definitely NOT a final version) -- generated by the XML parser
class Logger {
public function __call($name,$args) {
    $log_level = args[0];
    $args = array_slice($args,1);
    switch($method_name) {
        case 'foo':
        case 'far':
        //case .....
            //write in log files
            break;

    }
    //THEN, RELAY THE CALL TO THE INITIAL METHOD
 }
}

    #"dynamic" A.php
class A extends Logger {
    public function foo($log_level, $bar) {
    parent::foo($log_level, $bar);
        echo ' // Hello there !';
    }

public function bar($foo) {
    echo " $ù$ùmezf$z !";
}
}

#"dynamic" B.php
class B extends Logger {
public function far($log_level, $boo) {
    parent::far($log_level, $bar);
    echo $boo;  
}
}

这里的一大挑战是,一旦XML解析器完成其工作,就将A和B转换为“动态”版本。

理想的做法是在不修改A和B的代码(我的意思是在文件中)的情况下实现这一点 - 或者至少在程序完成后找到回归原始版本的方法。

要清楚,我想找到最合适的方法来拦截PHP中的方法调用。

您对此有何看法?

PS:当然,客户端代码应该没有后果(如果启用或不启用拦截则没有区别)。

2 个答案:

答案 0 :(得分:0)

您可以使用eval()来实际定义类,但要非常小心eval()函数可能非常危险。

这样的事情:

$parentName = 'Bar';

eval('class Foo extends ' . $parentName . ' { }');

http://php.net/eval

答案 1 :(得分:0)

此解决方案再次使用eval,但我会将其发布以供您考虑,因为我认为这是一种非常好的动态继承方式。

这里的方法是使用一个中间类,它扩展了一些可以改变的默认类(在这个例子中是一个不同的类,也扩展了默认类)。

我不确定你的设置中是什么,不允许这种工作 - 如果你澄清这个我可以提供更好的推荐。

<?php

/*
 * One of the following classes will be the superclass of the Child
 */

class Ancestor {
    function speak() {
        echo 'Ancestor <br />';
    }
}

class Mum extends Ancestor {
    function speak() {
        parent::speak();
        echo 'Mum <br />';
    }
}

class Dad extends Ancestor {
    function speak() {
        parent::speak();
        echo 'Dad <br />';
    }
}

/*
 * Decide on which class we wish to make the superclass of our Child
 */

$parentClass = null;

if (isset($_GET['parent'])) {
    $parentClass = $_GET['parent'];
    if (!class_exists($parentClass)) {
        $parentClass = "Ancestor";
    }
}

if (!is_null($parentClass)) {
    eval("class ChildParent extends $parentClass {};");
} else {
    class ChildParent extends Ancestor {};
}

if (class_exists('ChildParent')) {
class Child extends ChildParent
{
    function speak() {
        parent::speak();
        echo 'Child <br />';
    }
}
}

/*
 * Show what's going on
 */

echo '<a href="?">Either</a> | <a href="?parent=Mum">Mum</a> | <a href="?parent=Dad">Dad</a> <br />';

$child = new Child();
$child->speak();*