我希望能够通过另一个函数包装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 :(得分:7)
答案 1 :(得分:3)
这是我在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!
这就是我现在所拥有的,在很多情况下它非常有用,如果你愿意,你甚至可以多次包装它们。
答案 2 :(得分: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?
答案 3 :(得分: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 */ };
?>
或者,您可以使用传统的装饰器模式和/或工厂,而不是使用类。
答案 4 :(得分:0)
您可以使用面向方面的编程。但是您需要一些支持AOP的框架。
例如 Symfony 。 这是AOP for php的实现之一 https://github.com/goaop/goaop-symfony-bundle
还有Nette框架(我使用this one)
原则上它是这样的:假设您要在用户未登录并尝试访问某些方法时抛出异常。
这只是“虚拟” 代码,以显示其工作原理。
您有一些类似的方面方法:
import React from 'react';
import styled from 'styled-components';
export const DivMenuButton = styled.div`
border: 0px;
background-color: #000; // was wrong syntax
width: 200px;
height: ${props => props.height}
`;
然后您可以在服务中使用注释/** @AroundMethod(annotataion="isUserLogged()") */
public function checkUser(Method $method) {
if ($this->user->isLogged()) {
return $method->call();
} else {
throw new \Exception('User must be logged');
}
}
,该注释可能已在某些DI容器中注册。
@isUserLogged