Определение того, является ли переменная PHP ссылкой / ссылкой

Отсутствие препроцессора в C#.

я знаю, что они пропустили его, потому что некоторые люди могут злоупотребить им, но я думаю, что они вывели ребенка с водой в ванне. Генерация кода рассматривается как хорошая вещь, и в C++ препроцессор был моим генератором первого линейного кода.

24
задан Pacerier 3 April 2015 в 18:58
поделиться

3 ответа

Вы можете использовать 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, и кажется, что он создает еще одну ссылку где-то на пути ;)

6
ответ дан 29 November 2019 в 00:24
поделиться

Может быть, xdebug_debug_zval () поможет вам. http://www.xdebug.org/docs/all_functions

3
ответ дан 29 November 2019 в 00:24
поделиться

Возьмите пик в 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 и опорный флаг. Затем он меняет один, чтобы проверить, если другие изменения (указывая, что они являются той же ссылкой).

1
ответ дан 29 November 2019 в 00:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: