I have this line in a class function:
$this_value = eval("return $$existing_value;");
This gives me the value I need when the $$existing_value variable is set in the function, but I've found that I actually need to access the global scope in 99% of cases. I've tried rewritting it as $this_value = eval("return global $$existing_value;");, but that returns a php error.
Does any know how I can do this correctly?
(by the way, I am aware of the poor pratice this represents - but given the situation I cannot think of any other approaches)
Try
$this_value = eval('global $existing_value; return $$existing_value;');
or
$this_value = eval('global $$existing_value; return $$existing_value;');
$x = 3;
function sss()
{
$x = 1;
$y = eval('global $x; return $x;');
var_dump($y);
}
sss();
Will output int(3) , so it works , but be carefull about double quotes and simple quotes!
Since eval is returning the value you need, you should be bale to just assign the return value to the $_GLOBAL or $_SESSION (preferred because $_GLOBAL is evil) super globals.
$foo['bar'] = "pie";
$fixed_name_variable = "foo['bar']";
$_GLOBAL['foo'] = eval("return $$fixed_name_variable;");
echo $_GLOBAL['foo']; // pie
I've been re-thinking this process. I have relised that I can add a new array with a fixed name which the various processes contributing to this function can add the values needed, programatically, rather than trying to guess at names.
It'll also be far more secure and reliable than variable variables.
Related
Straightforward:
I want to write some code which tells if a variable was passed by reference or not.
For example:
<?php
function isReference($variable) {
//return TRUE if &$something was passed
//return FALSE if $something was passed
}
$text = 'Anything';
$a = isReference(&$text); //return TRUE
$b = isReference($test); //return FALSE
?>
For those who are curious - why do I need it?
Firstly I do not like to leave problems unsolved.
Secondly, I am currently enhancing by skills by writing an extension to mysqli, which would prepare statements similar to how PDO does. If anybody knows the difference between bindParam and bindValue in PDO, they know that it's a workaround of this question. I can just make two functions, but I wonder if it's possible with one.
Thanks in advance.
Here's a way to do it without using the debug_zval_dump function:
function isReference($variable) {
$variable = array($variable);
$arg = func_get_arg(0);
$isRef = isset($arg[0]) && $arg === array($variable[0]);
$variable = $variable[0];
return $isRef;
}
Note: there is only a single case when this will not work:
$text = array(&$text); // although i don't see why such a structure could be used
isReference($text); // will wrongly return false
Obviously you can bypass this limitation by using a random unique key (instead of 0).
You can use debug_zval_dump to dump a string representation of an internal zend value to output:
function isRef(&$val) {
ob_start();
debug_zval_dump(&$val);
$ret = ob_get_clean();
preg_match('~refcount\((\d+)\)~', $ret, $matches);
return $matches[1] - 4;
}
$var1 = 'Var1';
$var2 = &$var1; // passed by ref
if(isRef($var2)) echo 'Passed by ref';
But be aware of PHP - 5.4.
Simply checking for the default value seems to work fine in my tests. Obviously it wont work if $t is already set to 'x' but you could change the default value to something totally unlikely to workaround this:
function test(&$t='x'){
if($t!='x') $t = 2;
}
test(); echo $t; //outputs: null
test($t); echo $t; //outputs: 2
When passing a non-existent value by reference, PHP creates the value and sets it to NULL. I noticed it when memory increases were occurring while checking empty values in some functions. Take the following function:
function v(&$v,$d=NULL){return isset($v)?$v:$d;}
$bar = v($foo, $default);
This would be shorthand for:
if(isset($foo))
{
$bar = $foo;
}
else
{
$bar = $default;
}
However, when passing non-existent variables PHP creates them. In the case of variables - they are removed as soon as the method/function ends - but for checking super global arrays like $_GET or $_POST the array element is never removed causing extra memory usage.
$request_with = v($_SERVER['HTTP_X_REQUESTED_WITH']);
Can anyone explain why this happens and if it is a PHP todo fix or a feature for some other crazy use of values?
XeonCross' function v is a shorthand for the often used:
$val= isset($arr['elm']) ? $arr['elm'] : 'default'
to avoid the dreaded 'Undefined index: elm' notice. A nice helper function would be:
function ifset(&$v1, $v2 = null) {
return isset($v1) ? $v1 : $v2;
}
as Xeoncross suggested, so you could write the much nicer
$val = ifset($arr['elm'],'default')
however, this has a lot of interesting (?) quirks in our beloved "language" that we call PHP:
inside the function ifset, $v1 seems UNSET, so it correctly returns the value $v2 and you might conclude that ifset works ok. But afterwards $arr['elm'] is silently set to NULL. So consider the following:
function wtf(&$v) {
if (isset($v))
echo "It is set";
else
echo "It is NOT set";
}
$p=[];
wtf($p['notexist']); => It is NOT set
$p; => [ 'notexist' => NULL ]
But this is another delusion, as the isset() function returns false for NULL values as well:
$x=NULL;
isset($x) => false... huh??
Did we expect this? well.. it is in the documentation, so this is by design as well. Welcome to the wonderful world of php.
The reason you have the memory leak, is because you're telling it to.
When you ask for a reference parameter, PHP will provide you with one. When you are calling a function with an unset variable, PHP will set the variable and then pass the reference to that new variable. When you call it with a superglobal, it creates the missing index. That's because you told it to.
However, I must ask why specifically do you need variable references? 99.9% of the time you don't really need them. I suspect that it'll work just fine to do:
function v($v, $d = null) { return isset($v) ? $v : $d; }
Or, if you really must use references (which you can't get around your original problem with), you should also return a reference:
function &v(&$v, $d = null) {
if (isset($v)) {
return $v;
}
return $d;
}
Otherwise it's pointless to take a reference and not return one...
func($name1) should return name1
Is it possible?
Here's a function that does it.
function var_name (&$iVar, &$aDefinedVars)
{
foreach ($aDefinedVars as $k=>$v)
$aDefinedVars_0[$k] = $v;
$iVarSave = $iVar;
$iVar =!$iVar;
$aDiffKeys = array_keys (array_diff_assoc ($aDefinedVars_0, $aDefinedVars));
$iVar = $iVarSave;
return $aDiffKeys[0];
}
Call it like this
$test = "blah";
echo var_name($test, get_defined_vars());
That will print out "test".
I originally found that function over here You can also do it by iterating over the array returned by get_defined_vars(). That might be a bit easier to understand.
No, there is no way to get the name of a variable in PHP.
When calling a function, that function will only receive the content of the variable, and not the "variable itself" -- which means a function cannot find out the name of the variable that was passed to it.
Good Idea ? No
Any usecase you where you should do it ? No
Proof of concept ? Sure !
<?php
a($test);
function a($x) {
$trace = debug_backtrace();
$file = file($trace[0]['file']);
$line = $file[$trace[0]['line']-1];
var_dump($line); // Prints "a($test);" Do the Stringparsing and your done
}
Yes, this takes the "easy" by reading the sourcefile, it is also doable by using a php extension called "bytekit" that gives you userland access to the php opcodes and work from there.
No.
When you define a function, you specify a local variable name for it to have inside the scope of that function. PHP will pass the function the appropriate value, but the symbol is no longer in scope.
You could look into using "variable variables" as an alternative, however.
Obviously, it is possible for sufficiently high values of crazy.
The comments on this page include several techniques:
http://php.net/manual/en/language.variables.php
lucas dot karisny at linuxmail dot org's answer works on my machine:
http://www.php.net/manual/en/language.variables.php#49997
YMMV.
Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"
I know this is not exactly reflection, but kind of.
I want to make a debug function that gets a variable and prints a var_dump and the variable name.
Of course, when the programmer writes a call to the function, they already know the variable's name, so they could write something like:
debug( $myvar, 'myvar' );
But I want it to be quick and easy to write, just the function name, the variable, and voilĂ !
debug( $myvar ); // quicker and easier :)
You can do it by converting the variable to a key/value set before passing it to the function.
function varName($theVar) {
$variableName = key($theVar);
$variableValue = $theVar[$variableName];
echo ('The name of the variable used in the function call was '.$variableName.'<br />');
echo ('The value of the variable used in the function call was '.$variableValue.'<br />');
}
$myVar = 'abc';
varName(compact('myVar'));
Though I don't recommend creating a reference to a nameless variable, function varName(&$theVar) works too.
Since compact() takes the variable name as a string rather than the actual variable, iterating over a list of variable names should be easy.
As to why you would want to do this -- don't ask me but it seems like a lot of people ask the question so here's my solution.
I know I'm answering a 4 year old question but what the hell...
compact() might help you is your friend here!
I made a similar function to quickly dump out info on a few chosen variables into a log for debugging errors and it goes something like this:
function vlog() {
$args = func_get_args();
foreach ($args as $arg) {
global ${$arg};
}
return json_encode(compact($args));
}
I found JSON to be the cleanest and most readable form for these dumps for my logs but you could also use something like print_r() or var_export().
This is how I use it:
$foo = 'Elvis';
$bar = 42;
$obj = new SomeFancyObject();
log('Something went wrong! vars='.vlog('foo', 'bar', 'obj'));
And this would print out like this to the logs:
Something went wrong! vars={"foo":"Elvis","bar":42,"obj":{"nestedProperty1":1, "nestedProperty2":"etc."}}
Word of warning though: This will only work for variables declared in the global scope (so not inside functions or classes. In there you need to evoke compact() directly so it has access to that scope, but that's not really that big of a deal since this vlog() is basically just a shortcut for json_encode(compact('foo', 'bar', 'obj')), saving me 16 keystrokes each time I need it.
Nope, not possible. Sorry.
Not elegantly... BUT YOU COULD FAKE IT!
1) Drink enough to convince yourself this is a good idea (it'll take a lot)
2) Replace all your variables with variable variables:
$a = 10
//becomes
$a = '0a';
$$a = 10;
3) Reference $$a in all your code.
4) When you need to print the variable, print $a and strip out the leading 0.
Addendum: Only do this if you are
Never showing this code to anyone
Never need to change or maintain this code
Are crazy
Not doing this for a job
Look, just never do this, it is a joke
I know this is very very late, but i did it in a different way.
It might honestly be a bit bad for performance, but since it's for debugging it shouldn't be a problem.
I read the file where the function is called, on the line it was called and I cut out the variable name.
function dump($str){
// Get the caller with debug backtrace
$bt = debug_backtrace();
$caller = array_shift($bt);
// Put the file where the function was called in an array, split by lines
$readFileStr = file($caller['file']);
// Read the specific line where the function was called
$lineStr = $readFileStr[$caller['line'] -1];
// Get the variable name (including $) by taking the string between '(' and ')'
$regularOutput = preg_match('/\((.*?)\)/', $lineStr, $output);
$variableName = $output[1];
// echo the var name and in which file and line it was called
echo "var: " . $variableName . " dumped in file: " . $caller['file'] . ' on line: ' . $caller['line'] . '<br>';
// dump the given variable
echo '<pre>' . var_export($str, true) . '</pre>';
}
i've had the same thought before, but if you really think about it, you'll see why this is impossible... presumably your debug function will defined like this: function debug($someVar) { } and there's no way for it to know the original variable was called $myvar.
The absolute best you could do would be to look at something like get_defined_vars() or $_GLOBALS (if it were a global for some reason) and loop through that to find something which matches the value of your variable. This is a very hacky and not very reliable method though. Your original method is the most efficient way.
No, the closer you will get is with get_defined_vars().
EDIT: I was wrong, after reading the user comments on get_defined_vars() it's possible with a little hack:
function ev($variable){
foreach($GLOBALS as $key => $value){
if($variable===$value){
echo '<p>$'.$key.' - '.$value.'</p>';
}
}
}
$lol = 123;
ev($lol); // $lol - 123
Only works for unique variable contents though.
Bit late to the game here, but Mach 13 has an interesting solution: How to get a variable name as a string in PHP
You could use eval:
function debug($variablename)
{
echo ($variablename . ":<br/>");
eval("global $". $variablename . ";");
eval("var_dump($" . $variablename . ");");
}
Usage: debug("myvar") not debug($myvar)
This is late post but I think it is possible now using compact method
so the code would be
$a=1;
$b=2;
$c=3
var_dump(compact('a','b','c'));
the output would be
array (size=3)
'a' => int 1
'b' => int 2
'c' => int 3
where variable name a, b and c are the key
Hope this helps
I believe Alix and nickf are suggesting this:
function debug($variablename)
{
echo ($variablename . ":<br/>");
global $$variablename; // enable scope
var_dump($$variablename);
}
I have tested it and it seems to work just as well as Wagger's code (Thanks Wagger: I have tried so many times to write this and the global variable declaration was my stumbling block)