9

私はSOや他の場所で読んでいますが、決定的なものを見つけることができないようです.

以下の例で説明されているように、この呼び出しスタックを介して参照を効果的に実行し、目的の機能を実現する方法はありますか? 例はそれを解決しようとはしませんが、確かに問題を示しています:

class TestClass{
    // surely __call would result similarly
    public static function __callStatic($function, $arguments){
        return call_user_func_array($function, $arguments);
    }
}

// note argument by reference
function testFunction(&$arg){
    $arg .= 'bar';
}

$test = 'foo';
TestClass::testFunction($test);

// expecting: 'foobar'
// getting:   'foo' and a warning about the reference
echo $test;

潜在的な解決策を提示するために、ここに要約の詳細を追加します。

のみに焦点を当てるとcall_user_func_array()、(少なくとも PHP 5.3.1では) 暗黙的に引数を参照渡しできないことがわかります。

function testFunction(&$arg){
    $arg .= 'bar';
}

$test = 'foo';
call_user_func_array('testFunction', array($test));
var_dump($test);
// string(3) "foo" and a warning about the non-reference parameter

配列要素$testを参照として明示的に渡すことで、これを軽減できます。

call_user_func_array('testFunction', array(&$test));
var_dump($test);
// string(6) "foobar"

を使用してクラスを導入すると__callStatic()、参照による明示的な呼び出し時パラメーターが期待どおりに実行されるように見えますが、非推奨の警告が (私の IDE で) 発行されます。

class TestClass{
    public static function __callStatic($function, $arguments){
        return call_user_func_array($function, $arguments);
    }
}

function testFunction(&$arg){
    $arg .= 'bar';
}

$test = 'foo';
TestClass::testFunction(&$test);
var_dump($test);
// string(6) "foobar"

で参照演算子を省略すると、TestClass::testFunction()結果として$testに値渡しされます。__callStatic()もちろん、 は配列要素としてtestFunction()viaに値渡しされますcall_user_func_array()testFunction()は参照を想定しているため、警告が発生します。

ハッキングすると、いくつかの追加の詳細が明らかになりました。__callStatic()定義が参照によって返されるように記述されている場合 ( ) public static function &__callStatic()、目に見える効果はありません。さらに、$arguments配列の要素を__callStatic()参照として再キャストするとcall_user_func_array()、期待どおりに動作することがわかります。

class TestClass{
    public static function __callStatic($function, $arguments){
        foreach($arguments as &$arg){}
        call_user_func_array($function, $arguments);
        var_dump($arguments);
        // array(1) {
        //   [0]=>
        //   &string(6) "foobar"
        // }
    }
}

function testFunction(&$arg){
    $arg .= 'bar';
}

$test = 'foo';
TestClass::testFunction($test);
var_dump($test);
// string(3) "foo"

$test参照によって渡されなくなったため、これらの結果は予期されたものであり、変更はそのスコープに戻されません。ただし、これcall_user_func_array()は実際に期待どおりに機能していること、および問題が呼び出しマジックに限定されていることを確認しています。

さらに読むと、PHP のユーザー関数の処理と__call()/__callStatic()マジックの「バグ」である可能性があります。既存の問題または関連する問題についてバグ データベースを調べたところ、1 つ見つかりましたが、再度見つけることができませんでした。別のレポートを発行するか、既存のレポートの再開を要求することを検討しています。

4

4 に答える 4

3

これは楽しいものです。

TestClass::testFunction(&$string);

これは機能しますが、call-time-pass-by-reference警告もスローします。

主な問題は、__callStaticの2番目の引数が値で入力されることです。そのデータがすでに参照されていない限り、データのコピーを作成しています。

したがって、呼び出しエラーを複製できます。

call_user_func_array('testFunction', array( $string ));
// PHP Warning:  Parameter 1 to testFunction() expected to be a reference, value given

call_user_func_array('testFunction', array( &$string ));
echo $string;
// 'helloworld'

参照によって配列を深くコピーするようにメソッドを変更しようとしまし__callStaticたが、それも機能しませんでした。

によって引き起こされた即時コピーがここでキラーになることは間違いあり__callStaticません。構文的に少しステッカーにするのに十分なフープジャンプがないと、これを行うことはできません。

于 2011-04-09T03:53:01.690 に答える
0

うわー、1時間以上頭を悩ませた後でも、まだよくわかりませんが...

mixed call_user_func_array ( callback $function , array $param_arr )

クラスが関数call_user_func_array()を呼び出すときに(この状況で)単純なロジックを使用すると、静的文字列がパラメーターとして使用されます(マジックメソッドによって渡されます__callStatic())。そのため、パラメーター 2 は関数の目には文字列でcall_user_func_array()あり、そのパラメーターは関数のパラメーター 1 でもありますtestFunction()。変数へのポインターではなく、単に文字列であり、おそらく次のようなメッセージの理由です。

Warning: Parameter 1 to testFunction() expected to be a reference, value given in ... on line ...

つまり、存在しない変数に値を割り当てることはできませんが、 testFunction() はパラメーターが参照であると想定し、そうでないため警告をスローします。

次のようにクラス外でテストできます。

function testFunction(&$arg){
    $arg .= 'world';
  }

$string = 'hello';
call_user_func_array('testFunction', array($string));
echo $string;

同じ警告をスローします!したがって、問題はクラスではなく、問題はこの関数です。

この関数は明らかに、変数を指すことなく関数パラメーターを静的データとして渡します。関数が呼び出す関数は、参照された引数を処理できません。

于 2011-04-09T04:32:29.950 に答える