php 将Callable数组转换为一个Callable

envsm3lx  于 2023-02-11  发布在  PHP
关注(0)|答案(2)|浏览(125)

如何从数组创建具有多个回调函数的回调函数:

$fn = function() { echo '1';};
$fn2 = function() { echo '2';};

$array = [
    $fn,
    $fn2
];

$callback = ... $array; // Calls first $fn then $fn2.

大背景:
我正在使用一些库,其中一些类有一个回调函数作为属性,这是指一个函数,可以在实际操作之前执行。

public function before(callable $fn)
{
    $this->before = $fn;

    return $this;
}

默认情况下,对于我的工作,我用某个函数填充它,所以你不能添加另一个函数。
由于类具有$this->before和一些私有创建的关键方法,我无法用自己的类覆盖,而且不幸的是,它是第三方库,我无法对其进行更改
我想到了重写类和用于设置此回调的main方法的想法,这样我的类将拥有一个数组,并且在调用父类之前添加回调函数时,我将从添加到数组的所有函数中创建一个回调函数。

/**
 * @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); 
}

有什么建议吗?
我想知道这是否可能,如果我想在每个函数中注入一个参数,有什么方法可以解决这个问题吗?

v9tzhpje

v9tzhpje1#

一种选择是将回调封装在一个可以处理多个调用的结构中,并按照您想要的顺序进行。下面的版本使用__invoke,但您可以使用任何您想要的PHP可调用语法。

class MultipleCaller {
    private $callbacks = [];
    public function addCallback(callable $fn) {
        $this->callbacks[] = $fn;
    }
    
    public function __invoke() {
        foreach($this->callbacks as $callback) {
            $callback();
        }
    }
}

$mc = new MultipleCaller();
$mc->addCallback(static function () { echo 1, PHP_EOL; } );
$mc->addCallback(static function () { echo 2, PHP_EOL; } );

$mc();
    • 编辑**

是的,可以传递参数。一个选项是使用...来传递内容

class MultipleCaller {
    private $callbacks = [];
    public function addCallback(callable $fn) {
        $this->callbacks[] = $fn;
    }
    
    public function __invoke(...$args) {
        foreach($this->callbacks as $callback) {
            $callback(...$args);
        }
    }
}

$mc = new MultipleCaller();
$mc->addCallback(static function (...$args) { echo 'Function 1', PHP_EOL, var_dump($args), PHP_EOL; } );
$mc->addCallback(static function (...$args) { echo 'Function 2', PHP_EOL, var_dump($args), PHP_EOL; } );

function doWork(callable $fn, ...$args) {
    $fn(...$args);
}

doWork($mc, 'alpha', 'beta');

演示:https://3v4l.org/TGdJq
func_get_args也可以以类似的方式使用

    • 编辑2**

如果你想调用一个更显式的方法,也可以跳过神奇的__invoke,然后使用[$mc, 'invoke']或更现代的$mc->invoke(...)语法。

<?php

class MultipleCaller {
    private $callbacks = [];
    public function addCallback(callable $fn) {
        $this->callbacks[] = $fn;
    }
    
    public function invoke(...$args) {
        foreach($this->callbacks as $callback) {
            $callback(...$args);
        }
    }
}

$mc = new MultipleCaller();
$mc->addCallback(static function (...$args) { echo 'Function 1', PHP_EOL, var_dump($args), PHP_EOL; } );
$mc->addCallback(static function (...$args) { echo 'Function 2', PHP_EOL, var_dump($args), PHP_EOL; } );

function doWork(callable $fn, ...$args) {
    $fn(...$args);
}

doWork([$mc, 'invoke'], 'alpha', 'beta');
doWork($mc->invoke(...), 'alpha', 'beta');

演示:www.example.comhttps://3v4l.org/Zd1De#v8.2.2

agxfikkp

agxfikkp2#

我找到了解决办法:

$fn = function() { var_dump('First');};
$fn2 = function() { var_dump('Second');};
$fn3 = function() { var_dump(func_get_args());};

$array = [
    $fn,
    $fn2,
    $fn3
];

$callback = function () use ($array) {
    foreach ($array as $fn) {
        $fn(...func_get_args());
    }
};

$callback('Passed parameter');

将显示:

string(5) "First"
string(6) "Second"
array(1) {
  [0]=>
  string(16) "Passed parameter"
}

相关问题