3

私のメソッドの署名は次のようになります。

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

このように呼び出すと、

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

すべてが期待どおりに機能します。このProgramRuleFilterメソッドは配列を更新し、$program正常にフィルタリングされた場合は true/false を返します$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

の 2 番目の引数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 で$object既存の関数を呼び出すだけです。(そうしないと、クロージャーがオブジェクト インスタンスのメソッドを呼び出すことができないという事実を回避するのは、ProgramRuleFilterやや珍しいことです。しかし、PHP 5.4 では、クロージャー内で置き換えることができます。)$object = $this$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 に答える