I can't access superglobals via variable variables inside a function. Am I the source of the problem or is it one of PHP's subtleties? And how to bypass it?
print_r(${'_GET'});
works fine
$g_var = '_GET';
print_r(${$g_var});
Gives me a Notice: Undefined variable: _GET
PHP isn't able to recognize that this is a global variable access:
It compiles $_GET and ${'_GET'} to the same opcode sequence, namely a global FETCH_R. ${$g_var} on the other hand will result in a local FETCH_R.
This is also mentioned in the docs:
Superglobals cannot be used as variable variables inside functions or class methods.
You can possibly bypass it using $GLOBALS superglobal variable. Instead of writing
function & getSuperGlobal($name) {
return ${"_$name"};
}
you can write
function & getSuperGlobal($name) {
return $GLOBALS["_$name"];
}
and the results will equal.
It seems that the last PHP versions are dealing fine with that problem.
Next code works fine with PHP 5.5.9.
<?php
function foo() {
print_r(${'_SERVER'});
}
foo();
Related
I have a little function that has a string parameter. Now I want a variable defined within that function to be known outside of that function where the function is being executed.
function somefunc($hello) {
$hello = "hi";
$bye = "bye";
return $bye;
}
And using that function in another php script.
somefunc("hi");
echo $bye;
The other script in which the function is being used and in which I'm trying to echo out the variable keeps telling me that the variable bye has not been defined. How can I get its value without making it global? The other script has the function included in it properly, so this cant be the problem.
Thanks in advance for any help!!
Your syntax is the problem. To fix the current issue you need to first define a variable with the return variable or echo it.
function somefunc($hello) {
$hello = "hi";
$bye = "bye"
return $bye;
}
echo somefunc("hi"); // bye
// --- or ---
$bye = somefunc("hi");
echo $bye; // bye
The variable defined within that function cannot be accessed outside of its context (the function).
The scope of a variable is the context within which it is defined. For the most part all PHP variables only have a single scope. This single scope spans included and required files as well.
For a better understanding of variable scopes check out the docs in the PHP manual; they are pretty good at breaking it down.
You could also look at global references of variable in the PHP manual and it may work for what you are trying to do.
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?.
I have a bunch of HTML and PHP code and in the template file it works fine but I'm trying to put it in a PHP function and now when I run the page I get the error Undefined variable: variableName
Here's some code:
function testFunction()
{
foreach ($variableName as $variable):
echo 'tasf';
endforeach;
}
Inside that function $variableName cannot be found but if I move it outside the function it can be found just fine. I'm doing this within a symfony php template file if it matters.
Simple issue of variable scope. If that variable is defined outside the function then either you need to pass it there or declare it global
See Manual Here
PHP Variable Scope
$str = 'Hello World';
echo $str; // works fine
function foo($bar){
echo $bar; // passed as function argument. works fine
}
foo($str);
function bar(){
global $str;
echo $str; // passed from global. works fine
}
Function scope means that variables referenced inside a function, must be declared within it, or passed...
function testFunction($variableName)
{
foreach ($variableName as $variable):
echo 'tasf';
endforeach;
}
Here's a link to the PHP manual on Variable Scope.
Under no circumstances should you resort to using global variables. There is always a better way, and doing so is considered poor practice. It makes your code difficult to follow as it means anyone else may have to read all of it in order to understand what's going on.
You need to use the global keyword to make this happen.
global should be used sparingly however, and can have unintended side effects.
I have some function (pasted below little piece of function), which I used as separate function and it worked well.
Now I want to move this functon into some class. As you see, it works with $_SESSION and $_COOKIE.
Question is, is it required to send $_SESSION and $_COOKIE as input data while calling this function (I mean something like that: calling like protect($_SESSION, $_COOKIE) and then fetch them from inside function)? or it will work without sending them?
...
public function protect() {
session_start();
if (isset($_SESSION['HTTP_USER_AGENT'])) {
if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) {
$this->logout();
exit;
}
}
if (!isset($_SESSION['id']) && !isset($_SESSION['login'])) {
if (isset($_COOKIE['id']) && isset($_COOKIE['key'])) {
...
$_COOKIE and $_SESSION are superglobals, which means they are available everywhere. You never need to import them, pass them as arguments or anything similar, they are always available in any scope.
For this reason, they should always be treated as read-only - assigning a new value to them will affect the rest of the scripts execution in every scope.
$_SESSION AND $_COOKIE are superglobals, meaning they are available in all scopes. So it is not strictly necessary to pass them as parameters to functions.
However, there is a benefit in passing them as parameters when you start unit testing. Parameters will make it considerably easier to test values to the function without needing them to be available in $_SESSION or $_COOKIE.
You dont need to pass the $_SESSION or $_COOKIE variables as they are superglobals - accessible from anywhere ... from the docs :
This is a 'superglobal', or automatic global, variable. This simply means that it is available in all scopes throughout a script. There is no need to do global $variable; to access it within functions or methods.
Why does THIS not work when called via e.g. wd(1) (it always returns '-2')?
$zoom=$user['zoom'];
function wd($hrs){
return $hrs*$zoom-2;
}
But THIS works fine:
function wd($hrs){
return $hrs*30-2;
}
Assuming this was a casting problem, I tried all sorts of variations like
(int)$hrs * ((int)$zoom)
or
(int)$hrs * (float)$zoom
but no success :(
Any help would be appreciated.
(And BTW, does it matter whether the function is located within
include('header.php')
-- although I tried it both within and outside the header?)
EDIT: You should pass that variable as an argument to the function, but if you absolutely need to keep the variable global, do the following.
You need to bring the global into scope:
$zoom=$user['zoom'];
function wd($hrs){
global $zoom;
return $hrs*$zoom-2;
}
This isn't a casting issue - it's because you're trying to use a variable that's out of scope.
Whilst you'll need to read the PHP docs for the full low-down, at a basic level, you can only access variables that are defined within the same function or method. (Although you can use the global keyword to access global variables. That said, global variables are less than ideal.)
As such, you could simply update your function to also pass in 'zoom' as a parameter as follows:
function wd($hrs, $zoom){
return $hrs*$zoom-2;
}
$zoom=$user['zoom'];
function wd($hrs){
// there is no variable $zoom within the function's visibility scope
// so you will get a "Notice: undefined variable 'zoom'" here.
return $hrs*$zoom-2;
}
see http://docs.php.net/language.variables.scope