I want to be able to wrap a PHP function by another function, but leaving its original name/parameter list intact.
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()
Decorator is a structural pattern that allows adding new behaviors to objects dynamically by placing them inside special wrapper objects, called decorators. Using decorators you can wrap objects countless number of times since both target objects and decorators follow the same interface.
Recall that a decorator is just a regular Python function. All the usual tools for easy reusability are available. Let's move the decorator to its own module that can be used in many other functions. Note: You can name your inner function whatever you want, and a generic name like wrapper() is usually okay.
Needless to say, Python's decorators are incredibly useful. Not only can they be used to slow down the time it takes to write some code, but they can also be incredibly helpful at speeding up code. Not only are decorators incredibly useful when you find them about, but it is also a great idea to write your own.
A Decorator in Python is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. Functions are first-class objects in Python. We can easily decorate a function using the @decorator syntax.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With