Skip to content

Instantly share code, notes, and snippets.

@srgoogleguy
Last active September 23, 2016 03:06
Show Gist options
  • Save srgoogleguy/5796925 to your computer and use it in GitHub Desktop.
Save srgoogleguy/5796925 to your computer and use it in GitHub Desktop.
Implementation for a PHP function to find out which variables a given variable is currently referencing or referenced by. This function simply compares the zval pointer by iterating the active symbol table as opposed to simply checking the is_ref property of the zval to tell that it's a reference. This means two-way reference detection is possible.
/**
* Find which variables in the current scope reference which other variables.
*
* mixed ref_info ( string $variable_name )
* - Returns an associative array of variable names that are references of the supplied varriable name argument.
* Returns false on failure.
*/
PHP_FUNCTION(ref_info)
{
char *str;
int len;
long long quickhash = 0;
zval *sym, **pptr;;
Bucket *ptrList;
/* The function requires a single argument of type string representative of the symbol name to seek references for */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) {
return;
}
if (!len) {
RETVAL_FALSE;
return;
}
if (!EG(active_symbol_table)) {
zend_rebuild_symbol_table(TSRMLS_C);
}
ptrList = EG(active_symbol_table)->pListHead;
while (ptrList != NULL) {
if (!strcmp(ptrList->arKey, str)) {
quickhash = ptrList->pDataPtr;
}
ptrList = ptrList->pListNext;
}
if (!quickhash) {
RETVAL_FALSE;
return;
}
array_init(return_value);
ptrList = EG(active_symbol_table)->pListHead;
while (ptrList != NULL) {
if (zend_hash_find(EG(active_symbol_table), ptrList->arKey, ptrList->nKeyLength, (void**)&pptr) == SUCCESS) {
sym = *pptr;
} else {
RETVAL_FALSE;
return;
}
if (!sym->is_ref__gc) {
ptrList = ptrList->pListNext;
continue;
} else {
if (quickhash == ptrList->pDataPtr && strcmp(ptrList->arKey, str)) {
add_assoc_string(return_value, ptrList->arKey, str, 1);
}
}
ptrList = ptrList->pListNext;
}
}
<?php
/**
* Usage example
*/
$a = 42;
$b = &$a;
$c = &$a;
$d = &$c;
$z = "foo bar";
var_dump(ref_info('a'),
ref_info('b'),
ref_info('c'),
ref_info('d'),
ref_info('e') /* Undefined variable name will return Boolean false */,
ref_info('z') /* Defined but not a reference will return an empty array */
);
/**
Output
array(3) {
["b"]=>
string(1) "a"
["c"]=>
string(1) "a"
["d"]=>
string(1) "a"
}
array(3) {
["a"]=>
string(1) "b"
["c"]=>
string(1) "b"
["d"]=>
string(1) "b"
}
array(3) {
["a"]=>
string(1) "c"
["b"]=>
string(1) "c"
["d"]=>
string(1) "c"
}
array(3) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "d"
["c"]=>
string(1) "d"
}
bool(false)
array(0) {
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment