代码之家  ›  专栏  ›  技术社区  ›  Fragsworth

php相当于python修饰器?

  •  11
  • Fragsworth  · 技术社区  · 17 年前

    我希望能够用另一个函数包装一个PHP函数,但保持其原始名称/参数列表不变。

    例如:

    function A() {
        print "inside A()\n";
    }
    
    function Wrap_A() {
        print "Calling A()\n";
        A();
        print "Finished calling A()\n";
    }
    
    // <--- Do some magic here (effectively "A = Wrap_A")
    
    A();
    

    输出:

    Calling A()
    inside A()
    Finished calling A()
    
    4 回复  |  直到 10 年前
        1
  •  7
  •   Zed    17 年前

    显然 runkit 可以 help you .

    另外,你也可以用OO的方式来做这个。把原来的乐趣放在课堂上,把装饰师放在一个扩展的课堂上。实例化并执行。

        2
  •  3
  •   Devin McBeth    10 年前

    下面是我用PHP从Python模仿装饰器的方法。

    function call_decorator ($decorator, $function, $args, $kwargs) {
    
        // Call the decorator and pass the function to it
        $decorator($function, $args, $kwargs);
    }
    
    function testing ($args, $kwargs) {
        echo PHP_EOL . 'test 1234' . PHP_EOL;
    }
    
    function wrap_testing ($func, $args, $kwargs) {
    
        // Before call on passed function
        echo 'Before testing';
    
        // Call the passed function
        $func($args, $kwargs);
    
        // After call on passed function
        echo 'After testing';
    }
    
    // Run test
    call_decorator('wrap_testing', 'testing');
    

    输出:

    Before testing
    testing 1234
    After testing
    

    使用此实现,您还可以对匿名函数执行类似的操作:

    // Run new test
    call_decorator('wrap_testing', function($args, $kwargs) {
        echo PHP_EOL . 'Hello!' . PHP_EOL;
    });
    

    输出:

    Before testing
    Hello!
    After testing
    

    最后,如果你愿意的话,你甚至可以这样做。

    // Run test
    call_decorator(function ($func, $args, $kwargs) {
        echo 'Hello ';
        $func($args, $kwargs);
    }, function($args, $kwargs) {
        echo 'World!';
    });
    

    输出:

    Hello World!
    

    有了上面的构造,如果需要的话,可以将变量传递给内部函数或包装器。下面是一个匿名内部函数的实现:

    $test_val = 'I am accessible!';
    
    call_decorator('wrap_testing', function($args, $kwargs){
        echo $args[0];
    }, array($test_val));
    

    如果没有匿名函数,它的工作原理将完全相同:

    function test ($args, $kwargs) {
        echo $kwargs['test'];
    }
    
    $test_var = 'Hello again!';
    
    call_decorator('wrap_testing', 'test', array(), array('test' => $test_var));
    

    最后,如果需要修改包装器或包装器中的变量,只需通过引用传递变量。

    无参考:

    $test_var = 'testing this';
    call_decorator(function($func, $args, $kwargs) {
        $func($args, $kwargs);
    }, function($args, $kwargs) {
        $args[0] = 'I changed!';
    }, array($test_var));
    

    输出:

    testing this
    

    参考文献:

    $test_var = 'testing this';
    call_decorator(function($func, $args, $kwargs) {
        $func($args, $kwargs);
    }, function($args, $kwargs) {
        $args[0] = 'I changed!';
    
    // Reference the variable here
    }, array(&$test_var));
    

    输出:

    I changed!
    

    这就是我现在所拥有的,它在很多情况下非常有用,如果你想的话,你甚至可以把它们包装多次。

        3
  •  1
  •   Community Mohan Dere    9 年前

    也许你在找 call_user_func_array :

    function wrapA() {
      $args = func_get_args();
      return call_user_func_array('A', $args);
    }
    

    既然php 5.3,你甚至可以说:

    return call_user_func_array('A', func_get_args());
    

    在你编辑完你的问题之后,我会说,不,这是不可能的,但是有一些方法,请看这个问题: how to implement a decorator in PHP?

        4
  •  1
  •   Charles    17 年前

    用PHP中的函数不能这样做。在其他动态语言中,比如Perl和Ruby,您可以重新定义以前定义的函数,但是当您尝试这样做时,PHP会抛出一个致命的错误。

    在5.3中,可以创建 anonymous function 并将其存储在变量中:

    <?php
        $my_function = function($args, ...) { ... };
        $copy_of_my_function = $my_function;
        $my_function = function($arg, ...) { /* Do something with the copy */ };
    ?>
    

    或者,您可以使用传统的装饰器模式和/或工厂并使用类。