Does anybody have an explanation to this weird behavior of php?
Basically, I made a variable $number, and than made a variable $num2, which is a ref to $number. So I thought they will both share the same memory location.
But when I unset $number, its still outputs .. , I thought that if I would use some gc commands it will clear it cause it looks like heap behavior. But it's still not working. :P
function sum(&$var) {
$var++;
}
$number = 5;
$num2 = &$number;
sum($number);
echo $number; echo '<br>';
gc_enable();
gc_collect_cycles();
sleep(5);
unset($number);
echo $num2;
In PHP when you unset a variable that another variable is referenced to (this is what occurs in your case), it simply breaks the link connecting those variables, but remains the value in the second variable.
This is described in the PHP docs.
$mainVar = "Hello!";
$linkedVar = &$mainVar;
unset($mainVar);
So even after $mainVar is unset, the $linkedVar retains that value.
Related
I want to set a PHP variable: $custom, that will be used whenever it is defined.
But I want the output of this variable to be dependant of another variable: $v index, which is used inside while, which gets defined only during the while statement.
I don't know if it's possible to do, right now I have the following code, and for the way I defined $custom[3], it doesn't work.
Only $custom[1] and $custom[2] varibables will work, but they take into account only constant values or variable whose values were already set, so this isn't helpful.
Code:
<?php
$product[1]["price"]=10;
$product[2]["price"]=50;
$product[3]["price"]=70;
$custom[1] = 'Static HTML Block';
$custom[2] = 'Past Variable: '. $product[2]["price"] .'';
$custom[3] = 'Future Variable: '. $product[$v]["price"] .''; // I want this kind of definitoin
?>
<HTML>
// the following part will be used within an include, and shouldn't be modified ///
<?php
$v = 1;
while ($z <= 5) {
?>
<?= $custom[$v] ? $custom[$v] : '$' . $product[$v]["price"] ?>
<?php
$v = $v + 1;
$z = $z + 1;
}
?>
So basically, I want that on the third run (when v=3), that Future Variable: 70 will be the output.
The Rationale:
I want to use the latter code as a constant Include, that will serve as a template for all files. but on occasion, a certain file may require special changes that also require PHP code modification, so I will want to perform them within such specific file, that will affect the original include.
Edit 2:
More Simple example:
<?php
$product[1]["price"]=10;
$product[2]["price"]=50;
$custom[1] = 'I dont modify the PHP code';
$custom[2] = 'I DO mofiy the latter PHP code: '. $product[$v]["price"] .'';
?>
<HTML>
// the following part will be used within an include, and shouldn't be modified ///
<?php $v = 1; while ($v <= 5) { ?>
<?= $custom[$v] ?>
<p>
<?php $v = $v + 1; } ?>
// Expected Output:
//I dont modify the PHP code
//I DO mofiy the latter PHP code: 50
It's a little difficult to tell what you are trying to do, but I think you need to decouple your data from your presentation:
$product[1]['price']=10;
$product[2]['price']=50;
$product[3]['price']=70;
$custom[1] = 'Static HTML Block';
$custom[2] = 'Past Variable: %s';
$custom[3] = 'Future Variable: %s';
$v = 1;
while($z <= 5) {
$price = $product[ $v ]['price'];
printf($custom[ $v ], $price);
$v++;
$z++;
}
In this case, $custom stores the format, but doesn't actually contain the data. You call printf to output the desired format with whatever data you want to pass.
It's not clear to me what you're trying to accomplish, but if I had to guess, you want something known as templates (e.g. Twig), and your question might possibly be a XY problem. If you supply more context maybe someone might be able to help you further.
As to the matter at hand, you cannot define $custom[3] here since $v is not defined yet:
$custom[3] = 'Future Variable: '. $product[$v]["price"] .''; // I want this kind of definitoin
The closest you can get is to use eval (which is rarely recommended), or define a closure, even if it's awkward. Instead of a variable, you define a function:
$custom[3] = function($productData) {
return 'Future Variable: '. $productData["price"] .'';
}
The above you can do in an included file.
Then in the loop you check whether the custom object is a function, and if so, you call it and assign the return value to the reply.
The code below stays the same whatever the include - actually, it even works with the data you have now. Of course, it has to be a little more complicated.
while ($z <= 5) {
// If the $v-th item is customised
if (array_key_exists($v, $custom)) {
// Verify what it is
if (is_callable($custom[$v])) {
// if it's a function, call it.
$reply = $custom[$v]($product);
} else {
$reply = $custom[$v];
}
} else {
// Not customised, just print the price.
$reply = '$' . $product[$v]["price"];
}
print $reply;
Another more "templateish" solution is to define strings and then process them using e.g. preg_replace_callback in order to generate the desired HTML. In this case, too, you need to pass to the templater a fixed variable, such as $product[$v]. You need some kind of 'language' to indicate where you want elements of this fixed variables to be instantiated. Usually, square brackets or curly brackets, often doubled, are used:
$custom[3] = 'Future Variable: {{price}}';
At resolution time, preg_replace_callback may be made to replace {{price}} with the value in $product[$v]['price'], and so on (e.g. {{weight}}, {{description}}...).
(You can also do this server side and populate the HTML page via AJAX using client-side libraries such as Handlebars).
The quick and nasty way to make your own template is to create an array of keys => values and pass it to the where loops as your $custom variable.
While you're in the where(){} loop, use the php function extract to convert the array into $key = 'value' pairs. This is very similar to list without having having to define each variable manually.
http://php.net/manual/en/function.extract.php
Eg.
$data = [
'foo' => 'bar',
];
extract($data);
print $foo; // output: bar
Then after you extract, include your file. Make sure that you wrap this in output buffering mode ob_start() and put it in a function so your local variables can't be overriden.
This is how you make homebrew templating languages.
I tried to find a proper and explanatory title but I couldn't and I will try to explain what I am asking here:
Normally if you don't assign an empty array to a variable, you can start assign values to indexes like this:
$hello["world"] = "Hello World";
...
echo $hello["world"];
but I always encounter such definition:
$hello = array() //assigning an empty array first
$hello["hello"] = "World";
...
echo $hello["hello"];
Why is it used a lot. Is there a performance gain or something with the second one?
Thanks.
Two reasons:
Better readability (you know the array is initialized at this point)
Security - when running on a system with register_globals enabled a user could add e.g. hello[moo]=something to the query string and the array would already be initialized with this. $hello = array(); overwrites this value though since a new array is created.
Initializing your variables is good practice.
Take for example this:
$foo = 'bar';
// 10 lines and 1 year later
$foo['baz'] = 'test';
Congratulations, you now have the string "tar".
This may happen accidentally and introduce needless bugs. It gets even worse with conditional variable creation. It's avoided easily by getting into the good habit of explicitly initializing your variables.
$hello = array();
if(someConditionIsTrue){
$hello["world"] = "Hello World";
}
foreach($hello as $val){ // this will not give you any error or warning.
echo $val;
}
But
if(someConditionIsTrue){
$hello["world"] = "Hello World";
}
foreach($hello as $val){ // this will give you error .
echo $val;
}
If I remember correctly, the first one will produce a warning by PHP if you have error_reporting as E_ALL. You should always use the second method because it explicitly initialises a new array. If you are looking through code and out of nowhere see $hello["hello"] but cannot recall seeing any reference to $hello before, it would be confusing.
The same will happen if you do $hello[] = "World", a warning will be displayed
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.
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...
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)