Last active
September 23, 2016 03:06
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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