Python 装饰器的 PHP 等价物?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1425303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP equivalent for a python decorator?
提问by Fragsworth
I want to be able to wrap a PHP function by another function, but leaving its original name/parameter list intact.
我希望能够用另一个函数包装 PHP 函数,但保持其原始名称/参数列表不变。
For instance:
例如:
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();
Output:
输出:
Calling A()
inside A()
Finished calling A()
采纳答案by Zed
回答by Dbeazy
Here is my method of mimicking decorators from python in php.
这是我在 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');
Output:
输出:
Before testing
testing 1234
After testing
With this implementation you can also do something like this with an anonymous function:
使用此实现,您还可以使用匿名函数执行以下操作:
// Run new test
call_decorator('wrap_testing', function($args, $kwargs) {
echo PHP_EOL . 'Hello!' . PHP_EOL;
});
Output:
输出:
Before testing
Hello!
After testing
And lastly you can even do something like this, if you are so inclined.
最后,如果您愿意,您甚至可以做这样的事情。
// Run test
call_decorator(function ($func, $args, $kwargs) {
echo 'Hello ';
$func($args, $kwargs);
}, function($args, $kwargs) {
echo 'World!';
});
Output:
输出:
Hello World!
With this construction above, you can pass variables to the inner function or wrapper, if need be. Here is that implementation with an anonymous inner function:
使用上面的这种构造,您可以将变量传递给内部函数或包装器,如果需要的话。这是具有匿名内部函数的实现:
$test_val = 'I am accessible!';
call_decorator('wrap_testing', function($args, $kwargs){
echo $args[0];
}, array($test_val));
It will work exactly the same without an anonymous function:
如果没有匿名函数,它将完全相同:
function test ($args, $kwargs) {
echo $kwargs['test'];
}
$test_var = 'Hello again!';
call_decorator('wrap_testing', 'test', array(), array('test' => $test_var));
Lastly, if you need to modify the variable inside either the wrapper or the wrappie, you just need to pass the variable by reference.
最后,如果您需要修改包装器或包装器中的变量,您只需要通过引用传递变量。
Without reference:
没有参考:
$test_var = 'testing this';
call_decorator(function($func, $args, $kwargs) {
$func($args, $kwargs);
}, function($args, $kwargs) {
$args[0] = 'I changed!';
}, array($test_var));
Output:
输出:
testing this
With reference:
供参考:
$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));
Output:
输出:
I changed!
That is all I have for now, it is a pretty useful in a lot of cases, and you can even wrap them multiple times if you want to.
这就是我现在所拥有的,它在很多情况下都非常有用,如果您愿意,您甚至可以将它们包装多次。
回答by knittl
maybe you're looking for call_user_func_array
:
也许您正在寻找call_user_func_array
:
function wrapA() {
$args = func_get_args();
return call_user_func_array('A', $args);
}
since PHP 5.3 you could even say:
自 PHP 5.3 起,您甚至可以说:
return call_user_func_array('A', func_get_args());
after you've edited your question i would say, no, this is not possible, but there are some ways, see this question: how to implement a decorator in PHP?
在你编辑你的问题后,我会说,不,这是不可能的,但有一些方法,请参阅这个问题:如何在 PHP 中实现装饰器?
回答by Charles
You can't do this with functions in PHP. In other dynamic languages, such as Perl and Ruby, you can redefine previously defined functions, but PHP throws a fatal error when you attempt to do so.
你不能用 PHP 中的函数来做到这一点。在其他动态语言中,例如 Perl 和 Ruby,您可以重新定义以前定义的函数,但是当您尝试这样做时 PHP 会抛出致命错误。
In 5.3, you can create an anonymous functionand store it in a variable:
在 5.3 中,可以创建匿名函数并将其存储在变量中:
<?php
$my_function = function($args, ...) { ... };
$copy_of_my_function = $my_function;
$my_function = function($arg, ...) { /* Do something with the copy */ };
?>
Alternatively, you can use the traditional decorator pattern and/or a factory and work with classes instead.
或者,您可以使用传统的装饰器模式和/或工厂并使用类来代替。
回答by Ali Amjid
You can use Aspect Oriented Programming. But you need some framework that support AOP.
您可以使用面向方面的编程。但是您需要一些支持 AOP 的框架。
For example Symfony. This is one of implementations of AOP for php https://github.com/goaop/goaop-symfony-bundle
例如Symfony。这是 php 的 AOP 实现之一 https://github.com/goaop/goaop-symfony-bundle
There is also the Nette Framework (I use this one)
还有 Nette 框架(我用的是这个)
In principle it works like this: let's say you want to throw an exception if user is not logged in and tries to access some method.
原则上它是这样工作的:假设您想在用户未登录并尝试访问某个方法时抛出异常。
This is just "fictive"code to show how it works.
这只是展示其工作原理的“虚构”代码。
You have some aspect method like this:
你有一些像这样的方面方法:
/** @AroundMethod(annotataion="isUserLogged()") */
public function checkUser(Method $method) {
if ($this->user->isLogged()) {
return $method->call();
} else {
throw new \Exception('User must be logged');
}
}
And then you can use the annotation @isUserLogged
in your services which will be probably registered in some DI container.
然后您可以@isUserLogged
在您的服务中使用该注解,该注解可能会在某个 DI 容器中注册。
/**
* @isUserLogged()
*/
public function changeUserInfo() {
}