Is memory of local function variables cleared on function end? - php

Consider the following situation..
$var = 'Lots of information';
function go($var) {
// Do stuff
}
Now, when PHP exits the function, does it clear the memory automatically of all local variables within the function or should I be doing:
unset($var);
...within the function on any local variables that store large amounts of data?

It will clear itself inside the function scope. This means that the $var parameter of the function will no longer exists after the function call.
Notice that $var = 'Lots of information'; is outside the function block therefore will not be cleared automatically. In this case $var in the global scope and $var in the function scope are two different things and inside the function block only $var in the function scope will exists.

This question goes to the concept of Variable Scope. Inside the function, the variables are "contained" and unless declared global, are not related to variables of the same name outside of the function. So if you created a large variable inside a function, and you want to unset() it, you would need to unset() inside the function. This page is important, especially the part about "global" and "static" variables. PHP also has a way to pass a variable by reference using an ampersand in front of the variable name. In that case, the function is operating on the variable itself, not the function's copy of the variable.
http://php.net/manual/en/language.variables.scope.php

Related

PHP get_defined_vars() doesn't print superglobals inside function

I'm working through debugging some legacy code, and want to use a pre-built function that is essentially a wrapper for get_defined_vars().
Running this code directly in the calling file prints an array of variables as expected:
print_r(get_defined_vars());
However, wrapping this in a simplified version of my function prints an empty array:
function debugAllVars() {
print_r(get_defined_vars());
}
debugAllVars();
Regardless of the scope, I would have expected "superglobal" variables such as $_POST to be present in the output.
Why is the output completely empty?
get_defined_vars() prints all variables in the "symbol table" of the scope where it is called. When you try to wrap it as debugAllVars, you introduce a new scope, which has a new symbol table.
For a standalone function like this, the symbol table consists of:
the function's parameters
any global variables imported into the current scope using the global keyword
any static variables declared in the current scope with the static keyword (even if not assigned a value)
any variables implicitly declared by assigning a value to them
any variables implicitly declared by taking a reference to them (e.g. $foo = &$bar would implicitly declare $bar if not already defined; $foo = $bar would not)
Notably, this list does not include the superglobals, such as $_GET, $_POST, and $GLOBALS. If you run get_defined_vars() in global scope (i.e. outside any function), you will see that these are present in the symbol table there, which is also what the magic variable $GLOBALS points to. So, why are they not present in every scope, and how can we use them if they're not?
For this, we need to dig into the internals of the implementation, where these variables are referred to as "auto-globals" rather than "superglobals".
The answer to why is performance: the naive implementation of an "auto-global" would be one that acted as though every function automatically had a line at the top reading global $_GET, $_POST, ...;. However, this would mean copying all those variables into the symbol table before every function was run, even if they weren't used.
So instead, these variables are special-cased in the compiler, while converting your PHP code into the internal "opcodes" used by the VM which executes the code.
Using a source code browser, we can see how this works.
The key function is zend_is_auto_global in zend_compile.c (taken from current master, effectively PHP 7.2):
zend_bool zend_is_auto_global(zend_string *name) /* {{{ */
{
zend_auto_global *auto_global;
if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
if (auto_global->armed) {
auto_global->armed = auto_global->auto_global_callback(auto_global->name);
}
return 1;
}
return 0;
}
Here, name is the name of a variable, and CG means "compiler globals", so the main job of this function is to say "if the variable name given is in a compiler-global hash called auto_globals, return 1". The additional call to auto_global_callback allows the variable to be "lazy loaded", and only populated when it is first referenced.
The main usage of that function appears to be this conditional, in zend_compile_simple_var_no_cv:
if (name_node.op_type == IS_CONST &&
zend_is_auto_global(Z_STR(name_node.u.constant))) {
opline->extended_value = ZEND_FETCH_GLOBAL;
} else {
opline->extended_value = ZEND_FETCH_LOCAL;
}
In other words, if the variable name you referenced is in the list of superglobals, the compiler switches the opcode into a different mode, so that when it is executed, it looks up the variable globally rather than locally.
get_defined_vars gets all variables defined in the scope that it's called in. Your debugAllVars function introduces a new scope, so get_defined_vars will at most give you all variables within debugAllVars. It cannot give you variables from the caller's scope.
Also see Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?.

Defining a global variable, and including functions that require it?

I have six functions that require a global variable. In an attempt to reduce redundancy, I wrote a new function that is triggered rather than triggering all six. This one function has a global $var that is required by the other functions.
So, it looks like this
function one_function_for_the_rest() {
global $importantVar;
functionOne();
functionTwo();
functionThree();
}
but the global variable is not being seen by the called functions. Am I doing this incorrectly, or is this a limitation I was not aware of?
You're not doing it correctly as the variable is defined when on_function_for... is called. An easier way for this would be just to have $importantVar; at the start of the code.
Or wrap your functions inside a class and put the variable inside the class.
e: so basically do : function myFunc($important) { stuff } and when calling the function do myFunc($importantVar)
example :
$asd = "lol";
class myclass {
public function lol($asd) {
echo $asd;
}
}
$obj = new myclass;
$obj->lol($asd);
You're not doing it correctly. Each function either needs to use the global scope identifier, like global $importantVar;, or have $importantVar passed as a parameter. Otherwise, the other functions don't have $importantVar in their respective scopes.
Simply calling a function from within one_function_for_the_rest does not tell that other function anything about global variables or variables used in one_function_for_the_rest. In technical terms, your function calls do not bring $importantVar into the respective scopes of functionOne, functionTwo, or functionThree.
PHP does not have the same scoping rules as most other languages have. That is the downside to not having to declare variables with var as in JavaScript or other similar constructs.
Basically in PHP, every function used is only available in that function. There are three exceptions:
The global keyword
The $this variable inside objects. This one is also "magic" as it's also available inside anonymous functions defined inside a class.
When declaring an anonymous functions you can bind variables to it using use.

global variables from one function to another

Lets say I have this:
function myFunc()
{
global $distinct_variable;
die ($distinct_variable);
}
function anotherFunc()
{
$distinct_variable = 'Hello World';
myFunc();
}
anotherFunc();
For anotherFunc() to correctly show 'Hello World', it must be written like this
{
global $distinct_variable;
$distinct_variable = 'Hello World';
myFunc();
}
Now it will show the message, but why must I global $distinct_variable; in anotherFunc() since it is a global in myFunc() which is within anotherFunc()
Yes, I know that variables inside functions won't go outside of them, but I was thinking it should have worked...
Could someone explain why isn't it working?
Thanks.
Thank you for your answers, I get it now :)
A global variable is exactly that - it exists in the GLOBAL scope ONLY.
Everything in PHP (except superglobals) exist in only one scope - be that the global scope, or the scope of a function/method. Scope does not cascade - so just because you have a variable in an "outer" function does not make it available to an "inner" function.
Similarly, global fetches the variables defined in the GLOBAL scope only (the top-most scope), not simply "the scope above this one, from which I was called". This is what you tried to do, but it absolutely will not work. This level of finer-grained control is what function arguments/return values are for.
Each function has its own symbol table. There is also a global symbol table. Just because one function is being called from within another doesn't mean that the variables declared global in one are global in the other, or inherited from the other. They still refer to the variable in the "local" symbol table by default.
Doing global $somevar; echo $somevar boils down to echo $GLOBALS['somevar'];. That $GLOBALS superglobal does not include variables that were defined inside a function: only truly 'global' vars, which exist at the top level of the script.

PHP include_once inside a function to have global effect

I have a function in php:
function importSomething(){
include_once('something.php');
}
How do i make it sot that the include_once has a global effect? That everything imported will be included in the global scope?
You can return all the variables in the file like so...
function importSomething(){
return include_once 'something.php';
}
So long as something.php looks like...
<?php
return array(
'abc',
'def'
);
Which you could assign to a global variable...
$global = importSomething();
echo $global[0];
If you wanted to get really crazy, you could extract() all those array members into the scope (global in your case).
include() and friends are scope-restricted. You can't change the scope that the included content applies to unless you move the calls out of the function's scope.
I guess a workaround would be to return the filename from your function instead, and call it passing its result to include_once()...
function importSomething() {
return 'something.php';
}
include_once(importSomething());
It doesn't look as nice, and you can only return one at a time (unless you return an array of filenames, loop through it and call include_once() each time), but scoping is an issue with that language construct.
If you want ordinary variable definitions to be teleported into the global scope automatically, you could also try:
function importSomething(){
include_once('something.php');
$GLOBALS += get_defined_vars();
}
However, it if it's really just a single configuration array, I would also opt for the more explicit and reusable return method.
I know this answer is really late for this user, but this is my solution:
inside your function, simply declare any of the vars you need to ovewrite as global.
Example:
Need to have the $GLOBALS['text'] set to "yes":
Contents of index.php:
function setText()
{
global $text;
include("setup.php");
}
setText();
echo 'the value of $text is "'.$text.'"'; // output: the value of $text is "yes"
Contents of setup.php:
$text = "yes";
The solution is similar to mario's, however, only explicitely globally-declared vars are overwritten.
All variables brought in from an included file inherit current variable scope of the including line. Classes and functions take on global scope though so it depends what your importing.
http://uk.php.net/manual/en/function.include.php
(Final Paragraph before example)

global array in php

i have to function in two different files.
one of them should add a new item to an array each time is called and the array should be accessible .what i did for it is :
function1(){
global $array;
$array[] = 'hi';
}
but it just create one item in array even if i call this function 4 times .
What you did should work.
<?php
function function1(){
global $array;
$array[] = 'hi';
}
function1();
function1();
function1();
print_r($array);
Test it.
You probably have another problem. Please note that the lifetime of all variables is the current run of your script. They won't exist in a successive run. For that you need to use some sort of persistence like session, cookie, file system, database.
For more help post your complete code.
I'm a bit confused by the wording of your question. When you say "i have to function in two different files." does you mean you have "two" functions?
If you have two functions both trying to use your $array variable, you'll need to call global $array; in both functions.
The reason for this is that global is a bit misleading. All it's really doing is assigning a reference to a member of $_GLOBALS to a variable in the local scope which has the same name as the $_GLOBALS index. In other words, if you do something like this:
global $variable;
it's essentially the same thing as saying this:
$variable =& $_GLOBALS['variable']; (assign by reference)
The actual variable $variable is still scoped at the function level, it just happens to have a reference to a global variable.
The implication of this is that if you don't define global $variable in every function, you're just creating a brand new variable within the scope of that function. When the function ends, the variable is unset and any changes made to it within the function are lost.
With all of that said, global variables still tend to be a bad idea. It's a lot clearer if you just maintain a local variable, and pass it as a parameter to other functions when needed.
I had the problem that a global $array was not known in a function. But when I placed the first def: $array = array(); before the first function call, it worked.

Categories