Problems with saving value of superglobal in PHP - php

This code doesn't work:
$john = array("goodie");
function test(){
global $john;
for($i=0; $i<100; $i++)
{
array_push($john, "pro");
}
print_r($john);
}
test(); // outputs correct array: array("goodie","pro","pro"....)
/* then when again function is called */
test(); // output is NULL
// with 100 errors in loop:
// expects parameter 1 to be an array, NULL given...
I have problems to fix this in my code, and I don't understand problem. Why instead adding new 100 items in array, global variable is unset.

I think you shouldn't use your globals in that way. A function should be a closed part of your code. So its much better to make an input parameter and work with the variable like that.
function test(array $input) {
for($i=0; $i<100; $i++) {
array_push($input, "pro");
}
return $input;
}

This is one reason why global variables are generally evil. Because its global, it's probably getting modified somewhere, possibly in some obscure fashion that's hard to detect. Instead of making it global, why not pass it in as a parameter and return it back out?
function test(array $param){
for($i=0; $i<100; $i++)
{
array_push($param, "pro");
}
return $param;
}
$john = array();
$john = test($john);
// ...
$john = test($john);

Related

Unset a variable without checking whether it has been already used or declared

To unset a variable without cheking whether it has been already used or declared.Which is valid in PHP: (a) or (b)? Although both works. In the sample code below,forward referencing is used,how PHP handles it internally?
(a)
while(stmt1->fetch())
{
unset($data);
$i=0;
while(stmt2->fetch())
{
//Some code.......
$data[$i] = $some_Value;
$i++;
}
}
(b)
while(stmt1->fetch())
{
if(isset($data))
{
unset($data);
}
$i=0;
while(stmt2->fetch())
{
//Some code.......
$data[$i] = $some_Value;
$i++;
}
}
Instead of unsetting the variable, set it with an initial value. This conveys the intention much clearer.
Also, you don't need to keep track of $i to insert a new element:
while ($stmt1->fetch()) {
$data = []; //Initialize empty array. This is PHP 5.4+ syntax.
while ($stmt2->fetch()) {
$data[] = $someValue; //$array[] means "Push new element to this array"
}
}
Method B is not neccessary. If you unset a non-existing variable nothing will happen, you won't get an undefined variable error.
You can see this behaviour here (it has error_reporting(E_ALL)).
Just in case you see it is some other code, I've already seen something like the following code (It's not the real code, only to give an idea of the use case).
The isset what used like "isset and with validated value". I'm not saying it's good practice (of course it's not, and even worse in this simplified example), it's just to show that, with overloaded magic methods, it may have some sense.
class unsetExample {
private $data = 'some_value';
public function __isset($name) {
if ($this->${name} != 'my_set_value') {
return false;
} else {
return true;
}
public function __unset($name) {
unset($this->${name});
echo 'Value unset';
}
}
$u = new unsetExample;
if (isset($u->data)) {
unset($u->data);
} else {
echo 'In that case I don\'t want to unset, but I will do something else instead';
}
Edit : Changed the code, it's much more how it was is the real code now

How can I find out the name of a variable inside a function?

I have a function
function my_dump($a,$name){
echo '<pre>'.$name.":\n";
var_export($a);
echo '</pre>';
}
How can I achieve this with only one argument so the function recognizes the name of the called variable itself?
for example:
my_dump($cool_variable_name);
will output:
Name: "cool_variable_name"
Content: array(...
If you need to debug code, then using tools like xdebug is a lot more flexible and efficient than homebrew variable dumps; but debug_backtrace() (although a big overhead) might give you what you need. Extract the filename and line number of the call to your debug dump function, and parse that line to extract the variable name that's used when calling the function
function my_dump($a) {
$backtrace = debug_backtrace()[0];
$fh = fopen($backtrace['file'], 'r');
$line = 0;
while (++$line <= $backtrace['line']) {
$code = fgets($fh);
}
fclose($fh);
preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name);
echo '<pre>'.trim($name[1]).":\n";
var_export($a);
echo '</pre>';
}
$foo = 'bar';
$baz = array(
'Hello',
'World'
);
my_dump($foo);
my_dump(
$baz
);
If your PHP version doesn't support array dereferencing, change
$backtrace = debug_backtrace()[0];
to
$backtrace = debug_backtrace();
$backtrace = $backtrace[0];
If your call to my_dump() spans multiple lines (like my $baz example), you'll need a slightly more sophisticated parser to extract the variable name from your code.
function my_dump($a) {
$backtrace = debug_backtrace()[0];
$fh = fopen($backtrace['file'], 'r');
$line = 0;
while (++$line <= $backtrace['line']) {
$code = fgets($fh);
}
fclose($fh);
preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name);
echo '<pre>'.trim($name[1]).":\n";
var_export($a);
echo '</pre>';
}
It does not run right - because used expression does not give correct result.
Using of \s* has not sense because nothing can be between name of function and brackets with parameters.
Using of ; in expression has not sense too. At least because is allows only standalone using of this function where result of this function is given to else variable. But sometimes it may be needed to use this function as parameter.
And using of (.*) will allow also all that is behind variable name given as parameter - even if there is semicolon.
So, it is needed to exclude of sign of end bracket, ), from result. There are many ways how to do that.
You can use form from code of function below or this (or something else)
'/'.__FUNCTION__.'\((\w+)\)/'
Whole function may be very simplified into (for example, this is case of class function):
protected function Get_VariableNameAsText($Variable="")
{
$File = file(debug_backtrace()[0]['file']);
for($Line = 1; $Line < count($File); $Line++)
{
if($Line == debug_backtrace()[0]['line']-1)
{
preg_match('/'.__FUNCTION__.'\(([^\)]*)\)/', $File[$Line], $VariableName);
return trim($VariableName[1]);
}
}
}
I deleted using of var_export because I don't see why to use it, when I only want to get variable name as string (text). And printing of given string is better outside of this function.
If you have not 5.4 or greater, you need to change code
$File = file(debug_backtrace()[0]['file']);
if($Line == debug_backtrace()[0]['line']-1)
on
$Trace = debug_backtrace();
$File = file($Trace[0]['file']);
if($Line == $Trace[0]['line']-1)
... I beg your pardon for new answer instead change of previous, but it would be too long (and thus uncomfortable) for reading.
Below is function from previous answer, that is improved for multiple usage of this function. This version is capable to get name of correct variable in case of multiple usage in one line.
It is not capable to get name of more than one variable - at least because I don't think it would be good (useful for anything).
Differences:
adding of integer parameter $Index
new function for regular expression
new regular expression
new handling of result of regular expression
parameter $Index is not demanded - but its ignoring whenever else than the first usage of that function will give wrong result
\x20 in expression means space
exception class and exception message in try-catch block may be rewritten as you need
protected status of function may be changed or deleted
protected function Get_VariableNameAsText($Variable="", $Index="")
{
$File = file(debug_backtrace()[0]['file']);
try
{
if(!empty($Index) && !is_integer($Index))
{
throw new UniT_Exception(UniT_Exception::UNIT_EXCEPTIONS_MAIN_PARAM, UniT_Exception::UNIT_EXCEPTIONS_PARAM_VALTYPE);
}
}
catch(UniT_Exception $Exception)
{
$Exception -> ExceptionWarning(__CLASS__, __FUNCTION__, $this -> Get_Parameters(__CLASS__, __FUNCTION__)[1], gettype($Index), 'integer');
}
for($Line = 1; $Line < count($File); $Line++)
{
if($Line == debug_backtrace()[0]['line']-1)
{
preg_match_all('/'.__FUNCTION__.'\((?<type>[a-z]{1,}\:{2}\${1}|\$this\x20{0,1}\-\>{1}\x20{0,1}|\${1})(?<variable>[A-Za-z0-9_]{1,})\x20{0,1}\,{0,1}\x20{0,1}(?<index>[0-9]{0,})\x20{0,}\)/', $File[$Line], $VariableName, PREG_SET_ORDER);
if(empty($Index))
{
return $VariableName[0]['type'].$VariableName[0]['variable'];
}
else
{
return $VariableName[$Index]['type'].$VariableName[$Index]['variable'];
}
}
}
}
I hope it will help you, like or better than previous version.
Edit: New expression allows using of more types of variables (not only common).
If it is a simple script, where all variables are defined in the global scope, you could get for the $GLOBALS solution:
function my_dump($a){
if(is_string($a) and isset($GLOBALS[$a])) {
echo "varname: $a\n";
$a=&$GLOBALS[$a];
}
echo '<pre>'.$name.":\n";
var_export($a);
echo '</pre>';
}
this way you can call the dump function with the variable name instead
my_dump("cool_variable_name");
instead of
my_dump($cool_variable_name);
There is no way to do this.
When the function is called the value of the parameter gets pasted into your $a , so every attempt to get the name of it would return "a".
http://us3.php.net/get_defined_vars will fail, because it only returns variables inside your function (that means "a").
You may use an array with one item, but I guess that's not what you intend to do.

What does & before the function name signify?

What does the & before the function name signify?
Does that mean that the $result is returned by reference rather than by value?
If yes then is it correct? As I remember you cannot return a reference to a local variable as it vanishes once the function exits.
function &query($sql) {
// ...
$result = mysql_query($sql);
return $result;
}
Also where does such a syntax get used in practice ?
Does that mean that the $result is returned by reference rather than by value?
Yes.
Also where does such a syntax get used in practice ?
This is more prevalent in PHP 4 scripts where objects were passed around by value by default.
To answer the second part of your question, here a place there I had to use it: Magic getters!
class FooBar {
private $properties = array();
public function &__get($name) {
return $this->properties[$name];
}
public function __set($name, $value) {
$this->properties[$name] = $value;
}
}
If I hadn't used & there, this wouldn't be possible:
$foobar = new FooBar;
$foobar->subArray = array();
$foobar->subArray['FooBar'] = 'Hallo World!';
Instead PHP would thrown an error saying something like 'cannot indirectly modify overloaded property'.
Okay, this is probably only a hack to get round some maldesign in PHP, but it's still useful.
But honestly, I can't think right now of another example. But I bet there are some rare use cases...
Does that mean that the $result is returned by reference rather than by value?
No. The difference is that it can be returned by reference. For instance:
<?php
function &a(&$c) {
return $c;
}
$c = 1;
$d = a($c);
$d++;
echo $c; //echoes 1, not 2!
To return by reference you'd have to do:
<?php
function &a(&$c) {
return $c;
}
$c = 1;
$d = &a($c);
$d++;
echo $c; //echoes 2
Also where does such a syntax get used in practice ?
In practice, you use whenever you want the caller of your function to manipulate data that is owned by the callee without telling him. This is rarely used because it's a violation of encapsulation – you could set the returned reference to any value you want; the callee won't be able to validate it.
nikic gives a great example of when this is used in practice.
<?php
// You may have wondered how a PHP function defined as below behaves:
function &config_byref()
{
static $var = "hello";
return $var;
}
// the value we get is "hello"
$byref_initial = config_byref();
// let's change the value
$byref_initial = "world";
// Let's get the value again and see
echo "Byref, new value: " . config_byref() . "\n"; // We still get "hello"
// However, let’s make a small change:
// We’ve added an ampersand to the function call as well. In this case, the function returns "world", which is the new value.
// the value we get is "hello"
$byref_initial = &config_byref();
// let's change the value
$byref_initial = "world";
// Let's get the value again and see
echo "Byref, new value: " . config_byref() . "\n"; // We now get "world"
// If you define the function without the ampersand, like follows:
// function config_byref()
// {
// static $var = "hello";
// return $var;
// }
// Then both the test cases that we had previously would return "hello", regardless of whether you put ampersand in the function call or not.

PHP function won't execute when called

I'm having a problem with this function. It's supposed to echo out some stuff, but for some reason it won't do so when I call it.
Here's the function:
$count = count($info['level']);
function displayInfo()
{
for ($i=0; $i<$count; $i++)
{
echo "[b]".$info['name'][$i]."[/b]\n\n"
."Level: ".$info['level'][$i]
."\nPrice: ".$info['price'][$i]
."\nSellback: ".$info['sell'][$i]
."\nLocation: ".$location
."\n\nType: ".$info['type'][$i]
."\nElement: ".$info['element'][$i]
."\nDamage: ".$info['damage'][$i]
."\nBTH: ".$info['bth'][$i]
."\n\nSPECIAL"
."\nHits: ".$info['hits'][$i]
."\nType: ".$info['stype'][$i]
."\nElement: ".$info['selement'][$i]
."\nDamage: ".$info['sdamage'][$i]
."\nBTH: ".$info['sbth'][$i]
."\nRate: ".$info['rate'][$i]
."\n\nDescription\n".$description
."\n".$img
."\n\n\n";
}
}
And here's the code I use to call the function:
<?PHP
displayInfo();
?>
I can't find out what's wrong--it's not a sintax error, page loads without interuption.
Thanks in advance.
You are declaring the $count and $info variable outside of your function :
// $info already exists
$count = count($info['level']); // and $count is initialized here
function displayInfo()
{
for ($i=0; $i<$count; $i++)
...
In PHP, a variable declared outside of a function is not visible from inside the function.
If you want your "external" variables to be visible from inside the function, you have to declare them as global in the function :
$count = count($info['level']);
function displayInfo()
{
global $count, $info;
// $count is now visible ; same for $info
for ($i=0; $i<$count; $i++)
...
But it's generally considered better to pass the variables as parameters to the function : you have to declare them as a parameter :
function displayInfo($count, $info)
{
for ($i=0; $i<$count; $i++)
...
And pass them to the function when calling it :
$count = count(...);
displayInfo($count, $info);
Passing parameters instead of using global variables ensures you know what your functions have access to -- and modify.
Edit : thanks for the note, X-Istence ! Didn't read enough of the given code :-(
$count and $info are declared outside the function and therefore they are not visible within it. You could pass $info into the function and then calculate $count within, like this:
//get info from db, or somewhere
$info = array();
displayInfo($info);
function displayInfo($info)
{
$count = count($info['level']);
//now $count and $info are visible.
}
See http://php.net/manual/en/language.variables.scope.php
Add global for variables which should be accessed from function, but are not parameters:
function displayInfo()
{
## bad design
global $count, $info;
...
Or pass your array as parameter:
function displayInfo($info)
{
## this is local variable accessable only inside function
$count = count($info['level']);
...
}
The call it
<?php
## don't forget to pass array as parameter
displayInfo($info);
?>
You can either move your $count inside the function, or pass it to the function. Also, your $info array has to be passed into the function as well, or made a global. Here is the function prototype with count and info being passed into the function.
function displayInfo($count, $info)
{
for ($i=0; $i<$count; $i++)
{
// Do stuff
}
}
<?php
$count = count($info['level']);
displayInfo($count, $info);
?>
Indeed, there were no syntax errors, but there were other errors, as was pointed out in other reactions. I highly recommend configuring PHP to show all errors when writing new code. This way you would've seen a notice about $info and $count not being defined inside your function.
You can turn errors on in a couple of ways.
Configure your server to do it.
Turn them on by using an .htaccess file
Use the following PHP code in the very beginning of your script.
Example:
error_reporting(E_ALL | E_NOTICE); //turn on all errors
ini_set("display_errors","On"); //activate display_error

How to get a variable name as a string in PHP?

Say i have this PHP code:
$FooBar = "a string";
i then need a function like this:
print_var_name($FooBar);
which prints:
FooBar
Any Ideas how to achieve this? Is this even possible in PHP?
I couldn't think of a way to do this efficiently either but I came up with this. It works, for the limited uses below.
shrug
<?php
function varName( $v ) {
$trace = debug_backtrace();
$vLine = file( __FILE__ );
$fLine = $vLine[ $trace[0]['line'] - 1 ];
preg_match( "#\\$(\w+)#", $fLine, $match );
print_r( $match );
}
$foo = "knight";
$bar = array( 1, 2, 3 );
$baz = 12345;
varName( $foo );
varName( $bar );
varName( $baz );
?>
// Returns
Array
(
[0] => $foo
[1] => foo
)
Array
(
[0] => $bar
[1] => bar
)
Array
(
[0] => $baz
[1] => baz
)
It works based on the line that called the function, where it finds the argument you passed in. I suppose it could be expanded to work with multiple arguments but, like others have said, if you could explain the situation better, another solution would probably work better.
You could use get_defined_vars() to find the name of a variable that has the same value as the one you're trying to find the name of. Obviously this will not always work, since different variables often have the same values, but it's the only way I can think of to do this.
Edit: get_defined_vars() doesn't seem to be working correctly, it returns 'var' because $var is used in the function itself. $GLOBALS seems to work so I've changed it to that.
function print_var_name($var) {
foreach($GLOBALS as $var_name => $value) {
if ($value === $var) {
return $var_name;
}
}
return false;
}
Edit: to be clear, there is no good way to do this in PHP, which is probably because you shouldn't have to do it. There are probably better ways of doing what you're trying to do.
You might consider changing your approach and using a variable variable name?
$var_name = "FooBar";
$$var_name = "a string";
then you could just
print($var_name);
to get
FooBar
Here's the link to the PHP manual on Variable variables
No-one seems to have mentioned the fundamental reasons why this is a) hard and b) unwise:
A "variable" is just a symbol pointing at something else. In PHP, it internally points to something called a "zval", which can actually be used for multiple variables simultaneously, either because they have the same value (PHP implements something called "copy-on-write" so that $foo = $bar doesn't need to allocate extra memory straight away) or because they have been assigned (or passed to a function) by reference (e.g. $foo =& $bar). So a zval has no name.
When you pass a parameter to a function you are creating a new variable (even if it's a reference). You could pass something anonymous, like "hello", but once inside your function, it's whatever variable you name it as. This is fairly fundamental to code separation: if a function relied on what a variable used to be called, it would be more like a goto than a properly separate function.
Global variables are generally considered a bad idea. A lot of the examples here assume that the variable you want to "reflect" can be found in $GLOBALS, but this will only be true if you've structured your code badly and variables aren't scoped to some function or object.
Variable names are there to help programmers read their code. Renaming variables to better suit their purpose is a very common refactoring practice, and the whole point is that it doesn't make any difference.
Now, I understand the desire for this for debugging (although some of the proposed usages go far beyond that), but as a generalised solution it's not actually as helpful as you might think: if your debug function says your variable is called "$file", that could still be any one of dozens of "$file" variables in your code, or a variable which you have called "$filename" but are passing to a function whose parameter is called "$file".
A far more useful piece of information is where in your code the debug function was called from. Since you can quickly find this in your editor, you can see which variable you were outputting for yourself, and can even pass whole expressions into it in one go (e.g. debug('$foo + $bar = ' . ($foo + $bar))).
For that, you can use this snippet at the top of your debug function:
$backtrace = debug_backtrace();
echo '# Debug function called from ' . $backtrace[0]['file'] . ' at line ' . $backtrace[0]['line'];
This is exactly what you want - its a ready to use "copy and drop in" function that echo the name of a given var:
function print_var_name(){
// read backtrace
$bt = debug_backtrace();
// read file
$file = file($bt[0]['file']);
// select exact print_var_name($varname) line
$src = $file[$bt[0]['line']-1];
// search pattern
$pat = '#(.*)'.__FUNCTION__.' *?\( *?(.*) *?\)(.*)#i';
// extract $varname from match no 2
$var = preg_replace($pat, '$2', $src);
// print to browser
echo '<pre>' . trim($var) . ' = ' . print_r(current(func_get_args()), true) . '</pre>';
}
USAGE: print_var_name($FooBar)
PRINT: FooBar
HINT
Now you can rename the function and it will still work and also use the function several times in one line! Thanks to #Cliffordlife
And I add a nicer output! Thanks to #Blue-Water
Lucas on PHP.net provided a reliable way to check if a variable exists. In his example, he iterates through a copy of the global variable array (or a scoped array) of variables, changes the value to a randomly generated value, and checks for the generated value in the copied array.
function variable_name( &$var, $scope=false, $prefix='UNIQUE', $suffix='VARIABLE' ){
if($scope) {
$vals = $scope;
} else {
$vals = $GLOBALS;
}
$old = $var;
$var = $new = $prefix.rand().$suffix;
$vname = FALSE;
foreach($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
Then try:
$a = 'asdf';
$b = 'asdf';
$c = FALSE;
$d = FALSE;
echo variable_name($a); // a
echo variable_name($b); // b
echo variable_name($c); // c
echo variable_name($d); // d
Be sure to check his post on PHP.net: http://php.net/manual/en/language.variables.php
I made an inspection function for debugging reasons. It's like print_r() on steroids, much like Krumo but a little more effective on objects. I wanted to add the var name detection and came out with this, inspired by Nick Presta's post on this page. It detects any expression passed as an argument, not only variable names.
This is only the wrapper function that detects the passed expression.
Works on most of the cases.
It will not work if you call the function more than once in the same line of code.
This works fine:
die(inspect($this->getUser()->hasCredential("delete")));
inspect() is the function that will detect the passed expression.
We get: $this->getUser()->hasCredential("delete")
function inspect($label, $value = "__undefin_e_d__")
{
if($value == "__undefin_e_d__") {
/* The first argument is not the label but the
variable to inspect itself, so we need a label.
Let's try to find out it's name by peeking at
the source code.
*/
/* The reason for using an exotic string like
"__undefin_e_d__" instead of NULL here is that
inspected variables can also be NULL and I want
to inspect them anyway.
*/
$value = $label;
$bt = debug_backtrace();
$src = file($bt[0]["file"]);
$line = $src[ $bt[0]['line'] - 1 ];
// let's match the function call and the last closing bracket
preg_match( "#inspect\((.+)\)#", $line, $match );
/* let's count brackets to see how many of them actually belongs
to the var name
Eg: die(inspect($this->getUser()->hasCredential("delete")));
We want: $this->getUser()->hasCredential("delete")
*/
$max = strlen($match[1]);
$varname = "";
$c = 0;
for($i = 0; $i < $max; $i++){
if( $match[1]{$i} == "(" ) $c++;
elseif( $match[1]{$i} == ")" ) $c--;
if($c < 0) break;
$varname .= $match[1]{$i};
}
$label = $varname;
}
// $label now holds the name of the passed variable ($ included)
// Eg: inspect($hello)
// => $label = "$hello"
// or the whole expression evaluated
// Eg: inspect($this->getUser()->hasCredential("delete"))
// => $label = "$this->getUser()->hasCredential(\"delete\")"
// now the actual function call to the inspector method,
// passing the var name as the label:
// return dInspect::dump($label, $val);
// UPDATE: I commented this line because people got confused about
// the dInspect class, wich has nothing to do with the issue here.
echo("The label is: ".$label);
echo("The value is: ".$value);
}
Here's an example of the inspector function (and my dInspect class) in action:
http://inspect.ip1.cc
Texts are in spanish in that page, but code is concise and really easy to understand.
From php.net
#Alexandre - short solution
<?php
function vname(&$var, $scope=0)
{
$old = $var;
if (($key = array_search($var = 'unique'.rand().'value', !$scope ? $GLOBALS : $scope)) && $var = $old) return $key;
}
?>
#Lucas - usage
<?php
//1. Use of a variable contained in the global scope (default):
$my_global_variable = "My global string.";
echo vname($my_global_variable); // Outputs: my_global_variable
//2. Use of a local variable:
function my_local_func()
{
$my_local_variable = "My local string.";
return vname($my_local_variable, get_defined_vars());
}
echo my_local_func(); // Outputs: my_local_variable
//3. Use of an object property:
class myclass
{
public function __constructor()
{
$this->my_object_property = "My object property string.";
}
}
$obj = new myclass;
echo vname($obj->my_object_property, $obj); // Outputs: my_object_property
?>
Many replies question the usefulness of this. However, getting a reference for a variable can be very useful. Especially in cases with objects and $this. My solution works with objects, and as property defined objects as well:
function getReference(&$var)
{
if(is_object($var))
$var->___uniqid = uniqid();
else
$var = serialize($var);
$name = getReference_traverse($var,$GLOBALS);
if(is_object($var))
unset($var->___uniqid);
else
$var = unserialize($var);
return "\${$name}";
}
function getReference_traverse(&$var,$arr)
{
if($name = array_search($var,$arr,true))
return "{$name}";
foreach($arr as $key=>$value)
if(is_object($value))
if($name = getReference_traverse($var,get_object_vars($value)))
return "{$key}->{$name}";
}
Example for the above:
class A
{
public function whatIs()
{
echo getReference($this);
}
}
$B = 12;
$C = 12;
$D = new A;
echo getReference($B)."<br/>"; //$B
echo getReference($C)."<br/>"; //$C
$D->whatIs(); //$D
Adapted from answers above for many variables, with good performance, just one $GLOBALS scan for many
function compact_assoc(&$v1='__undefined__', &$v2='__undefined__',&$v3='__undefined__',&$v4='__undefined__',&$v5='__undefined__',&$v6='__undefined__',&$v7='__undefined__',&$v8='__undefined__',&$v9='__undefined__',&$v10='__undefined__',&$v11='__undefined__',&$v12='__undefined__',&$v13='__undefined__',&$v14='__undefined__',&$v15='__undefined__',&$v16='__undefined__',&$v17='__undefined__',&$v18='__undefined__',&$v19='__undefined__'
) {
$defined_vars=get_defined_vars();
$result=Array();
$reverse_key=Array();
$original_value=Array();
foreach( $defined_vars as $source_key => $source_value){
if($source_value==='__undefined__') break;
$original_value[$source_key]=$$source_key;
$new_test_value="PREFIX".rand()."SUFIX";
$reverse_key[$new_test_value]=$source_key;
$$source_key=$new_test_value;
}
foreach($GLOBALS as $key => &$value){
if( is_string($value) && isset($reverse_key[$value]) ) {
$result[$key]=&$value;
}
}
foreach( $original_value as $source_key => $original_value){
$$source_key=$original_value;
}
return $result;
}
$a = 'A';
$b = 'B';
$c = '999';
$myArray=Array ('id'=>'id123','name'=>'Foo');
print_r(compact_assoc($a,$b,$c,$myArray) );
//print
Array
(
[a] => A
[b] => B
[c] => 999
[myArray] => Array
(
[id] => id123
[name] => Foo
)
)
If the variable is interchangable, you must have logic somewhere that's determining which variable gets used. All you need to do is put the variable name in $variable within that logic while you're doing everything else.
I think we're all having a hard time understanding what you're needing this for. Sample code or an explanation of what you're actually trying to do might help, but I suspect you're way, way overthinking this.
I actually have a valid use case for this.
I have a function cacheVariable($var) (ok, I have a function cache($key, $value), but I'd like to have a function as mentioned).
The purpose is to do:
$colour = 'blue';
cacheVariable($colour);
...
// another session
...
$myColour = getCachedVariable('colour');
I have tried with
function cacheVariable($variable) {
$key = ${$variable}; // This doesn't help! It only gives 'variable'.
// do some caching using suitable backend such as apc, memcache or ramdisk
}
I have also tried with
function varName(&$var) {
$definedVariables = get_defined_vars();
$copyOfDefinedVariables = array();
foreach ($definedVariables as $variable=>$value) {
$copyOfDefinedVariables[$variable] = $value;
}
$oldVar = $var;
$var = !$var;
$difference = array_diff_assoc($definedVariables, $copyOfDefinedVariables);
$var = $oldVar;
return key(array_slice($difference, 0, 1, true));
}
But this fails as well... :(
Sure, I could continue to do cache('colour', $colour), but I'm lazy, you know... ;)
So, what I want is a function that gets the ORIGINAL name of a variable, as it was passed to a function. Inside the function there is no way I'm able to know that, as it seems. Passing get_defined_vars() by reference in the second example above helped me (Thanks to Jean-Jacques Guegan for that idea) somewhat. The latter function started working, but it still only kept returning the local variable ('variable', not 'colour').
I haven't tried yet to use get_func_args() and get_func_arg(), ${}-constructs and key() combined, but I presume it will fail as well.
I have this:
debug_echo(array('$query'=>$query, '$nrUsers'=>$nrUsers, '$hdr'=>$hdr));
I would prefer this:
debug_echo($query, $nrUsers, $hdr);
The existing function displays a yellow box with a red outline and shows each variable by name and value. The array solution works but is a little convoluted to type when it is needed.
That's my use case and yes, it does have to do with debugging. I agree with those who question its use otherwise.
Here's my solution based on Jeremy Ruten
class DebugHelper {
function printVarNames($systemDefinedVars, $varNames) {
foreach ($systemDefinedVars as $var=>$value) {
if (in_array($var, $varNames )) {
var_dump($var);
var_dump($value);
}
}
}
}
using it
DebugHelper::printVarNames(
$systemDefinedVars = get_defined_vars(),
$varNames=array('yourVar00', 'yourVar01')
);
You could use compact() to achieve this.
$FooBar = "a string";
$newArray = compact('FooBar');
This would create an associative array with the variable name as the key. You could then loop through the array using the key name where you needed it.
foreach($newarray as $key => $value) {
echo $key;
}
I think you want to know variable name with it's value. You can use an associative array to achieve this.
use variable names for array keys:
$vars = array('FooBar' => 'a string');
When you want to get variable names, use array_keys($vars), it will return an array of those variable names that used in your $vars array as it's keys.
This is the way I did it
function getVar(&$var) {
$tmp = $var; // store the variable value
$var = '_$_%&33xc$%^*7_r4'; // give the variable a new unique value
$name = array_search($var, $GLOBALS); // search $GLOBALS for that unique value and return the key(variable)
$var = $tmp; // restore the variable old value
return $name;
}
Usage
$city = "San Francisco";
echo getVar($city); // city
Note: some PHP 7 versions will not work properly due to a bug in array_search with $GLOBALS, however all other versions will work.
See this https://3v4l.org/UMW7V
There is no predefined function in PHP that can output the name of a variable. However, you can use the result of get_defined_vars(), which returns all the variables defined in the scope, including name and value. Here is an example:
<?php
// Function for determining the name of a variable
function getVarName(&$var, $definedVars=null) {
$definedVars = (!is_array($definedVars) ? $GLOBALS : $definedVars);
$val = $var;
$rand = 1;
while (in_array($rand, $definedVars, true)) {
$rand = md5(mt_rand(10000, 1000000));
}
$var = $rand;
foreach ($definedVars as $dvName=>$dvVal) {
if ($dvVal === $rand) {
$var = $val;
return $dvName;
}
}
return null;
}
// the name of $a is to be determined.
$a = 1;
// Determine the name of $a
echo getVarName($a);
?>
Read more in How to get a variable name as a string in PHP?
Why don't you just build a simple function and TELL it?
/**
* Prints out $obj for debug
*
* #param any_type $obj
* #param (string) $title
*/
function print_all( $obj, $title = false )
{
print "\n<div style=\"font-family:Arial;\">\n";
if( $title ) print "<div style=\"background-color:red; color:white; font-size:16px; font-weight:bold; margin:0; padding:10px; text-align:center;\">$title</div>\n";
print "<pre style=\"background-color:yellow; border:2px solid red; color:black; margin:0; padding:10px;\">\n\n";
var_export( $obj );
print "\n\n</pre>\n</div>\n";
}
print_all( $aUser, '$aUser' );
I was looking for this but just decided to pass the name in, I usually have the name in the clipboard anyway.
function VarTest($my_var,$my_var_name){
echo '$'.$my_var_name.': '.$my_var.'<br />';
}
$fruit='apple';
VarTest($fruit,'fruit');
I know this is old and already answered but I was actually looking for this. I am posting this answer to save people a little time refining some of the answers.
Option 1:
$data = array('$FooBar');
$vars = [];
$vars = preg_replace('/^\\$/', '', $data);
$varname = key(compact($vars));
echo $varname;
Prints:
FooBar
For whatever reason you would find yourself in a situation like this, it does actually work.
.
Option 2:
$FooBar = "a string";
$varname = trim(array_search($FooBar, $GLOBALS), " \t.");
echo $varname;
If $FooBar holds a unique value, it will print 'FooBar'. If $FooBar is empty or null it will print the name of the first empty or null string it finds.
It could be used as such:
if (isset($FooBar) && !is_null($FooBar) && !empty($FooBar)) {
$FooBar = "a string";
$varname = trim(array_search($FooBar, $GLOBALS), " \t.");
}
other use:
shrug
function varsToArrayAssoc(...$arguments){
$bt = debug_backtrace();
$file = file($bt[0]['file']);
$src = $file[$bt[0]['line']-1];
$pat = '#(.*)'.__FUNCTION__.' *?\( *?(.*) *?\)(.*)#i';
$vars =explode(',',substr_replace(trim(preg_replace($pat, '$2', $src)) ,"", -1));
$result=[];
foreach(func_get_args() as $key=>$v){
$index=trim(explode('$',$vars[$key])[1]);
$result[$index]=$v;
}
return $result;
}
$a=12;
$b=13;
$c=123;
$d='aa';
var_dump(varsToArrayAssoc($a,$b,$c,$d));
Use this to detach user variables from global to check variable at the moment.
function get_user_var_defined ()
{
return array_slice($GLOBALS,8,count($GLOBALS)-8);
}
function get_var_name ($var)
{
$vuser = get_user_var_defined();
foreach($vuser as $key=>$value)
{
if($var===$value) return $key ;
}
}
It may be considered quick and dirty, but my own personal preference is to use a function/method like this:
public function getVarName($var) {
$tmp = array($var => '');
$keys = array_keys($tmp);
return trim($keys[0]);
}
basically it just creates an associative array containing one null/empty element, using as a key the variable for which you want the name.
we then get the value of that key using array_keys and return it.
obviously this gets messy quick and wouldn't be desirable in a production environment, but it works for the problem presented.
why we have to use globals to get variable name... we can use simply like below.
$variableName = "ajaxmint";
echo getVarName('$variableName');
function getVarName($name) {
return str_replace('$','',$name);
}
I really fail to see the use case... If you will type print_var_name($foobar) what's so hard (and different) about typing print("foobar") instead?
Because even if you were to use this in a function, you'd get the local name of the variable...
In any case, here's the reflection manual in case there's something you need in there.

Categories