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() 

Очевидно, руткит может вам помочь .

Кроме того, вы всегда можете сделать это способом 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! 

Это все, что у меня есть на данный момент, это довольно полезно во многих случаях, и вы можете даже обернуть их несколько раз, если захотите.