Я хочу, чтобы иметь возможность обернуть функцию 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()
Очевидно, руткит может вам помочь .
Кроме того, вы всегда можете сделать это способом OO. Поместите оригинальное удовольствие в класс, а декоратор – в расширенный класс. Создавайте и отправляйтесь.
возможно, вы ищете 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());
после того, как вы отредактировали свой вопрос, я бы сказал, нет, это невозможно, но есть некоторые способы, посмотрите на этот вопрос: как реализовать декоратор в PHP?
Вы не можете сделать это с помощью функций в PHP. В других динамических языках, таких как Perl и Ruby, вы можете переопределить ранее определенные функции, но PHP выдает фатальную ошибку при попытке сделать это.
В 5.3 вы можете создать анонимную функцию и сохранить ее в переменной:
<?php $my_function = function($args, ...) { ... }; $copy_of_my_function = $my_function; $my_function = function($arg, ...) { /* Do something with the copy */ }; ?>
Кроме того, вы можете использовать традиционный узор декоратора и / или фабрику и вместо этого работать с классами.
Вот мой метод подражания декораторам из python в php.
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!
Это все, что у меня есть на данный момент, это довольно полезно во многих случаях, и вы можете даже обернуть их несколько раз, если захотите.