I have not been able to find a good example for this particular case. Most people who ask this question have a more complex use case and so the answer usually involves a complex solution. I simply have a few variables at the beginning of the script that need to be available throughout all the code including several functions. Otherwise I would have to set it in each function, and considering this is a user set value, changing it all throughout the code is just not possible.
<?php
//**** Example User Config Area ****
$name = "blah";
$tag = "blah";
//**********************************
function taco() {
echo $name; //this function needs to use these user set variables
echo $tag;
}
?>
Everyone says NOT to use global variables. Is this a case where global variables actually DOES make sense? If not, what should I do here to make this work?
It should be noted that those values do not change in the program. They only change if the user edits them. Like a DB location or a username etc.
Just pass these variables:
function taco($name, $tag) {
echo $name;
echo $tag;
}
// and
taco($name, $tag);
There are two main ways you can do configuration in PHP.
The first is to create a configuration object that you can pass around to each function. Some people consider this a little clunky, but it does get around using global variables.
That being said, if you're just trying to store configuration details, a global variable is not a bad option and has been discussed on this site before.
You need to think about your use case. If you're dealing with something that could create a race condition, then global variables are of course a bad idea. If you just want to store some static information to reference throughout your code... it's not the end of the world.
Related
Is there any way I can define a variable such a way that I don't need to global $var1; in every function? Just define it in beginning and keep using where ever needed. I know $GLOBALS exist, but don't want to use it.
First let me try to explain why you shouldn't use globals because they are extremely hard to manage. Say a team member overrides an $ADMIN variable in a file to be 1, and then all code that references the $ADMIN variable will now have the value of 1.
globals are so PHP4, so you need to pick a better design pattern, especially if this is new code.
A way to do this without using the ugly global paradigm is to use a class container. This might be known as a "registry" to some people.
class Container {
public static $setting = "foo";
}
echo Container::$setting;
This makes it more clear where this variable is located, however it has the weakness of not being able to dynamically set properties, because in PHP you cannot do that statically.
If you don't mind creating an object, and setting dynamic variables that way, it would work.
You need to pass the variable as a parameter to that function to avoid using GLOBALS.
The Problematic Scenario (Works ! but avoid it at all costs)
<?php
$test = 1;
function test()
{
global $test;
echo $test; // <--- Prints 1
}
test();
The right way...
<?php
$test = 1;
function test($test)
{
echo $test; // <--- Prints 1
}
test($test); //<--- Pass the $test param here
This behaviour called as superglobal variable. But php has limited predefined list of them: Superglobals.
So you cannot add your own superglobal variable.
Variable scope
My suggestions from the most to less radical:
Edit source code of PHP and add your own superglobals.
Do not write code at all.
Do not use PHP (use different language with different variable scope policy).
Do not use functions (write plain script).
Use constants instead of variables.
Use function params instead of using globals.
Use static variables instead of globals. (\G::$variable)
To include raw JavaScript files into my pages, i've ended up using:
function include_js($jsfile, $basepath = JSPATH){
echo '<script type="text/javascript">';
include($basepath . $jsfile);
echo '</script>';
}
Works fine, and the PHP code inside these JS files is still executing fine, no problem here.
But here is some pseudo code of what i used before:
<script>
var hello = '<?php echo $id; ?>';
</script>
So, here's the problem:
Before, the PHP code used inside my JavaScript files was executed in the same context as the page's one.
Now, it's executed in the context of the include_js() function.
Thus, i don't have access to any of my page's variables anymore. I could fix it with a global $id;, but that was pseudo-code.
Actually, i have NO idea what variables i'll need to have access to.
Any idea how to solve that problem? If you have a better solution than what i'm actually doing inside include_js() to achieve the same goal without the problem i'm talking about, that would be as much appreciated!
You could import all global variables (but Superglobals) into the local scope of the function where you do the include. I don't think it's really a good solution (as it's a hammer) but as you write in your question you don't know which variables are used, so you could localize them like:
$varname = $GLOBALS['varname'];
As an alternative you could inspect the JS file and/or provide the list of variables for a file and add it to the include function as an array. See another answer for some code example.
You could also first pre-include (and throw away) the js file, gather the warnings about undefined variables, import them and then include for real. Some more include/discard/return/variable related chunks of code.
You can use global variables, but a more robust way is to write your own "constant databases". Something like:
class ConstantDB{
public static function set($key, $value){
}
public static function get($key){
}
}
It's just very convenient in many cases. For your particular situation, then you can use
ConstantDB::set("my_id", $id);
and inside the include_js, you can use
ConstantDB::get("my_id");
If a function relies on $_SESSION['some_var'] then the header comment out to make that clear. How do you do it? Just as text, or what?
Or even #param?
You could maybe use #uses to document superglobals
Wow, I never even thought about that. I don't even doc things like that. I would say to just state it in the method detail like
/**
* Takes the some_var session variable and uses it to solve world hunger
* #return food
*/
Makes the most sense to me.
There is #global, but that seems to indicate the creation of a global var. I think #param should only refer to method parameters passed to the method. There is no #note, that I know of.
#global has two usages: to denote a global var's definition, and to highlight a global's usage in a method. This second usage fits your use case.
However, assuming that you are referencing $_SESSION['some_var'] directly in that method, and never denoting it via the "global" keyword, it's possible that phpDocumentor's #global tag won't find it when the method is parsed. As such, #uses is probably the best alternative as a means to highlight the method's reliance on that superglobal.
[1] -- http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.global.pkg.html
If your code depends on something global, or external, to be present in order to work (for example, it requires the sqlite to be installed) you can use #use as Nev mentioned.
HOWEVER...
In general, I would say it is a bad practice to have a function populate or use global variables (or use superglobals), as it breaks the encapsulation of the function and creates a strong dependency between the code inside the function and outside.
If any code external to the function is supposed to create or access those globals, the values should instead be passed as parameters to the function.
For example, instead of
function doMagic(){
if ($_SESSION['use_black_magic'] == true){ // var coming from the outside
$_SESSION['magic_results'] = 'dead chicken';
}else{
$_SESSION['magic_results'] = 'unicorn';
}
}
$_SESSION['use_black_magic'] = false;
doMagic();
echo $_SESSION['magic_results']; // (unicorn) variable set within doMagic()
it should be
function doMagic( $use_black_magic = true ){
if ($use_black_magic == true){
return 'dead chicken';
}else{
return 'unicorn';
}
}
$magic_results = doMagic( false );
echo $magic_results; // unicorn
This way, doMagic() doesn't need to know anything about where the results are to be stored, nor where to find the parameter value. And the external code, doesn't need to know that the function doMagic() is doing something with $_SESSION variables.
As soon as your code grows just a little bit, maintaining, sharing, debugging, and extending this kind of code becomes a nightmare...
http://en.wikipedia.org/wiki/Separation_of_concerns
I have a function that retrieves some data from the database, formats it as HTML and then stores this HTML into a variable, $output. The problem is that $output cannot be echoed on the screen now, only later, after other functions run. Also this data must be retrieved at this stage, not later.
So how can I call this $output variable in another function, after output to the screen has started?
You could define $output in the main script, and import it into a function:
function output()
{
global $output;
This will probably work for your situation at hand. However, it is considered bad practice to use the global variable space with stuff like this, and rightly so. (Believe me, I've done it for years. :)
There are some other approaches that are better for long-term code quality and maintainability.
Global config array
You could either keep one global array for all global settings. Do this somewhere in your main script:
$config = array();
$config["output"] = "<html>.......</htmL>";
$config["user_language"] = "en";
.....
you import the configuration array into the function like so:
function output()
{ global $config;
echo $config["output"];
Registry pattern
if you want to do some reading, you could use something more advanced like the Registry Pattern. The snippet shown here looks a nice example for a registry. The Zend Framework also has a class for this.
But things like a Registry are really, really advanced, and probably not necessary for you at this point. I would suggest using one central config array. Should the need for something more complex arise, the config array is easy to find and replace.
Context: Are global variables in PHP considered bad practice?
welcome to using returns, and passing parameters:
DO NOT USE global , it breaks encapsulation, one of the cornerstones of object oriented programming, and can lead to incredibly hard to maintain code.
<?php
function doSomethingInDb(){
$value = db_result(); //something from the database, this is psuedo code
return $value
}
function displaySomethingFromDb($input){
echo($input); //or some other way of displaying
}
//calulate results
$output = doSomethinginDb();
//do other stuff...
//output the result when you need it...
displaySomethingFromDb($output);
You have to pass the variable via a function argument, or define it as global inside the function.
$output = '<p>macilaci</p>';
function doesathing($output)
{
echo $output;
}
OR
function doesathing()
{
global $output;
echo $output;
}
don't put the data in a variable inside the function which retrieves it.
function retrieve(...)
{
... fetch from db
return $rv;
}
function other() {...}
function still($data)
{
...
echo $data;
}
$output = retrieve(...);
other();
still($output);
Rather than just putting this snippet into a global variable, IMHO a better solution is to use a templating system to construct the elements of the page.
NB I'm not suggesting you immediately rush out and start downloading Smarty - although there are benefits and drawbacks to completely seperating logic and presentation, there are only benefits in taking a modular approach to your screen layout.
C.
Put the following line at the start of the function that defines $output:
global $output;
Put the same line at the start of any function that will make use of it.
(This will not work, or will interfere with other variables, if there is already a variable called $output in the global scope.)
Use Session
For example:
session_start();
$query = '...........';
$result = mysql_query($query);
$_SESSION['mysqlResult'] = $result;
Now you can use it from any page at any time by simply calling like this
$myresult = $_SESSION['mysqlResult'];
We use instantiate and put system critical objects in $GLOBALS for easy access from anywhere (e.g. DB, Cache, User, etc.).
We use $GLOBALS so much that it would (yes, really) drop the amount of code quite a bit if I could reference it like $G = &$GLOBALS for a shorthand call.
The problem is that, per my experience and several hours of Googling, I have not found any construct in PHP which allows you to 'flag' a var as global, making $GLOBALS first class, and everything else second class.
Am I missing something? Is this possible?
<?php
function &G($name) {
if(func_num_args() > 1) {
$GLOBALS[$name] = func_get_arg(1);
}
return $GLOBALS[$name];
}
G('test', 'hey');
echo G('test'); // outputs hey
echo $test; // outputs hey
$b =& G('test');
$b = 'hello';
echo G('test'); // outputs hello
echo $test; // outputs hello
Instead of putting everything into $GLOBALS you might want to take a look into the registry concept that is widespread in the php world.
However, having many global variables/objects is a sign of bad design and high coupling. Using something like $G guarantees spaghetti code and a soon-to-come maintenance nightmare. Who cares if you can drop the amount of code by a few characters?
No, but you can use a little trick. Create a global function by the same name as your global var, and have it return the global instance. Eg.:
function db() {
return $GLOBALS['db'];
}
You can now write your code as:
...
$stuffs = db()->query("select * from stuff");
...
You may recognise this as a variant over the singleton pattern, but a syntactically much more pleasant one.
Others have mentioned it, but you should also consider not using global objects in the first place. I generally prefer to pass objects in to there where it's needed (dependency injection). I'm not overly found of the registry pattern though.
global $variable; //?
In addition to the registry concept Middus points out, there are several approaches and concepts around this, some of which you can find in the answers to this question:
In a PHP project, how do you organize and access your helper objects?