変数が相互に参照している場合(これは基本的にチェックしたいものです)、それらは同じzvalを使用します。したがって、これは少し厄介ですが、うまくいくでしょう、それを行う方法:
<?php
function vars_are_referenced (&$var1, &$var2) {
// What we are doing *will* throw an error (I said it was nasty ;-) )
$oldER = error_reporting();
$oldDE = ini_get('display_errors');
error_reporting(0);
ini_set('display_errors', 0);
// We need to use output buffering, we don't want to break any existing
// buffering so we cache the contents of the buffer
$oldBuffer = ob_get_length() ? ob_get_clean() : NULL;
// If the values are not identical, definitely not a match
if ($var1 !== $var2) return FALSE;
// Now we inspect the zval of $var1
ob_start();
debug_zval_dump(&$var1);
preg_match('/\brefcount\((\d+)\)(?:\b|$)/', ob_get_clean(), $matches);
$var1RefCountBefore = (int) $matches[1];
// If they are the same, this will increase the refcount
$temp = &$var2;
// Inspect the zval of $var1 again
ob_start();
debug_zval_dump(&$var1);
preg_match('/\brefcount\((\d+)\)(?:\b|$)/', ob_get_clean(), $matches);
$var1RefCountAfter = (int) $matches[1];
// If refcount is now greater, they are the same
$result = $var1RefCountAfter > $var1RefCountBefore;
// Repopulate the output buffer if necessary
if ($oldBuffer !== NULL) {
ob_start();
echo $oldBuffer;
}
// Turn error reporting back to correct level
error_reporting($oldER);
ini_set('display_errors', $oldDE);
return $result;
}
function test_ref_fail () {
$a = 1;
$var_name = 'a';
var_dump(vars_are_referenced($GLOBALS['a'], $a));
}
function test_ref_success_1 () {
global $a;
$var_name = 'a';
var_dump(vars_are_referenced($GLOBALS['a'], $a));
}
function test_ref_success_2 (&$a) {
$var_name = 'a';
var_dump(vars_are_referenced($GLOBALS['a'], $a));
}
$a = 1;
$b = &$a;
var_dump(vars_are_referenced($a, $b));
test_ref_fail();
test_ref_success_1();
test_ref_success_2($a);
これは(zvalを調べることによって)それを行うための最良の方法ですが、あなたが見ることができると確信しているように、これは現在PHPで利用可能な関数を備えたきれいな方法ではありません。必要に応じて動作させるために必要な呼び出し時の参照渡しが原因で、エラーが発生debug_zval_dump()
します。呼び出し時の参照渡しが削除されたため、PHP>=5.4で致命的なエラーが発生します。
ですから、これは別の方法です-変数の変更が含まれるため、私は好きではありませんが、何も壊してはならず、重要なことに、エラーが発生することはなく、どこでも機能します:
<?php
function vars_are_referenced (&$var1, &$var2) {
// If the values are not identical, definitely not a match
if ($var1 !== $var2) return FALSE;
// Make a copy of the old value
$oldVal = $var1;
// Get a new value we can assign that is different to the old value
$newVal = ($oldVal === 1) ? 2 : 1;
// Assign the value to $var1
$var1 = $newVal;
// See if $var2 has changed
$result = $var1 === $var2;
// Put the value of $var1 right again
$var1 = $oldVal;
return $result;
}
vars_are_referenced()
文字列としての変数の名前と変数自体に基づいて、変数がグローバルであるかどうかを具体的に判断するためのヘルパー関数(上記の定義のいずれかで機能します)を次に示します。
<?php
function var_is_global ($name, &$var) {
return vars_are_referenced($GLOBALS[$name], $var);
}
任意の変数がオブジェクトのコンテキスト外で静的であるかどうかを正確にチェックする方法を考えることはできません。