I'm a Java developer and recently I'v been tasked with PHP code review. While going through the PHP source code, I'v noticed that a variable is initialised in an if, while, switch and do statement then same variable is used outside these statements. Below is a fragment the code
Senario 1
if ($status == 200) {
$messageCode = "SC001";
}
// Here, use the $message variable that is declared in an if
$queryDb->selectStatusCode($message);
Senario 2
foreach ($value->children() as $k => $v) {
if ($k == "status") {
$messageCode = $v;
}
}
// Here, use the $messageCode variable that is declared in an foreach
$messageCode ....
In my understanding, a variable declared in a control statement is only accessible with in the control code block.
My question is,
what is the variable scope of a variable in a PHP function and how is this variable accessible outside a control statement block?
How is that above code working and producing expected results?
In PHP control statements have no separate scope. They share the scope with the outer function or the global scope if no function is present. (PHP: Variable scope).
$foo = 'bar';
function foobar() {
$foo = 'baz';
// will output 'baz'
echo $foo;
}
// will output 'bar'
echo $foo;
Your variables will have the last value assigned within the control structure. It is good practice to initialize the variable before the control structure but it is not required.
// it is good practice to declare the variable before
// to avoid undefined variables. but it is not required.
$foo = 'bar';
if (true == false) {
$foo = 'baz';
}
// do something with $foo here
Namespaces do not affect variable scope. They only affect classes, interfaces, functions and constants (PHP: Namespaces Overview). The following code will output 'baz':
namespace A {
$foo = 'bar';
}
namespace B {
// namespace does not affect variables
// so previous value is overwritten
$foo = 'baz';
}
namespace {
// prints 'baz'
echo $foo;
}
Related
If I have a file a.php which I can't edit.
<?php
$a = 1;
function a() {
global $a;
echo $a;
}
a();
then running php a.php prints 1 nicely. But if I have b.php:
<?php
function b() {
include "a.php";
}
b();
Then running php b.php doesn't print anything.
What can I type before the include "a.php" to make it behave the same without editing a.php?
(Obviously other than defining $a. In my real-world example it has to work for a complicated a.php).
Try adding a global into your new function:
function b() {
global $a;
include "a.php";
}
At the moment I wonder if PHP is treating $a as local to your b() function.
Addendum: in response to your comment, it seems that you need to grab arbitrary variables that your include has created locally in your function, and remake them as global. This works for me on 5.3.20 on OSX 10.6.8:
function b() {
include 'a.php';
// Move variables into global space
foreach (get_defined_vars() as $name => $value) {
global $$name;
// global wipes the value, so just reset it
$$name = $value;
echo "Declared $name as global\n";
}
}
b();
// Your global vars should be available here
Obviously you can remove the echo once you're happy it works.
Defining a function inside a function? Yuck. But I guess you have a real-world situation that doesn't allow any other way. But for the record, this is REALLY BAD PRACTICE
Adding global $a to b() should work.
function b() {
global $a;
include "a.php";
}
I don't know what variables need to be defined. a.php is really complicated
Then the only way I can think of is not using a function in b.php, so you're in the global scope when including a.php. I can see no other way.
It sounds like a.php is some legacy or 3rd party script that you have to wrap in your own application. I had a similar problem once and the solution was not pretty. First, you will have to find out, what global variables exist (grep global or similar helps).
This is the relevant part of my "Script Adapter" class:
private function _includeScript($file, $globals)
{
foreach ($globals as $global) {
global $$global;
}
ob_start();
require $file;
$this->_response->setBody(ob_get_clean());
}
As you see, I had to catch the output too. The class also emulates $_GET and catches header calls to assign everything to a Response object, but for your case only this method is important. It gets called with the file name and an array of global variable names as parameters:
_includeScript('a.php', array('a'));
In PHP, if you want to access variable in the outer scope, you need to declare it explicitly, e.g.
$foo = 'bar';
func (function() use ($foo) {
echo $foo;
});
But in JavaScript, they are implicit, e.g.
foo = 'bar';
func (function() {
console.log(foo);
});
What are the advantages and disadvantage of these two type of closure?
In PHP, if you want to access variable in the outer scope, you need to
declare it explicitly [...] use ($foo)
Technically, your function is not accessing $foo in the outer scope. To do that, you would need to:
$foo = 'bar';
$func = function() {
global $foo;
echo $foo;
};
This is not a closure. No variables are closed in with the function. If the value of $foo is changed, the next call to func will reflect that:
$func(); // bar
$foo = 'baz';
$func(); // baz
However, if we close in $foo with func:
$foo = 'bar';
$func = function() use ($foo) {
echo $foo;
};
$func(); // bar
$foo = 'baz';
$func(); // bar
func's $foo will retain it's value because it's been closed-over into the function.
To do the same in JavaScript, you simply create a function within a function and a closure will be created (giving the inner function access to the enclosing function's scope):
function getFunc(foo) {
return function () {
console.log(foo);
};
}
foo = "bar";
func = getFunc(foo);
func(); // bar
foo = "baz";
func(); // bar
What are the advantages and disadvantage of these two type of closure?
Using a "heap" type scope, as opposed to stack, so that the variable environment stays attached to the function allows first-class functions to be much more flexible as they can be passed around and recalled without worrying about creating (or passing in) a certain set of variables in order to make the function usable.
PHP does this because it doesn't know otherwise whether you meant to use the outer variable or not, since an unset variable acts like an empty string. This type of closure is therefore required for PHP, but not for Javascript.
I have a problem with the below:-
//index.php
<?php
define('PATH','Ajfit/');
/* Get all the required files and functions */
require(PATH . 'settings.inc.php');
require(PATH . 'inc/common.inc.php');
?>
//setting.inc.php
<?php
$settings['language']='English';
?>
//inc/common.inc.php
<?php
//global $settings, $lang, $_SESSION; //$setting = null????
$language = $settings['language']; //$language is still null
?>
when i try and access the global variable $settings within common.inc.php it is set null even though i set the variable within setting.inc.php. If i debug, when i step out of setting.inc.php the $settings valiable is set within the index.php, however when i step into common.inc.php the $settings valiable is set to null.
Does anyone have any ideas?
Answer: In the inc/common.inc.php file, you don't need to use the global keyword, the variable is already accessible. Using global redefines the variable, and is thus made null.
Explanation:
Variable Scope is the key here. The global keyword is only required when scope changes. The scope of regular files (including include()s) is all the same, so all of your variables are accessible by any php in the same scope, even if it comes from a different file.
An example of where you need to use global is inside of functions. The scope of a function is different than that of plain php, which is different from class scope, and so on.
Example:
//foo.php
$foo = "bar";
echo $foo; //prints "bar" since scope hasn't changed.
function zoo() {
echo $foo; //prints "" because of scope change.
}
function zoo2() {
global $foo;
echo $foo; //prints "bar" because $foo is recognized as in a higher scope.
}
include('bar.php');
//bar.php
echo $foo; //prints "bar" because scope still hasn't changed.
function zoo3() {
echo $foo; //prints "" for the same reason as in zoo()
}
function zoo4() {
global $foo;
echo $foo; //prints "bar" for the same reason as in zoo2()
}
More Information:
If you want more information on when to use global and when not to, check the php.net documentation on variable scope.
I have two PHP files. In the first I set a cookie based on a $_GET value, and then call a function which then sends this value on to the other file. This is some code which I'm using in join.php:
include('inc/processJoin.php');
setcookie("site_Referral", $_GET['rid'], time()+10000);
$joinProc = new processJoin();
$joinProc->grabReferral($_COOKIE["site_Referral"]);
The other file (processJoin.php) will then send this value (among others) to further files which will process and insert the data into the database.
The problem I'm having is that when the grabReferral() function in processJoin.php is called, the $referralID variable isn't being defined on a global scale - other functions in processJoin.php can't seem to access it to send to other files/processes.
I've tried this in processJoin.php:
grabReferral($rid) {
global $ref_id;
$ref_id = $rid;
}
someOtherFunction() {
sendValue($ref_id);
}
But the someOtherFunction can't seem to access or use the $ref_id value. I've also tried using define() to no avail. What am I doing wrong?
you have to define the global var in the second function as well..
// global scope
$ref_id = 1;
grabReferral($rid){
global $ref_id;
$ref_id = $rid;
}
someOtherFunction(){
global $ref_id;
sendValue($ref_id);
}
felix
personally, I would recommend the $GLOBALS super variable.
function foo(){
$GLOBALS['foobar'] = 'foobar';
}
function bar(){
echo $GLOBALS['foobar'];
}
foo();
bar();
DEMO
This is a simple and working code to initialize global variable from a function :
function doit()
{
$GLOBALS['val'] = 'bar';
}
doit();
echo $val;
Gives the output as :
bar
The following works.
<?php
foo();
bar();
function foo()
{
global $jabberwocky;
$jabberwocky="Jabberwocky<br>";
bar();
}
function bar()
{
global $jabberwocky;
echo $jabberwocky;
}
?>
to produce:
Jabberwocky
Jabberwocky
So it seems that a variable first declared as global inside a function and then initalised inside that function acquires global scope.
The global keyword lets you access a global variable, not create one. Global variables are the ones created in the outermost scope (i.e. not inside a function or class), and are not accessible inside function unless you declare them with global.
Disclaimer: none of this code was tested, but it definitely gets the point across.
Choose a name for the variable you want to be available in the global scope.
Within the function, assign a value to the name index of the $GLOBALS array.
function my_function(){
//...
$GLOBALS['myGlobalVariable'] = 42; //globalize variable
//...
}
Now when you want to access the variable from code running in the global scope, i.e. NOT within a function, you can simply use $ name to access it, without referencing the $GLOBALS array.
<?php
//<global scope>
echo $myGlobalVariable; //outputs "42"
//</global scope>
?>
To access your global variable from a non-global scope such as a function or an object, you have two options:
Access it through the appropriate index of the $GLOBALS array. Ex: $GLOBALS['myGlobalVariable'] This takes a long time to type, especially if you need to use the global variable multiple times in your non-global scope.
A more concise way is to import your global variable into the local scope by using the 'global' statement. After using this statement, you can reference the global variable as though it were a local variable. Changes you make to the variable will be reflected globally.
//<non global scopes>
function a(){
//...
global $myGlobalVariable;
echo $myGlobalVariable; // outputs "42"
//...
}
function b(){
//...
echo $GLOBALS['myGlobalVariable']; // outputs "42"
echo $myGlobalVariable; // outputs "" (nothing)
// ^also generates warning - variable not defined
//...
}
//</non global scopes>
Please use global variables in any language with caution, especially in PHP.
See the following resources for discussion of global variables:
http://chateau-logic.com/content/dangers-global-variables-revisited-because-php
http://c2.com/cgi/wiki?GlobalVariablesAreBad
The visibility of a variable
I hope that helped
<?php
$a = 1;
$b = 2;
function Sum()
{
global $a, $b;
$b = $a + $b;
}
Sum();
echo $b;
?>
I understand that if you declare a variable within a php function with the 'global' keyword it will reference a variable declared outside the function, but why would a php programmer want to declare a variable outside of a function scope as 'global?' Thanks!
I understand what this does:
<?
$a = 1;
function $boo() {
global $a;
echo $a;
}
?>
But what I'm getting at is why would I want to do this?
<?
global $a;
function $boo() {
//foo
}
?>
It has to do with php scope
If you have file a.php that has a class like this
<?
class test()
{
function test()
{
include('b.php');
}
}
?>
and a file b.php
<?
$a = 1;
?>
Then $a will only be accessible in the scope of function test()
if you have global $a in b.php, $a then becomes a global variable
here's the php doc about it : http://php.net/manual/en/function.include.php
I have no idea why you would want to do that. For all intents and purposes (unless I am very, very much mistaken) this is exactly the same as just:
<?
var $a;
function $boo() {
// foo
}
?>
Which in turn is the very same as
<?
function $boo() {
// foo
}
?>
because you generally don't have to instantiate your variables in PHP.
Very curious why you're using variably-named functions though? (function $boo() {} )
Well, IMHO the use of global variables is a poor programming practice. It can cause unintended side-effects in your program which are hard to debug, and makes it harder to maintain.