3

我的方法的签名如下所示:

public function ProgramRuleFilter(&$program, $today=null) {

当我这样调用它时,

$programs = array_filter($programs, array($this,'ProgramRuleFilter'));

一切都按预期工作。该ProgramRuleFilter方法更新$program数组,然后如果成功过滤则返回真/假$programs

但是,现在我想向过滤器传递一个额外的参数,$today. 我怎样才能做到这一点?

我试图像这样调用它:

$programs = array_filter($programs, new CallbackArgs(array($this,'ProgramRuleFilter'),$today));

使用这个小类作为包装器:

class CallbackArgs {
    private $callback;
    private $args;

    function __construct() {
        $args = func_get_args();
        $this->callback = array_shift($args);
        $this->args = $args;
    }

    function __invoke(&$arg) {
        return call_user_func_array($this->callback, array_merge(array($arg),$this->args));
    }
}

但是程序没有被更新,所以在某处它丢失了对原始对象的引用。我不知道如何解决这个问题。

4

2 回答 2

10

的第二个参数array_filter必须是回调;这意味着它array_filter本身将调用您的过滤器函数。没有办法告诉array_filter以任何其他方式调用该函数,因此您需要找到一种方法以$today其他方式将值导入您的函数。

这是何时使用闭包的完美示例,它可以让您将一些数据(在本例中为 的值$today)绑定到函数/回调中。假设您使用的是 PHP 5.3 或更高版本:

// Assuming $today has already been set

$object = $this; // PHP 5.4 eliminates the need for this
$programs = array_filter( $programs, function( $x ) use ( $today, $object ){
    return $object->ProgramRuleFilter( $x, $today );
});

这定义了一个闭包内联,使用父作用域的值$today$object来自父作用域的值,然后只调用ProgramRuleFilter该 $object 上的现有函数。(有点不寻常$object = $this的是,否则闭包将无法调用对象实例上的方法。但在 PHP 5.4 中,您可以在闭包内替换为。$object$this

现在,这是一种不太优雅的方法,因为这个闭包所做的只是将工作交给ProgramRuleFilter函数。更好的方法是使用闭包而不是函数。所以:

// Assuming $today has already been set

$filter = function( $x ) use ( $today ){
    // Cut and paste the contents of ProgramRuleFilter() here,
    // and make it operate on $x and $today
};
$programs = array_filter( $programs, $filter );

哪种变体最适合您将取决于应用程序其余部分的实现。祝你好运!

于 2012-04-20T17:11:27.607 回答
1

我写了一个新方法来处理它:

public static function array_filter_args($array, $callback) {
    $args = array_slice(func_get_args(),2);
    foreach($array as $key=>&$value) {
        if(!call_user_func_array($callback, array_merge(array(&$value),$args))) {
            unset($array[$key]);
        }
    }
    return $array;
}

像这样调用:

$programs = ArrayHelper::array_filter_args($programs, array($this,'ProgramRuleFilter'), $today);

我不知道你能做到这一点array(&$value),但我想我会尝试一下,它看起来很有效。我猜这array_merge是取消引用变量的罪魁祸首。

于 2012-04-20T17:11:30.933 回答