Отсутствие препроцессора в C#.
я знаю, что они пропустили его, потому что некоторые люди могут злоупотребить им, но я думаю, что они вывели ребенка с водой в ванне. Генерация кода рассматривается как хорошая вещь, и в C++ препроцессор был моим генератором первого линейного кода.
Вы можете использовать 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, и кажется, что он создает еще одну ссылку где-то на пути ;)
Может быть, xdebug_debug_zval () поможет вам. http://www.xdebug.org/docs/all_functions
Возьмите пик в 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 и опорный флаг. Затем он меняет один, чтобы проверить, если другие изменения (указывая, что они являются той же ссылкой).