26

PHPには、特定の変数が別の変数への参照であるか、別の変数によって参照されているかを判断する方法がありますか?php.netのコメント$a=& $bでは、「$aと$bはここでは完全に等しい。$aは$bを指していないか、逆もまた同様です。$aと$bは同じ場所を指しています。

特定の変数が参照/参照されているかどうかを判断できない場合、2つの変数が相互の参照であるかどうかを判断する一般的な方法はありますか?繰り返しになりますが、php.netのコメントは、そのような比較を行うための関数を提供します。ただし、これは、変数の1つを編集し、他の変数が同様に影響を受けるかどうかを確認する関数です。私が検討している変数のいくつかは魔法のゲッター/セッターを多用しているので、可能であればこれを避けたいと思います。

この場合のリクエストの背景は、構造を詳細に表示するのに役立つデバッグ関数を作成することです。

4

5 に答える 5

8

完全な実例:

function EqualReferences(&$first, &$second){
    if($first !== $second){
        return false;
    } 
    $value_of_first = $first;
    $first = ($first === true) ? false : true; // modify $first
    $is_ref = ($first === $second); // after modifying $first, $second will not be equal to $first, unless $second and $first points to the same variable.
    $first = $value_of_first; // unmodify $first
    return $is_ref;
}

$a = array('foo');
$b = array('foo');
$c = &$a;
$d = $a;

var_dump(EqualReferences($a, $b)); // false
var_dump(EqualReferences($b, $c)); // false
var_dump(EqualReferences($a, $c)); // true
var_dump(EqualReferences($a, $d)); // false
var_dump($a); // unmodified
var_dump($b); // unmodified
于 2013-08-07T17:54:53.703 に答える
7

あなたが使用することができますdebug_zval_dump

function countRefs(&$var) {
    ob_start();
    debug_zval_dump(&$var);
    preg_match('~refcount\((\d+)\)~', ob_get_clean(), $matches);
    return $matches[1] - 4;
}

$var = 'A';
echo countRefs($var); // 0

$ref =& $var;
echo countRefs($var); // 1

ただし、これはPHP 5.4以降では機能しなくなります。これは、参照サポートによって呼び出し時間の経過が削除されE_STRICT、下位バージョンでレベルエラーがスローされる可能性があるためです。

上記の関数のどこから来たのか疑問に思われるかもしれ-4ません:あなたは私に言います...私は試してみてそれを手に入れました。私の目には3つ(変数、関数内の変数、渡される変数zend_debug_zval)だけであるはずですが、PHPの内部はあまり得意ではなく、途中でさらに別の参照が作成されるようです;)

于 2011-01-27T15:00:33.567 に答える
4

たぶんxdebug_debug_zval()があなたを助けます。http://www.xdebug.org/docs/all_functions

于 2011-01-27T14:33:59.933 に答える
1

編集: 私は質問に答えたようです'2つの変数がメモリ内の同じ値を参照しているかどうかを確認することは可能ですか'実際の質問ではありません。:P


'plain'変数に関する限り、答えは'no'です。

オブジェクトに関する限り、多分。

デフォルトでは、すべてのオブジェクトは参照によって処理されます。また、各オブジェクトにはシリアル番号があり、いつでも確認できますvar_dump()

>> class a {};
>> $a = new a();
>> var_dump($a);

object(a)#12 (0) {
}

どういうわけかこの#にたどり着くことができれば、2つの変数について効果的に比較し、それらが同じオブジェクトを指しているかどうかを確認できます。問題は、この番号を取得する方法です。var_export()それを返しません。私もそれを取得するクラスで何も見ていませんReflection

私の頭に浮かぶことの1つは、出力バッファリングと正規表現を使用することです。

于 2011-01-27T14:31:50.900 に答える
1

xdebug_debug_zval()でピークを取ります。今のところ、それが変数のzvalに関するすべてを判断できるかどうかを実際に知る唯一の方法です。

そこで、役立つ情報を決定するためのヘルパー関数をいくつか示します。

function isRef($var) {
    $info = getZvalRefCountInfo($var);
    return (boolean) $info['is_ref'];
}
function getRefCount($var) {
    $info = getZvalRefCountInfo($var);
    return $info['refcount'];
}
function canCopyOnWrite($var) {
    $info = getZvalRefCountInfo($var);
    return $info['is_ref'] == 0;
}
function canReferenceWithoutCopy($var) {
    $info = getZvalRefCountInfo($var);
    return $info['is_ref'] == 1 || $info['refcount'] == 1;
}

function getZvalRefCountInfo($var) {
    ob_start();
    xdebug_debug_zval($var);
    $info = ob_get_clean();
    preg_match('(: \(refcount=(\d+), is_ref=(\d+)\))', $info, $match);
    return array('refcount' => $match[1], 'is_ref' => $match[2]);
}

したがって、いくつかのサンプル変数を使用すると、次のようになります。

$a = 'test';
$b = $a;
$c = $b;
$d =& $c;
$e = 'foo';

変数が参照であるかどうかをテストできます。

isRef('a'); // false
isRef('c'); // true
isRef('e'); // false

zvalにリンクされている変数の数を取得できます(必ずしも参照ではなく、コピーオンライト用にすることができます)。

getRefCount('a'); // 2
getRefCount('c'); // 2
getRefCount('e'); // 1

コピーオンライト(メモリコピーを実行せずにコピー)できるかどうかをテストできます。

canCopyOnWrite('a'); // true
canCopyOnWrite('c'); // false
canCopyOnWrite('e'); // true

そして、zvalをコピーせずに参照を作成できるかどうかをテストできます。

canReferenceWithoutCopy('a'); // false
canReferenceWithoutCopy('c'); // true
canReferenceWithoutCopy('e'); // true

そして今、私たちは変数がいくつかの黒魔術を通してそれ自体を参照しているかどうかをチェックすることができます:

function isReferenceOf(&$a, &$b) {
    if (!isRef('a') || getZvalRefCountInfo('a') != getZvalRefCountInfo('b')) {
        return false;
    }
    $tmp = $a;
    if (is_object($a) || is_array($a)) {
        $a = 'test';
        $ret = $b === 'test';
        $a = $tmp;
    } else {
        $a = array();
        $ret = $b === array();
        $a = $tmp;
    }
    return $tmp;
}

他のどのシンボルが同じzvalを参照しているかを判断できないため(他のシンボルのみが参照している)、少しハッキーです。したがって、これは基本的に$a、が参照であるかどうか、$aおよび$b両方に同じrefcountと参照フラグが設定されているかどうかを確認します。次に、一方を変更して、もう一方が変更されているかどうかを確認します(同じ参照であることを示します)。

于 2011-10-20T15:15:51.197 に答える