5

私は機能を持っています:

$query = "SELECT * from lol";
database_query( $query );

$querydatabase_query関数内でが変更されることは決してないことを考えると、$query渡された値の新しい反復に関数がより多くのメモリを割り当てる必要がないように、へのポインタを使用することをお勧めしますか?

function database_query( &$query ){
    //do stuff that does not affect $query
}
4

3 に答える 3

6

いいえ、これを行わないでください。PHPは、非参照渡しパラメーターの値が関数内で変更された場合にのみ、文字列の別のコピーを作成します(「コピーオンライト」)。パラメータを参照にすることで、コードを読んでいる人に、関数が実行していることについて間違った印象を与える理由はありません。

また、参照はポインタではありません

于 2012-12-12T12:43:24.207 に答える
1

の値$queryは文字列です。文字列には内部の可変状態がありません。PHPで文字列を含む変数を「変更」する唯一の方法は、新しい文字列を割り当てる(または、関数を参照して新しい文字列を割り当てる)ことです。など)。したがって、$foo = $query;そうすると、実際の文字は変更できないため、適切な実装では、ポインタを内部文字配列にコピーするだけで、実際の文字はコピーされません。したがって、PHPにコピーオンライトがあることを知らなかったとしても、値で文字列を渡すのは費用がかからないと結論付けることができます。

于 2012-12-12T21:14:13.367 に答える
-2

これは非常に興味深い質問であることがわかりました。私はこの1時間半、PHPとそれが参照を処理する方法について読みました(私を始めたリンクをありがとうTim Cooper)。

あなたの質問に答えるには、そうです-関数を呼び出すときは、そのような参照を使用することをお勧めします。参照を使用することで、使用するリソースが少なくなります。参照変数の「コピーオンライト」はありません。ここにいくつかの証拠があります:

<?php
function noref_nowrite($var_a){
    echo '<h3>NOT Using a Reference/Not Changing Data</h3>';
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>';
    echo '<p>'. debug_zval_dump($var_a) .'</p>';
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>';
}
function noref_write($var_a){
    $var_a++;
    echo '<h3>NOT Using a Reference/Changing Data</h3>';
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>';
    echo '<p>'. debug_zval_dump($var_a) .'</p>';
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>';
}

function ref_nowrite(&$var_a){
    echo '<h3>Using a Reference/Not Changing Data</h3>';
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>';
    echo '<p>'. debug_zval_dump($var_a) .'</p>';
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>';
}
function ref_write(&$var_a){
    $var_a++;
    echo '<h3>Using a Reference/Changing Data</h3>';
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>';
    echo '<p>'. debug_zval_dump($var_a) .'</p>';
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>';
}

$a = 5;
noref_nowrite($a);
noref_write($a);
ref_nowrite($a);
ref_write($a);
?>

上記のコードをコピーしてPHPページに貼り付けて実行すると、次のように表示されます。

NOT Using a Reference/Not Changing Data
var_a: (refcount=3, is_ref=0)=5
long(5) refcount(4)

$var_a = 5 and $GLOBALS[a] = 5


NOT Using a Reference/Changing Data
var_a: (refcount=1, is_ref=0)=6
long(6) refcount(2)
$var_a = 6 and $GLOBALS[a] = 5

Using a Reference/Not Changing Data
var_a: (refcount=3, is_ref=1)=5
long(5) refcount(1)
$var_a = 5 and $GLOBALS[a] = 5

Using a Reference/Changing Data
var_a: (refcount=3, is_ref=1)=6
long(6) refcount(1)
$var_a = 6 and $GLOBALS[a] = 6

つまり、ここにあるのは4つの基本的なテストです。グローバル変数($ a)を作成し、それに値5を割り当てます。

noref_nowrite関数を呼び出すと、XDebugは3つの参照をカウントし、PHPの組み込み関数は4をカウントすることがわかります。興味深いことに、PHPはこれを最適化するため、PHPは$var_aを$GLOBALS ['a']に参照するため、内部的にはref_nowrite関数を呼び出すのと同じです。 。

noref_write関数を呼び出すと、refcountが1(または、PHPの組み込み関数を見ると2)に低下していることがわかります。なんで?これは、「コピーオンライト」の問題が発生する場所だからです。$ var_aをインクリメントするまで、PHPは内部で$var_aを$aへの参照として使用していましたが、値を変更すると、PHPに変数のコピーを作成させて、インクリメントできるようにしました。そのため、その時点で$var_aは$aへの参照ではなくなり、代わりに独自のデータを参照するように変更されました。

ref_nowrite関数はあいまいな結果を示します。それだけを見ると、何も証明できません。ただし、ref_write関数は、XDebugが参照変数(is_ref = 1)を処理していることを示し、最も重要なことは、$ var_aをインクリメントした後、グローバル変数$aの値も変更されたことを示しています。これは$var_aと$GLOBALS['a']は間違いなくメモリ内の同じ場所を指しています。つまり、$ var_aを変更しても、「コピーオンライト」の状況はトリガーされませんでした。参照を処理しているため、トリガーされるべきではありません。

これをいじって自分を納得させてください。

PHP変数が参照/参照されているかどうかを検出する(ircmaxellにはよく考えられた答えがあると思いました)

http://us2.php.net/debug-zval-dump

XDebugのドキュメント: http: //xdebug.org/docs/display

PHPリファレンスの機能:http://us3.php.net/manual/en/language.references.whatdo.php

PHP参照カウントの基本:http://us3.php.net/manual/en/features.gc.refcounting-basics.php

于 2012-12-12T16:03:48.273 に答える