How to create a callback function that has multiple callback functions from an array:
$fn = function() { echo '1';};
$fn2 = function() { echo '2';};
$array = [
$fn,
$fn2
];
$callback = ... $array; // Calls first $fn then $fn2.
Bigger context:
I am using some library where some class has a callback function as a property, this refers to a function that can be executed before the actual operation.
public function before(callable $fn)
{
$this->before = $fn;
return $this;
}
By default, for my work, I fill it with a certain function, so you can’t add another one.
Due to the fact that the class has $this->before
and few key methods privately created, I am not able to overwrite by my own classes and I unfortunately it is a third-party library and I can’t make changes to it
I came up with the idea of overriding the class and the main method that is used to set this callback so that my class will have an array, and at the point of adding the callback function before calling the parent, I will create one callback function from all the functions added to the array.
/**
* @var callable[]
*/
private array $beforeCallbacks = [];
public function before(callable $fn): ChildrenClass
{
$this->beforeCallbacks[] = $fn;
foreach ($this->beforeCallbacks as $callback) {
if (!isset($newCallback)) {
$newCallback = $callback;
}
$newCallback .= $callback; // As you can guess, it doesn't work:C
}
return parent::before($newCallback);
}
Any suggestions?
I wonder if that’s even possible.
And what if I wanted to inject a parameter into each function, is there any way to handle this?
2
Answers
I found a solution:
will display:
One option is to wrap your callbacks in a structure that can handle calling multiple and in the order you want. The version below uses
__invoke
but you could do whatever callable syntax for PHP that you want.edit
Yes, arguments can be passed. One option is to use
...
to pass things throughDemo: https://3v4l.org/TGdJq
func_get_args
could also be used in a similar fashionedit 2
The magic
__invoke
can be skipped, too, if you’d rather have a more explicit method to call. You could then use[$mc, 'invoke']
or the more modern$mc->invoke(...)
syntax.Demo: https://3v4l.org/Zd1De#v8.2.2