Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.
Popular code excerpts may be moved to "Code Snippets" by the moderators.
So I have been wanting to be able to write my very own variable inspector to blow the lid off of var_dump() or print_r(). These functions, while useful, present data in a very archaic way in my opinion. One of the things that irritates me the most is that when I pass a variable to a dump function, I get the variable data returned, but I can never seem to get the variable name that the data is in. Well, I figured since it wasn't available in PHP core, I'd do it myself.
Side Note: I have a working PHP5 class for this that I am developing. Code for that can be fetched from my blog. As it is in development stage, I would really appreciate no critiquing of it. If you want to suggest features, you may, but it is not ready for critique yet.
<?php
/**
* Gets the name of the variable to be inspected
*
* @param mixed $var A reference to a variable that is to be inspected
* @return string The string name of the variable, or '[name_not_found]' if not found
*/
function get_var_name(&$var)
{
// Before we start, we need to read the data for the var we are checking
// into a temporary var since we need to pass a reference of the var we
// want the name for. Without this, we would actually be working with
// the original variable, screwing things up royally.
$passed = $var;
// Initialize the variable name return variable
$varName = '';
// Now the fun part... we change the value of the variable whose name we
// want to something random (not the number 4 onion)
$var = 'Scarlett_'.rand().'_Johannson';
// Now we loop through the GLOBAL array and see if we find the GLOBAL array
// key that matches this value
foreach ($GLOBALS as $k => $v) {
// If the value of the GLOBAL is the same as the temp value...
if ($v === $var) {
// Then we snag the GLOBAL key and use it as our var name
$varName = $k;
// And since we have it, we no longer need to loop
break;
}
}
// If there was no name found let the app know
if (empty($varName)) {
$varName = '[name_not_found]';
}
// Now change the value of the variable back to its original state
$var = $passed;
// And finally, return it to the app
return $varName;
}
?>
You'd be better off comparing "===" to a new instance of an object since "===" only evaluates to true on objects if the objects are references (which they couldn't be if you use the "new" keyword in your function). Comparing by value has a hole, albeit a narrow one.
<?php
/**
* Gets the name of the variable to be inspected
*
* @param mixed $var A reference to a variable that is to be inspected
* @return string The string name of the variable, or '[name_not_found]' if not found
*/
function get_var_name(&$var)
{
// Before we start, we need to read the data for the var we are checking
// into a temporary var since we need to pass a reference of the var we
// want the name for. Without this, we would actually be working with
// the original variable, screwing things up royally.
$passed = $var;
// Initialize the variable name return variable
$varName = '';
// Now the fun part... we change the value of the variable whose name we
// want to something random (not the number 4 onion)
$var =& new stdClass();
// Now we loop through the GLOBAL array and see if we find the GLOBAL array
// key that matches this value
foreach ($GLOBALS as $k => $v) {
// If the value of the GLOBAL is the same as the temp value...
if ($v === $var) {
// Then we snag the GLOBAL key and use it as our var name
$varName = $k;
// And since we have it, we no longer need to loop
break;
}
}
// If there was no name found let the app know
if (empty($varName)) {
$varName = '[name_not_found]';
}
// Now change the value of the variable back to its original state
$var = $passed;
// And finally, return it to the app
return $varName;
}
?>
Beware of using this method in PHP4 when passing objects to it too. It will break your reference
astions wrote:I can't imagine ever needing to obtain the name of a variable.
Good thing too, as writing a function that will always get the variable's name is a near impossible task in PHP. Plus, GLOBALS has a reference of itself! Who's idea was that? Nesting level too deep my ass...
Quick note, nothing I code for at the moment is for PHP4. I should have said that. I have no interest in supporting PHP4 code.
I tested that single line snippet from the manual and it wouldn't work correctly in a PHP 5 class. I also tested other versions of name fetching code and either none of them worked in PHP 5, none of them worked in constructors of an object being instantiated from within another object or they always returned null (empty). The code I posted works as a stand alone function and also works in objects. That, to me, sets it apart from the other snips.
There are several times when I have dumped data throughout a script at various points and would rather have had the variable name than the line number (it also helps you see how a variable's values changes).
I tested the code on PHP 5.1.6. At the moment I make no claims to functionality on other PHP distros as I have not been able to test them under these platforms.
Thanks for going over this guys. I truly appreciate the feedback.
I was trying to make arrays work with your function, and then this popped up. It's somewhat similar. I'm losing all hope on the arrays though. :-p
Well crap, I thought I was special. That code is almost exactly the same as what I put out (honestly I hadn't seen that one before). I had seen the snips on print_r() and var_dump(), but that code is almost identical to what I put out. Oh well, I guess my originality is crap .
Everah wrote:There are several times when I have dumped data throughout a script at various points and would rather have had the variable name than the line number (it also helps you see how a variable's values changes).
I agree. I hate having to break if-statements up into different lines
Everah wrote:I tested the code on PHP 5.1.6. At the moment I make no claims to functionality on other PHP distros as I have not been able to test them under these platforms.
There are a lot of documents online regarding recursive dependency (specifically the reference to GLOBALS in GLOBALS) that seem to start at PHP 5.2, which makes in extremely difficult to traverse deeper into GLOBALS.
array_slice() / array_shift() work when the globals array is ordered starting with G, but not every installation needs to do so. array_search() can't find GLOBALS in GLOBALS, in_array() can't do it, and simple '===' comparison can't either. Otherwise, I would have had an addition to your snippet that could document the exact position in the GLOBALS array (i.e. GLOBALS=>FOO=>BAR=>varName). Sadly, I couldn't find a way to make it a dynamic fix.
I was trying to make arrays work with your function, and then this popped up. It's somewhat similar. I'm losing all hope on the arrays though. :-p
Well crap, I thought I was special. That code is almost exactly the same as what I put out (honestly I hadn't seen that one before). I had seen the snips on print_r() and var_dump(), but that code is almost identical to what I put out. Oh well, I guess my originality is crap .
Hehe. Look at it this way: Yours has a more unique name than 'unique'.