2009-09-15 126 views
7

我希望能够通过另一个函数来包装PHP函数,但保留原来的名称/参数列表不变。python装饰器的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() 
+0

你Wrap_A的例子是有点误导人谁不已经知道如何Python的装饰器的工作,因为你Wrap_A的实施显式地引用A.一个装饰的想法是,你可以装饰任何函数,但在你的例子显然不能使用'Wrap_A'来包装其他一些函数'B'。你介意我是否编辑了你的问题,让它更精确地表示装饰是什么功能? – 2014-01-05 15:11:37

回答

6

显然runkit可能help you

此外,你可以随时做到这一点的方式。把原来的乐趣放在一个类中,并将装饰器放入扩展类中。实例化并去。

+0

谢谢'runkit'正是我一直在寻找。 – Fragsworth 2009-09-15 06:16:48

+1

你将如何使用它一样容易,一般在蟒蛇 - 在这里你添加装饰只是函数定义以上(在.NET和Java见过类似的结构)。 – Michael 2012-04-24 11:32:11

1

也许你正在寻找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?

+0

这是不是在所有涉及到什么我要找的。我编辑了我的问题以添加说明。 – Fragsworth 2009-09-15 06:02:02

1

你不能用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 */ }; 
?> 

或者,你可以使用传统的装饰图案和/或工厂和工作带班来代替。

1

这是我在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)); 

最后,如果您需要修改任何包装或内部变量wrappie,你只需要通过引用传递变量。

在不参考:

$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! 

这就是我的全部,现在,它是一个在很多情况下非常有用,你甚至可以多次包装他们,如果你想。