PHP equivalent for a python decorator?

我怕爱的太早我们不能终老 提交于 2019-11-30 06:56:07

Apparently runkit might help you.

Also, you can always do this the OO way. Put the original fun in a class, and the decorator into an extended class. Instantiate and go.

Here is my method of mimicking decorators from python in 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');

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.

knittl

maybe you’re looking for 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:

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?

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.

In 5.3, you can create an anonymous function and store it in a variable:

<?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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!