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?
Related
I'm creating a basic framework in PHP. I need to pass data for the current page into different functions, allow them to modify and save it, and then pass it back to the page to be displayed. I was originally planning on storing the data in a global variable like $GLOBALS['data'], but I'm starting to think that using a global is a bad idea. So I'm thinking that instead I will put a static variable in the system class, and access it using system::$data. So, my question is, which would be better and why?
This:
$GLOBALS['data'] = array();
$GLOBALS['data']['page_title'] = 'Home';
echo $GLOBALS['data']['page_title'];
Or this:
class system
{
public static $data = array()
}
function data($new_var)
{
system::$data = array_merge(system::$data, $new_var);
}
data(array('page_title' => 'Home'));
echo system::$data['page_title'];
There really is no difference between a global variable and a public static variable. The class variable is namespaced a tiny bit better, but that hardly makes any difference. Both are accessible anywhere at any time and both are global state.
As it happens, I just wrote an exhaustive article on the subject:
How Not To Kill Your Testability Using Statics
So, my question is, which would be better and why?
You already sense that there is some problem putting this all into globals. Although you have developed some thoughts to encapsulate things into a class.
I think that is a good starting point. Let's add some more spice to the cooking to get this more fluent at the beginning:
$data = new ArrayObject(array());
$data['page_title'] = 'Home';
You have created an object now that you can pass along containing your data. Just pass $data to the area's where it's needed. No global or global static variable needed.
You can even make that type more concrete later on by extending from ArrayObject with your own type.
For the record.
Pro of static:
Clarity of the code. For example:
function fn() {
System::data()
}
versus
function fn() {
global $system;
$system->data()
}
Cons of static:
If you are using psr-4 then you must add (and include) a new class (and a new file). It impacts the performance even if you use opcache (opcache aleviates it but it's not magic).
You must define a block of code.
I'm creating a basic framework in PHP. I need to pass data for the current page into different functions, allow them to modify and save it, and then pass it back to the page to be displayed. I was originally planning on storing the data in a global variable like $GLOBALS['data'], but I'm starting to think that using a global is a bad idea. So I'm thinking that instead I will put a static variable in the system class, and access it using system::$data. So, my question is, which would be better and why?
This:
$GLOBALS['data'] = array();
$GLOBALS['data']['page_title'] = 'Home';
echo $GLOBALS['data']['page_title'];
Or this:
class system
{
public static $data = array()
}
function data($new_var)
{
system::$data = array_merge(system::$data, $new_var);
}
data(array('page_title' => 'Home'));
echo system::$data['page_title'];
There really is no difference between a global variable and a public static variable. The class variable is namespaced a tiny bit better, but that hardly makes any difference. Both are accessible anywhere at any time and both are global state.
As it happens, I just wrote an exhaustive article on the subject:
How Not To Kill Your Testability Using Statics
So, my question is, which would be better and why?
You already sense that there is some problem putting this all into globals. Although you have developed some thoughts to encapsulate things into a class.
I think that is a good starting point. Let's add some more spice to the cooking to get this more fluent at the beginning:
$data = new ArrayObject(array());
$data['page_title'] = 'Home';
You have created an object now that you can pass along containing your data. Just pass $data to the area's where it's needed. No global or global static variable needed.
You can even make that type more concrete later on by extending from ArrayObject with your own type.
For the record.
Pro of static:
Clarity of the code. For example:
function fn() {
System::data()
}
versus
function fn() {
global $system;
$system->data()
}
Cons of static:
If you are using psr-4 then you must add (and include) a new class (and a new file). It impacts the performance even if you use opcache (opcache aleviates it but it's not magic).
You must define a block of code.
I was reading an article about Data Encapsulation in PHP, and the author explained in such a way that it made me to wonder if this is really possible? here is what he said.
The primary purpose of encapsulation
(scope) is to ensure that you write
code that can't be broken. This
applies to scope in general, so let me
use a simpler example of a local
variable inside a function:
function xyz ($x) {
$y = 1;
while ($y <= 10) {
$array[] = $y * $x;
$y++;
}
return $array;
}
The purpose of this function is to
pass a number and return an array. The
example code is pretty basic. In order
for function xyz() to be dependable,
you need to be guaranteed that it does
the exact same thing every time. So
what if someone had the ability to
from the outside change that initial
value of $y or $array? Or even $x? If
you were able to do that from outside
of the function, you could no longer
guarantee what that function is
returning.
Now this made me wonder can i really change the value of local variable sitting inside the function without using any argument as demonstrated above ?? if it is possible how do i do it?
thank you..
For this example you wouldn't be able to change any of the variables, because they're all declared inside of the function.
But if you had a class with a public class variable, you could change that outside of the class if you wanted to. (That's bad form and might screw a lot of things up, though.)
Unless you add a magic setter method ( __set($key,$value) ), and configure it in such a way that you can access that internal member, then no. You can change the key when you make the function if you're using some form of factory, but if you haven't made it public, there's no other way.
The only visible exception would be with a singleton factory: you could make a new instance of your singleton method with different parameters (changing it everywhere else), but I doubt you'd be likely to do that with a method.
Here's my scenario:
$foo = bar;
one()
{
two()
{
three()
{
// need access to $foo here
}
}
}
I know I could pass $foo down all three functions, but that isn't really ideal, because you may or may not require it, besides, there are other parameters already and I don't want to add to that list if I can prevent it. It's only when you get to three() do you need $foo. I know I could also specify global $foo; in three(), but I read that this wasn't a good practice.
Is there another way $foo can be made available to three() without doing either of those?
To provide a little more info, $foo in this case is info on how to connect to the database e.g. server, user, pass, but only in three() does it actually need that info. Of course I could connect to the database right as the document loads, but that feels unecessary if the document might not need it.
Any ideas?
UPDATE: I'm sorry, I didn't mean to have "function" at the beginning of each function implying that I was created them in a nested way.
Yes, you can use global, or pass it through as a parameter. Both are fair ways. However, I'd do the latter. Or, you can also use closures and the use keyword:
$foo = 'bar';
$one = function() use($foo) {
$two = function() use($foo) {
$three = function () use($foo) {
// access to $foo here
};
};
};
Can also be use(&$foo) if you need to modify the top $foo's value inside of $three()
Using global is not a bad practice if used properly. This case you would use global and it will be totally fine.
Since global makes functions get access to global variables, there are data corruption risks.
Just make sure to use with caution and you know what you're doing (i.e. not accidentally change the data that you don't want it to change. This sometimes causes some nasty bugs that's hard to track.)
Summarize: global in this case is perfectly fine.
What's really bad is nested functions, at least in PHP.
Don't listen anybody, who are speaking about global.
Read books about OOP (e.g. this one), read about Dependency Injection, Factory-patterns.
Dependency Injection is the best way to create flexible and easy-to-maintain code, and by DI philosophy you will pass $foo from first to third function in arguments, or will pass Context object with all necessary variables (if you want to minimize count of arguments).
More about DI you can read here: http://components.symfony-project.org/dependency-injection/trunk/book/00-Introduction
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'];