What is the utility of the global keyword?
Are there any reasons to prefer one method to another?
Security?
Performance?
Anything else?
Method 1:
function exempleConcat($str1, $str2)
{
return $str1.$str2;
}
Method 2:
function exempleConcat()
{
global $str1, $str2;
return $str1.$str2;
}
When does it make sense to use global?
For me, it appears to be dangerous... but it may just be a lack of knowledge. I am interested in documented (e.g. with example of code, link to documentation...) technical reasons.
Bounty
This is a nice general question about the topic, I (#Gordon) am offering a bounty to get additional answers. Whether your answer is in agreement with mine or gives a different point of view doesn't matter. Since the global topic comes up every now and then, we could use a good "canonical" answer to link to.
Globals are evil
This is true for the global keyword as well as everything else that reaches from a local scope to the global scope (statics, singletons, registries, constants). You do not want to use them. A function call should not have to rely on anything outside, e.g.
function fn()
{
global $foo; // never ever use that
$a = SOME_CONSTANT // do not use that
$b = Foo::SOME_CONSTANT; // do not use that unless self::
$c = $GLOBALS['foo']; // incl. any other superglobal ($_GET, …)
$d = Foo::bar(); // any static call, incl. Singletons and Registries
}
All of these will make your code depend on the outside. Which means, you have to know the full global state your application is in before you can reliably call any of these. The function cannot exist without that environment.
Using the superglobals might not be an obvious flaw, but if you call your code from a Command Line, you don't have $_GET or $_POST. If your code relies on input from these, you are limiting yourself to a web environment. Just abstract the request into an object and use that instead.
In case of coupling hardcoded classnames (static, constants), your function also cannot exist without that class being available. That's less of an issue when it's classes from the same namespace, but when you start mix from different namespaces, you are creating a tangled mess.
Reuse is severly hampered by all of the above. So is unit-testing.
Also, your function signatures are lying when you couple to the global scope
function fn()
is a liar, because it claims I can call that function without passing anything to it. It is only when I look at the function body that I learn I have to set the environment into a certain state.
If your function requires arguments to run, make them explicit and pass them in:
function fn($arg1, $arg2)
{
// do sth with $arguments
}
clearly conveys from the signature what it requires to be called. It is not dependent on the environment to be in a specific state. You dont have to do
$arg1 = 'foo';
$arg2 = 'bar';
fn();
It's a matter of pulling in (global keyword) vs pushing in (arguments). When you push in/inject dependencies, the function does not rely on the outside anymore. When you do fn(1) you dont have to have a variable holding 1 somewhere outside. But when you pull in global $one inside the function, you couple to the global scope and expect it to have a variable of that defined somewhere. The function is no longer independent then.
Even worse, when you are changing globals inside your function, your code will quickly be completely incomprehensible, because your functions are having sideeffects all over the place.
In lack of a better example, consider
function fn()
{
global $foo;
echo $foo; // side effect: echo'ing
$foo = 'bar'; // side effect: changing
}
And then you do
$foo = 'foo';
fn(); // prints foo
fn(); // prints bar <-- WTF!!
There is no way to see that $foo got changed from these three lines. Why would calling the same function with the same arguments all of a sudden change it's output or change a value in the global state? A function should do X for a defined input Y. Always.
This gets even more severe when using OOP, because OOP is about encapsulation and by reaching out to the global scope, you are breaking encapsulation. All these Singletons and Registries you see in frameworks are code smells that should be removed in favor of Dependency Injection. Decouple your code.
More Resources:
http://c2.com/cgi/wiki?GlobalVariablesAreBad
How is testing the registry pattern or singleton hard in PHP?
Flaw: Brittle Global State & Singletons
static considered harmful
Why Singletons have no use in PHP
SOLID (object-oriented design)
Globals are unavoidable.
It is an old discussion, but I still would like to add some thoughts because I miss them in the above mentioned answers. Those answers simplify what a global is too much and present solutions that are not at all solutions to the problem. The problem is: what is the proper way to deal with a global variable and the use of the keyword global? For that do we first have to examine and describe what a global is.
Take a look at this code of Zend - and please understand that I do not suggest that Zend is badly written:
class DecoratorPluginManager extends AbstractPluginManager
{
/**
* Default set of decorators
*
* #var array
*/
protected $invokableClasses = array(
'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
'htmltag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
'tag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
);
There are a lot of invisible dependencies here. Those constants are actually classes.
You can also see require_once in some pages of this framework. Require_once is a global dependency, hence creating external dependencies. That is inevitable for a framework. How can you create a class like DecoratorPluginManager without a lot of external code on which it depends? It can not function without a lot of extras. Using the Zend framework, have you ever changed the implementation of an interface? An interface is in fact a global.
Another globally used application is Drupal. They are very concerned about proper design, but just like any big framework, they have a lot of external dependencies. Take a look at the globals in this page:
/**
* #file
* Initiates a browser-based installation of Drupal.
*/
/**
* Root directory of Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
* Global flag to indicate that site is in installation mode.
*/
define('MAINTENANCE_MODE', 'install');
// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the system requirements page for more information.';
exit;
}
// Start the installer.
require_once DRUPAL_ROOT . '/includes/install.core.inc';
install_drupal();
Ever written a redirect to the login page? That is changing a global value. (And then are you not saying 'WTF', which I consider as a good reaction to bad documentation of your application.) The problem with globals is not that they are globals, you need them in order to have a meaningful application. The problem is the complexity of the overall application which can make it a nightmare to handle.
Sessions are globals, $_POST is a global, DRUPAL_ROOT is a global, the includes/install.core.inc' is an unmodifiable global. There is big world outside any function that is required in order to let that function do its job.
The answer of Gordon is incorrect, because he overrates the independence of a function and calling a function a liar is oversimplifying the situation. Functions do not lie and when you take a look at his example the function is designed improperly - his example is a bug. (By the way, I agree with this conclusion that one should decouple code.)
The answer of deceze is not really a proper definition of the situation. Functions always function within a wider scope and his example is way too simplistic. We will all agree with him that that function is completely useless, because it returns a constant. That function is anyhow bad design. If you want to show that the practice is bad, please come with a relevant example. Renaming variables throughout an application is no big deal having a good IDE (or a tool). The question is about the scope of the variable, not the difference in scope with the function. There is a proper time for a function to perform its role in the process (that is why it is created in the first place) and at that proper time may it influence the functioning of the application as a whole, hence also working on global variables.
The answer of xzyfer is a statement without argumentation. Globals are just as present in an application if you have procedural functions or OOP design. The next two ways of changing the value of a global are essentially the same:
function xzy($var){
global $z;
$z = $var;
}
function setZ($var){
$this->z = $var;
}
In both instances is the value of $z changed within a specific function. In both ways of programming can you make those changes in a bunch of other places in the code. You could say that using global you could call $z anywhere and change there. Yes, you can. But will you? And when done in inapt places, should it then not be called a bug?
Bob Fanger comments on xzyfer.
Should anyone then just use anything and especially the keyword 'global'? No, but just like any type of design, try to analyze on what it depends and what depends on it. Try to find out when it changes and how it changes. Changing global values should only happen with those variables that can change with every request/response. That is, only to those variables that are belonging to the functional flow of a process, not to its technical implementation. The redirect of an URL to the login page belongs to the functional flow of a process, the implementation class used for an interface to the technical implementation. You can change the latter during the different versions of the application, but should not change those with every request/response.
To further understand when it is a problem working with globals and the keyword global and when not will I introduce the next sentence, which comes from Wim de Bie when writing about blogs:
'Personal yes, private no'. When a function is changing the value of a global variable in sake of its own functioning, then will I call that private use of a global variable and a bug. But when the change of the global variable is made for the proper processing of the application as a whole, like the redirect of the user to the login page, then is that in my opinion possibly good design, not by definition bad and certainly not an anti-pattern.
In retrospect to the answers of Gordon, deceze and xzyfer: they all have 'private yes'(and bugs) as examples. That is why they are opposed to the use of globals. I would do too. They, however, do not come with 'personal yes, private no'-examples like I have done in this answer several times.
The one big reason against global is that it means the function is dependent on another scope. This will get messy very quickly.
$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();
vs.
$str = exampleConcat('foo', 'bar');
Requiring $str1 and $str2 to be set up in the calling scope for the function to work means you introduce unnecessary dependencies. You can't rename these variables in this scope anymore without renaming them in the function as well, and thereby also in all other scopes you're using this function. This soon devolves into chaos as you're trying to keep track of your variable names.
global is a bad pattern even for including global things such as $db resources. There will come the day when you want to rename $db but can't, because your whole application depends on the name.
Limiting and separating the scope of variables is essential for writing any halfway complex application.
Simply put there is rarely a reason to global and never a good one in modern PHP code IMHO. Especially if you're using PHP 5. And extra specially if you're develop Object Orientated code.
Globals negatively affect maintainability, readability and testability of code. Many uses of global can and should be replaced with Dependency Injection or simply passing the global object as a parameter.
function getCustomer($db, $id) {
$row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
return $row;
}
Dont hesitate from using global keyword inside functions in PHP. Especially dont take people who are outlandishly preaching/yelling how globals are 'evil' and whatnot.
Firstly, because what you use totally depends on the situation and problem, and there is NO one solution/way to do anything in coding. Totally leaving aside the fallacy of undefinable, subjective, religious adjectives like 'evil' into the equation.
Case in point :
Wordpress and its ecosystem uses global keyword in their functions. Be the code OOP or not OOP.
And as of now Wordpress is basically 18.9% of internet, and its running the massive megasites/apps of innumerable giants ranging from Reuters to Sony, to NYT, to CNN.
And it does it well.
Usage of global keyword inside functions frees Wordpress from MASSIVE bloat which would happen given its huge ecosystem. Imagine every function was asking/passing any variable that is needed from another plugin, core, and returning. Added with plugin interdependencies, that would end up in a nightmare of variables, or a nightmare of arrays passed as variables. A HELL to track, a hell to debug, a hell to develop. Inanely massive memory footprint due to code bloat and variable bloat too. Harder to write too.
There may be people who come up and criticize Wordpress, its ecosystem, their practices and what goes on around in those parts.
Pointless, since this ecosystem is pretty much 20% of roughly entire internet. Apparently, it DOES work, it does its job and more. Which means its the same for the global keyword.
Another good example is the "iframes are evil" fundamentalism. A decade ago it was heresy to use iframes. And there were thousands of people preaching against them around internet. Then comes facebook, then comes social, now iframes are everywhere from 'like' boxes to authentication, and voila - everyone shut up. There are those who still did not shut up - rightfully or wrongfully. But you know what, life goes on despite such opinions, and even the ones who were preaching against iframes a decade ago are now having to use them to integrate various social apps to their organization's own applications without saying a word.
......
Coder Fundamentalism is something very, very bad. A small percentage among us may be graced with the comfortable job in a solid monolithic company which has enough clout to endure the constant change in information technology and the pressures it brings in regard to competition, time, budget and other considerations, and therefore can practice fundamentalism and strict adherence to perceived 'evils' or 'goods'. Comfortable positions reminiscent of old ages these are, even if the occupiers are young.
For the majority however, the i.t. world is an ever changing world in which they need to be open minded and practical. There is no place for fundamentalism, leave aside outrageous keywords like 'evil' in the front line trenches of information technology.
Just use whatever makes the best sense for the problem AT HAND, with appropriate considerations for near, medium and long term future. Do not shy away from using any feature or approach because it has a rampant ideological animosity against it, among any given coder subset.
They wont do your job. You will. Act according to your circumstances.
It makes no sense to make a concat function using the global keyword.
It's used to access global variables such as a database object.
Example:
function getCustomer($id) {
global $db;
$row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
return $row;
}
It can be used as a variation on the Singleton pattern
I think everyone has pretty much expounded on the negative aspects of globals. So I will add the positives as well as instructions for proper use of globals:
The main purpose of globals was to share information between functions. back when
there was nothing like a class, php code consisted of a bunch of functions. Sometimes
you would need to share information between functions. Typically the global was used to
do this with the risk of having data corrupted by making them global.
Now before some happy go lucky simpleton starts a comment about dependency injection I
would like to ask you how the user of a function like example get_post(1) would know
all the dependencies of the function. Also consider that dependencies may differ from
version to version and server to server. The main problem with dependency injection
is dependencies have to be known beforehand. In a situation where this is not possible
or unwanted global variables were the only way to do achieve this goal.
Due to the creation of the class, now common functions can easily be grouped in a class
and share data. Through implementations like Mediators even unrelated objects can share
information. This is no longer necessary.
Another use for globals is for configuration purposes. Mostly at the beginning of a
script before any autoloaders have been loaded, database connections made, etc.
During the loading of resources, globals can be used to configure data (ie which
database to use where library files are located, the url of the server etc). The best
way to do this is by use of the define() function since these values wont change often
and can easily be placed in a configuration file.
The final use for globals is to hold common data (ie CRLF, IMAGE_DIR, IMAGE_DIR_URL),
human readable status flags (ie ITERATOR_IS_RECURSIVE). Here globals are used to store
information that is meant to be used application wide allowing them to be changed and
have those changes appear application wide.
The singleton pattern became popular in php during php4 when each instance of an object
took up memory. The singleton helped to save ram by only allowing one instance of an
object to be created. Before references even dependancy injection would have been a bad
idea.
The new php implementation of objects from PHP 5.4+ takes care of most of these problems
you can safely pass objects around with little to no penalty any more. This is no longer
necessary.
Another use for singletons is the special instance where only one instance of an object
must exist at a time, that instance might exist before / after script execution and
that object is shared between different scripts / servers / languages etc. Here a
singleton pattern solves the solution quite well.
So in conclusion if you are in position 1, 2 or 3 then using a global would be reasonable. However in other situations Method 1 should be used.
Feel free to update any other instances where globals should be used.
Related
I've heard many times on this forum that using global variable is a dead sin and implementing singleton is a crime.
It just came to my mind that old good constants bear all the features of these dishonored practices: they are globally accessed and no doubt they introduce globallest state ever.
So, the question is: shouldn't we declare a jihad to constants too, and use all the modern things like DI, IoC or other stylish words all the way instead?
Generally speaking yes, avoid constants. They introduce coupling from the consumers to the global scope. That is, the consumers rely on something outside. This is unobvious, e.g.
class Foo
{
public function doSomething()
{
if (ENV === ENV_DEV) {
// do something this way
} else {
// do something that way
}
}
}
Without knowing the internals of doSomething, you will not know there is a dependency on the global scope having that constant. So in addition of making your code somewhat harder to understand, you are also limiting how it can be reused.
The above is also true for constants that have only one value, e.g.
public function log($message)
{
fwrite(LOGFILE, $message);
}
Here the constant would point to a file resource defined somewhere outside as
define('LOGFILE', fopen('/path/to/logfile'));
And this is just as unobvious as using ENV. It's a dependency that requires something outside the class to exist. And I have to know that in order to work with that object. Since the class using this constant hides this detail, I might try to log something without making sure the constant exists and then I'd wonder why it doesn't work. It doesn't even have to be a resource, LOGFILE could simply contain the path as a string. Same result.
Relying on global constants in your consumers will also require you to setup global state in your unit-tests. This is something you generally want to avoid, even if the constants are fixed value, because the point of the unit-test is to test the unit in isolation and having to put the environment into a certain state hinders this.
Moreover, using global constants always poses the threat of constants of different libraries clashing. As a rule of thumb, don't put anything into the global scope. Use namespaces to cluster constants if you have to use them.
However, note that namespaced constants still have the same issues regarding coupling, so do class constants. As long as this coupling is within the same namespace it's less critical, but once you start to couple to constants from various namespaces you are again hampering reuse. For that matter, consider any constants public API.
An alternative to using constants would be to use immutable Value Objects, for instance:
class Environment
{
private $value;
public function __construct($value)
{
$this->assertValueIsAllowedValue($value);
$this->value = $value;
}
public function getValue() {
// …
This way, you can pass around these values to the objects that need them, in addition to making sure the values are valid. Like always, YMMV. This is just an option. A single constant will not make your code unusable, but relying largely on constants will have a detrimental effect, so as a rule of thumb, try to keep them down to a minimum.
On a related side note, you might also be interested in:
Pros and Cons of Interface constants and
PHP global in functions
The primary reason why global variables are considered bad practice is because they can be modified in one part of a system and used in another part, with no direct link between those two pieces of code.
This leads to potential bugs because it is possible to write code that uses a global variable without knowing (or considering) all the places where it is used and ways in which it could be changed. Or vice-versa, write code that makes a change to a global, without realising the impact that change may have in other unrelated parts of your code.
Constants do not share this issue, because they are... well, constant. Once they're defined, they can't be changed, and thus the issued described in the above paragraph cannot occur.
Therefore, they are fine to use globally.
That said, I have seen some poorly written PHP code that uses define to create constants, but declares the constants differently in different circumstances. This is a mis-use of constants: A constant should be an absolutely fixed value; it should only ever be a single value. If you have something that could potentially be different values on different runs through the program, then it shouldn't be defined as a constant. That sort of thing should indeed be a variable, and then should follow the same rules as other variables.
This sort of mis-use can only happen in a scripted language like PHP; it couldn't happen in a compiled language because you can only define a constant once, in one place and to a fixed value.
There's a big difference between a global variable and a global constant.
The main reason a global variable is shunned is because it can be modified by anything at any time. It can introduce all sorts of hidden dependencies on call/execution order, and can result in identical code working sometimes and not others, depending on if and how the global has been changed. Obviously the bad mojo can be ramped-up even more if you're dealing with concurrency or parallelism.
A global constant is (or should be) exactly the same throughout your code at all times. Once your code starts executing, it's guaranteed that every bit of code viewing it will see the same thing every time. That means there's no danger of introducing accidental dependencies. The use of constants can in fact be very good for improving reliability, as it means you don't need to update the value in several locations if you need to change your code. (Never underestimate human error!)
Singletons are a whole other issue. It's an often-abused design pattern which can basically end up as an object oriented version of global variables. In some languages (such as C++), it can also go very wrong if you're not careful of initialisation order. However, it can be a useful pattern on occasion, although there are usually better alternatives (albeit sometimes requiring slightly more work).
EDIT: Just to expand briefly, you mentioned in your question that global constants introduce the "globallest state ever". That's not really accurate, because a global constant is (or should be) fixed in the same way as the source code is fixed. It defines the static nature of the program, whereas "state" is typically understood as a dynamic run-time concept (i.e. the stuff that can change).
What is the utility of the global keyword?
Are there any reasons to prefer one method to another?
Security?
Performance?
Anything else?
Method 1:
function exempleConcat($str1, $str2)
{
return $str1.$str2;
}
Method 2:
function exempleConcat()
{
global $str1, $str2;
return $str1.$str2;
}
When does it make sense to use global?
For me, it appears to be dangerous... but it may just be a lack of knowledge. I am interested in documented (e.g. with example of code, link to documentation...) technical reasons.
Bounty
This is a nice general question about the topic, I (#Gordon) am offering a bounty to get additional answers. Whether your answer is in agreement with mine or gives a different point of view doesn't matter. Since the global topic comes up every now and then, we could use a good "canonical" answer to link to.
Globals are evil
This is true for the global keyword as well as everything else that reaches from a local scope to the global scope (statics, singletons, registries, constants). You do not want to use them. A function call should not have to rely on anything outside, e.g.
function fn()
{
global $foo; // never ever use that
$a = SOME_CONSTANT // do not use that
$b = Foo::SOME_CONSTANT; // do not use that unless self::
$c = $GLOBALS['foo']; // incl. any other superglobal ($_GET, …)
$d = Foo::bar(); // any static call, incl. Singletons and Registries
}
All of these will make your code depend on the outside. Which means, you have to know the full global state your application is in before you can reliably call any of these. The function cannot exist without that environment.
Using the superglobals might not be an obvious flaw, but if you call your code from a Command Line, you don't have $_GET or $_POST. If your code relies on input from these, you are limiting yourself to a web environment. Just abstract the request into an object and use that instead.
In case of coupling hardcoded classnames (static, constants), your function also cannot exist without that class being available. That's less of an issue when it's classes from the same namespace, but when you start mix from different namespaces, you are creating a tangled mess.
Reuse is severly hampered by all of the above. So is unit-testing.
Also, your function signatures are lying when you couple to the global scope
function fn()
is a liar, because it claims I can call that function without passing anything to it. It is only when I look at the function body that I learn I have to set the environment into a certain state.
If your function requires arguments to run, make them explicit and pass them in:
function fn($arg1, $arg2)
{
// do sth with $arguments
}
clearly conveys from the signature what it requires to be called. It is not dependent on the environment to be in a specific state. You dont have to do
$arg1 = 'foo';
$arg2 = 'bar';
fn();
It's a matter of pulling in (global keyword) vs pushing in (arguments). When you push in/inject dependencies, the function does not rely on the outside anymore. When you do fn(1) you dont have to have a variable holding 1 somewhere outside. But when you pull in global $one inside the function, you couple to the global scope and expect it to have a variable of that defined somewhere. The function is no longer independent then.
Even worse, when you are changing globals inside your function, your code will quickly be completely incomprehensible, because your functions are having sideeffects all over the place.
In lack of a better example, consider
function fn()
{
global $foo;
echo $foo; // side effect: echo'ing
$foo = 'bar'; // side effect: changing
}
And then you do
$foo = 'foo';
fn(); // prints foo
fn(); // prints bar <-- WTF!!
There is no way to see that $foo got changed from these three lines. Why would calling the same function with the same arguments all of a sudden change it's output or change a value in the global state? A function should do X for a defined input Y. Always.
This gets even more severe when using OOP, because OOP is about encapsulation and by reaching out to the global scope, you are breaking encapsulation. All these Singletons and Registries you see in frameworks are code smells that should be removed in favor of Dependency Injection. Decouple your code.
More Resources:
http://c2.com/cgi/wiki?GlobalVariablesAreBad
How is testing the registry pattern or singleton hard in PHP?
Flaw: Brittle Global State & Singletons
static considered harmful
Why Singletons have no use in PHP
SOLID (object-oriented design)
Globals are unavoidable.
It is an old discussion, but I still would like to add some thoughts because I miss them in the above mentioned answers. Those answers simplify what a global is too much and present solutions that are not at all solutions to the problem. The problem is: what is the proper way to deal with a global variable and the use of the keyword global? For that do we first have to examine and describe what a global is.
Take a look at this code of Zend - and please understand that I do not suggest that Zend is badly written:
class DecoratorPluginManager extends AbstractPluginManager
{
/**
* Default set of decorators
*
* #var array
*/
protected $invokableClasses = array(
'htmlcloud' => 'Zend\Tag\Cloud\Decorator\HtmlCloud',
'htmltag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
'tag' => 'Zend\Tag\Cloud\Decorator\HtmlTag',
);
There are a lot of invisible dependencies here. Those constants are actually classes.
You can also see require_once in some pages of this framework. Require_once is a global dependency, hence creating external dependencies. That is inevitable for a framework. How can you create a class like DecoratorPluginManager without a lot of external code on which it depends? It can not function without a lot of extras. Using the Zend framework, have you ever changed the implementation of an interface? An interface is in fact a global.
Another globally used application is Drupal. They are very concerned about proper design, but just like any big framework, they have a lot of external dependencies. Take a look at the globals in this page:
/**
* #file
* Initiates a browser-based installation of Drupal.
*/
/**
* Root directory of Drupal installation.
*/
define('DRUPAL_ROOT', getcwd());
/**
* Global flag to indicate that site is in installation mode.
*/
define('MAINTENANCE_MODE', 'install');
// Exit early if running an incompatible PHP version to avoid fatal errors.
if (version_compare(PHP_VERSION, '5.2.4') < 0) {
print 'Your PHP installation is too old. Drupal requires at least PHP 5.2.4. See the system requirements page for more information.';
exit;
}
// Start the installer.
require_once DRUPAL_ROOT . '/includes/install.core.inc';
install_drupal();
Ever written a redirect to the login page? That is changing a global value. (And then are you not saying 'WTF', which I consider as a good reaction to bad documentation of your application.) The problem with globals is not that they are globals, you need them in order to have a meaningful application. The problem is the complexity of the overall application which can make it a nightmare to handle.
Sessions are globals, $_POST is a global, DRUPAL_ROOT is a global, the includes/install.core.inc' is an unmodifiable global. There is big world outside any function that is required in order to let that function do its job.
The answer of Gordon is incorrect, because he overrates the independence of a function and calling a function a liar is oversimplifying the situation. Functions do not lie and when you take a look at his example the function is designed improperly - his example is a bug. (By the way, I agree with this conclusion that one should decouple code.)
The answer of deceze is not really a proper definition of the situation. Functions always function within a wider scope and his example is way too simplistic. We will all agree with him that that function is completely useless, because it returns a constant. That function is anyhow bad design. If you want to show that the practice is bad, please come with a relevant example. Renaming variables throughout an application is no big deal having a good IDE (or a tool). The question is about the scope of the variable, not the difference in scope with the function. There is a proper time for a function to perform its role in the process (that is why it is created in the first place) and at that proper time may it influence the functioning of the application as a whole, hence also working on global variables.
The answer of xzyfer is a statement without argumentation. Globals are just as present in an application if you have procedural functions or OOP design. The next two ways of changing the value of a global are essentially the same:
function xzy($var){
global $z;
$z = $var;
}
function setZ($var){
$this->z = $var;
}
In both instances is the value of $z changed within a specific function. In both ways of programming can you make those changes in a bunch of other places in the code. You could say that using global you could call $z anywhere and change there. Yes, you can. But will you? And when done in inapt places, should it then not be called a bug?
Bob Fanger comments on xzyfer.
Should anyone then just use anything and especially the keyword 'global'? No, but just like any type of design, try to analyze on what it depends and what depends on it. Try to find out when it changes and how it changes. Changing global values should only happen with those variables that can change with every request/response. That is, only to those variables that are belonging to the functional flow of a process, not to its technical implementation. The redirect of an URL to the login page belongs to the functional flow of a process, the implementation class used for an interface to the technical implementation. You can change the latter during the different versions of the application, but should not change those with every request/response.
To further understand when it is a problem working with globals and the keyword global and when not will I introduce the next sentence, which comes from Wim de Bie when writing about blogs:
'Personal yes, private no'. When a function is changing the value of a global variable in sake of its own functioning, then will I call that private use of a global variable and a bug. But when the change of the global variable is made for the proper processing of the application as a whole, like the redirect of the user to the login page, then is that in my opinion possibly good design, not by definition bad and certainly not an anti-pattern.
In retrospect to the answers of Gordon, deceze and xzyfer: they all have 'private yes'(and bugs) as examples. That is why they are opposed to the use of globals. I would do too. They, however, do not come with 'personal yes, private no'-examples like I have done in this answer several times.
The one big reason against global is that it means the function is dependent on another scope. This will get messy very quickly.
$str1 = 'foo';
$str2 = 'bar';
$str3 = exampleConcat();
vs.
$str = exampleConcat('foo', 'bar');
Requiring $str1 and $str2 to be set up in the calling scope for the function to work means you introduce unnecessary dependencies. You can't rename these variables in this scope anymore without renaming them in the function as well, and thereby also in all other scopes you're using this function. This soon devolves into chaos as you're trying to keep track of your variable names.
global is a bad pattern even for including global things such as $db resources. There will come the day when you want to rename $db but can't, because your whole application depends on the name.
Limiting and separating the scope of variables is essential for writing any halfway complex application.
Simply put there is rarely a reason to global and never a good one in modern PHP code IMHO. Especially if you're using PHP 5. And extra specially if you're develop Object Orientated code.
Globals negatively affect maintainability, readability and testability of code. Many uses of global can and should be replaced with Dependency Injection or simply passing the global object as a parameter.
function getCustomer($db, $id) {
$row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
return $row;
}
Dont hesitate from using global keyword inside functions in PHP. Especially dont take people who are outlandishly preaching/yelling how globals are 'evil' and whatnot.
Firstly, because what you use totally depends on the situation and problem, and there is NO one solution/way to do anything in coding. Totally leaving aside the fallacy of undefinable, subjective, religious adjectives like 'evil' into the equation.
Case in point :
Wordpress and its ecosystem uses global keyword in their functions. Be the code OOP or not OOP.
And as of now Wordpress is basically 18.9% of internet, and its running the massive megasites/apps of innumerable giants ranging from Reuters to Sony, to NYT, to CNN.
And it does it well.
Usage of global keyword inside functions frees Wordpress from MASSIVE bloat which would happen given its huge ecosystem. Imagine every function was asking/passing any variable that is needed from another plugin, core, and returning. Added with plugin interdependencies, that would end up in a nightmare of variables, or a nightmare of arrays passed as variables. A HELL to track, a hell to debug, a hell to develop. Inanely massive memory footprint due to code bloat and variable bloat too. Harder to write too.
There may be people who come up and criticize Wordpress, its ecosystem, their practices and what goes on around in those parts.
Pointless, since this ecosystem is pretty much 20% of roughly entire internet. Apparently, it DOES work, it does its job and more. Which means its the same for the global keyword.
Another good example is the "iframes are evil" fundamentalism. A decade ago it was heresy to use iframes. And there were thousands of people preaching against them around internet. Then comes facebook, then comes social, now iframes are everywhere from 'like' boxes to authentication, and voila - everyone shut up. There are those who still did not shut up - rightfully or wrongfully. But you know what, life goes on despite such opinions, and even the ones who were preaching against iframes a decade ago are now having to use them to integrate various social apps to their organization's own applications without saying a word.
......
Coder Fundamentalism is something very, very bad. A small percentage among us may be graced with the comfortable job in a solid monolithic company which has enough clout to endure the constant change in information technology and the pressures it brings in regard to competition, time, budget and other considerations, and therefore can practice fundamentalism and strict adherence to perceived 'evils' or 'goods'. Comfortable positions reminiscent of old ages these are, even if the occupiers are young.
For the majority however, the i.t. world is an ever changing world in which they need to be open minded and practical. There is no place for fundamentalism, leave aside outrageous keywords like 'evil' in the front line trenches of information technology.
Just use whatever makes the best sense for the problem AT HAND, with appropriate considerations for near, medium and long term future. Do not shy away from using any feature or approach because it has a rampant ideological animosity against it, among any given coder subset.
They wont do your job. You will. Act according to your circumstances.
It makes no sense to make a concat function using the global keyword.
It's used to access global variables such as a database object.
Example:
function getCustomer($id) {
global $db;
$row = $db->fetchRow('SELECT * FROM customer WHERE id = '.$db->quote($id));
return $row;
}
It can be used as a variation on the Singleton pattern
I think everyone has pretty much expounded on the negative aspects of globals. So I will add the positives as well as instructions for proper use of globals:
The main purpose of globals was to share information between functions. back when
there was nothing like a class, php code consisted of a bunch of functions. Sometimes
you would need to share information between functions. Typically the global was used to
do this with the risk of having data corrupted by making them global.
Now before some happy go lucky simpleton starts a comment about dependency injection I
would like to ask you how the user of a function like example get_post(1) would know
all the dependencies of the function. Also consider that dependencies may differ from
version to version and server to server. The main problem with dependency injection
is dependencies have to be known beforehand. In a situation where this is not possible
or unwanted global variables were the only way to do achieve this goal.
Due to the creation of the class, now common functions can easily be grouped in a class
and share data. Through implementations like Mediators even unrelated objects can share
information. This is no longer necessary.
Another use for globals is for configuration purposes. Mostly at the beginning of a
script before any autoloaders have been loaded, database connections made, etc.
During the loading of resources, globals can be used to configure data (ie which
database to use where library files are located, the url of the server etc). The best
way to do this is by use of the define() function since these values wont change often
and can easily be placed in a configuration file.
The final use for globals is to hold common data (ie CRLF, IMAGE_DIR, IMAGE_DIR_URL),
human readable status flags (ie ITERATOR_IS_RECURSIVE). Here globals are used to store
information that is meant to be used application wide allowing them to be changed and
have those changes appear application wide.
The singleton pattern became popular in php during php4 when each instance of an object
took up memory. The singleton helped to save ram by only allowing one instance of an
object to be created. Before references even dependancy injection would have been a bad
idea.
The new php implementation of objects from PHP 5.4+ takes care of most of these problems
you can safely pass objects around with little to no penalty any more. This is no longer
necessary.
Another use for singletons is the special instance where only one instance of an object
must exist at a time, that instance might exist before / after script execution and
that object is shared between different scripts / servers / languages etc. Here a
singleton pattern solves the solution quite well.
So in conclusion if you are in position 1, 2 or 3 then using a global would be reasonable. However in other situations Method 1 should be used.
Feel free to update any other instances where globals should be used.
Before I begin, this framework is not meant to compete with Zend, Symfony, Cake or any other framework. It is primarily a personal project so that I may test out some PHP 5.3 goodies, experience new techniques and gives me the chance to try things under my idea. I am also trying to make this framework as lightweight as possible, and reduce the amount of unncessary getters and setters. Now for the problem at hand.
A bulk of the framework is done, primarily all the core classes required for it to run. The problem arises on the entry point of the application. I want the whole application to be run through a single core object which branches out. The core object will be extended with classes to manage environments, configuration, registry, autoloading, routing, etc, etc. You can see this "core" object below, it is aptly called Application.
https://github.com/titon/titon/blob/42c88e36c29e3d8c697306fe68be18b3a8fd2e70/titon/source/Infrastructure.php
$app = new \titon\source\core\Application();
The idea was that from anywhere in the application, you can access the core objects through this $app variable. Example:
(I cant post more than 1 link, so please go to the following directories on Github. /app/config/Setup.php and /app/modules/core/Bootstrap.php)
$app->environment->current();
$app->loader->includePath(array(__DIR__));
$app->registry->factory('titon\source\system\Controller');
But now we get into the problem of global variables, which I do not want to use. I also like to try and avoid Singletons.
public function foobar() {
global $app; // Eww
}
But I also do not want to use static classes, as I was trying to go for a more OOP approach. The only solutions I can think of is using a static class property to hold the Application instance and access that everywhere, but I do not like that. Or I can pass the object down to its children over and over again, but again, not a fan.
Core::$app->router->detect(); // Meh
$this->setApplication($this); // Mehher
I was curious how Zend and Symfony approached this problem. But after looking through their source code, I could not backwards engineer and determine the correct entry point. Furthermore, it seemed Zend would created global variables all over (Zend_Config, etc), but I would prefer to have a managing object. Symfony 2.0, I just got lost. As for Cake, Solar, Fuel, it seems they are using static classes for these kind of objects.
Now my primary question is, how would you solve this? I would like to keep a single object to instantiate and be accessible everywhere, but it doesn't seem like an easy thing to handle. I am willing to rewrite a lot of the framework if need be.
The idea was that from anywhere in the application, you can access the core objects through this $app variable. Example:
...
But now we get into the problem of global variables, which I do not want to use. I also like to try and avoid Singletons.
That seems like a contradiction to me.
Do you know why you don't want any global variables? Is it because you read somewhere that global variables are a bad thing?
Conversely, do you know why you want a central object that is available from anywhere in your application?
Follow Up:
In case it wasn't clear, those were meant as rhetorical questions. From an architectural viewpoint, global variables (in any shape) are expensive. Some say evil. I think that's missing the point slightly - You need some amount of global variables in any application (At least one). To further muddy the waters, "global" is really a relative thing; It is much more meaningful to consider variables as having varying scopes, where global is on one extreme of the continuum and local, temporary variable at the other. If you have a single object containing all your other objects, then I would consider each of these variables as being effectively global variables, even though they may not be so in a technical sense. Think a bit about that.
As for a silver bullet, you could take a look at dependency injection. This is an approach to avoiding global variables that works, but has some cost in the form of complexity.
One of PHP's old unresolved issues: One can't define superglobals, without using a extension like runkit.
I usually solve this with a pseudo-Registry, i.e. I define a class R with all variables I want to make global defined as public static $var. I know, this is probably not the vanilla-OOP approach, but it serves well. R::$var is as short as it get, I think. Everything else, like dependency injection ($this->var) or singleton (R::getVar()), is longer.
The best solution to avoid global variables is dependency injection. You'll probably need to create some container. Look at the Symfony components library.
You may also try registry pattern.
I access my MySQL database via PDO. I'm setting up access to the database, and my first attempt was to use the following:
The first thing I thought of is global:
$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');
function some_function() {
global $db;
$db->query('...');
}
This is considered a bad practice. After a little search, I ended up with the Singleton pattern, which
"applies to situations in which there needs to be a single instance of a class."
According to the example in the manual, we should do this:
class Database {
private static $instance, $db;
private function __construct(){}
static function singleton() {
if(!isset(self::$instance))
self::$instance = new __CLASS__;
return self:$instance;
}
function get() {
if(!isset(self::$db))
self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')
return self::$db;
}
}
function some_function() {
$db = Database::singleton();
$db->get()->query('...');
}
some_function();
Why do I need that relatively large class when I can do this?
class Database {
private static $db;
private function __construct(){}
static function get() {
if(!isset(self::$db))
self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');
return self::$db;
}
}
function some_function() {
Database::get()->query('...');
}
some_function();
This last one works perfectly and I don't need to worry about $db anymore.
How can I create a smaller singleton class, or is there a use-case for singletons that I'm missing in PHP?
Singletons have very little - if not to say no - use in PHP.
In languages where objects live in shared memory, Singletons can be used to keep memory usage low. Instead of creating two objects, you reference an existing instance from the globally shared application memory. In PHP there is no such application memory. A Singleton created in one Request lives for exactly that request. A Singleton created in another Request done at the same time is still a completely different instance. Thus, one of the two main purposes of a Singleton is not applicable here.
In addition, many of the objects that can conceptually exist only once in your application do not necessarily require a language mechanism to enforce this. If you need only one instance, then don't instantiate another. It's only when you may have no other instance, e.g. when kittens die when you create a second instance, that you might have a valid Use Case for a Singleton.
The other purpose would be to have a global access point to an instance within the same Request. While this might sound desirable, it really isnt, because it creates coupling to the global scope (like any globals and statics). This makes Unit-Testing harder and your application in general less maintainable. There is ways to mitigate this, but in general, if you need to have the same instance in many classes, use Dependency Injection.
See my slides for Singletons in PHP - Why they are bad and how you can eliminate them from your applications for additional information.
Even Erich Gamma, one of the Singleton pattern's inventors, doubts this pattern nowadays:
"I'm in favor of dropping Singleton. Its use is almost always a design smell"
Further reading
How is testing the registry pattern or singleton hard in PHP?
What are the disadvantages of using a PHP database class as a singleton?
Database abstraction class design using PHP PDO
Would singleton be a good design pattern for a microblogging site?
Modifying a class to encapsulate instead of inherit
How to access an object from another class?
Why Singletons have no use in PHP
The Clean Code Talks - Singletons and Global State
If, after the above, you still need help deciding:
Okay, I wondered over that one for a while when I first started my career. Implemented it different ways and came up with two reasons to choose not to use static classes, but they are pretty big ones.
One is that you will find that very often something that you are absolutely sure that you'll never have more than one instance of, you eventually have a second. You may end up with a second monitor, a second database, a second server--whatever.
When this happens, if you have used a static class you're in for a much worse refactor than if you had used a singleton. A singleton is an iffy pattern in itself, but it converts fairly easily to an intelligent factory pattern--can even be converted to use dependency injection without too much trouble. For instance, if your singleton is gotten through getInstance(), you can pretty easily change that to getInstance(databaseName) and allow for multiple databases--no other code changes.
The second issue is testing (And honestly, this is the same as the first issue). Sometimes you want to replace your database with a mock database. In effect this is a second instance of the database object. This is much harder to do with static classes than it is with a singleton, you only have to mock out the getInstance() method, not every single method in a static class (which in some languages can be very difficult).
It really comes down to habits--and when people say "Globals" are bad, they have very good reasons to say so, but it may not always be obvious until you've hit the problem yourself.
The best thing you can do is ask (like you did) then make a choice and observe the ramifications of your decision. Having the knowledge to interpret your code's evolution over time is much more important than doing it right in the first place.
Who needs singletons in PHP?
Notice that almost all of the objections to singletons come from technical standpoints - but they are also VERY limited in their scope. Especially for PHP. First, I will list some of the reasons for using singletons, and then I will analyze the objections to usage of singletons. First, people who need them:
- People who are coding a large framework/codebase, which will be used in many different environments, will have to work with previously existing, different frameworks/codebases, with the necessity of implementing many different, changing, even whimsical requests from clients/bosses/management/unit leaders do.
See, the singleton pattern is self inclusive. When done, a singleton class is rigid across any code you include it in, and it acts exactly like how you created its methods and variables. And it is always the same object in a given request. Since it cannot be created twice to be two different objects, you know what a singleton object is at any given point in a code - even if the singleton is inserted to two, three different, old, even spaghetti codebases. Therefore, it makes it easier in terms of development purposes - even if there are many people working in that project, when you see a singleton being initialized in one point in any given codebase, you know what it is, what it does, how it does, and the state it is in. If it was the traditional class, you would need to keep track of where was that object first created, what methods were invoked in it until that point in the code, and its particular state. But, drop a singleton there, and if you dropped proper debugging and information methods and tracking into the singleton while coding it, you know exactly what it is. So therefore, it makes it easier for people who have to work with differing codebases, with the necessity of integrating code which was done earlier with different philosophies, or done by people who you have no contact with. (that is, vendor-project-company-whatever is there no more, no support nothing).
- People who need to work with third-party APIs, services and websites.
If you look closer, this is not too different than the earlier case - third-party APIs, services, websites, are just like external, isolated codebases over which you have NO control. Anything can happen. So, with a singleton session/user class, you can manage ANY kind of session/authorization implementation from third-party providers like OpenID, Facebook, Twitter and many more - and you can do these ALL at the same time from the SAME singleton object - which is easily accessible, in a known state at any given point in whatever code you plug it into. You can even create multiple sessions to multiple different, third-party APIs/services for the SAME user in your own website/application, and do whatever you want to do with them.
Of course, all of this also can be tone with traditional methods by using normal classes and objects - the catch here is, singleton is tidier, neater and therefore because of that manageable/testable easier compared to traditional class/object usage in such situations.
- People who need to do rapid development
The global-like behavior of singletons make it easier to build any kind of code with a framework which has a collection of singletons to build on, because once you construct your singleton classes well, the established, mature and set methods will be easily available and usable anywhere, anytime, in a consistent fashion. It takes some time to mature your classes, but after that, they are rock solid and consistent, and useful. You can have as many methods in a singleton doing whatever you want, and, though this may increase the memory footprint of the object, it brings much more savings in time required for rapid development - a method you are not using in one given instance of an application can be used in another integrated one, and you can just slap a new feature which client/boss/project manager asks just by a few modifications.
You get the idea. Now lets move on to the objections to singletons and
the unholy crusade against something that is useful:
- Foremost objection is that it makes testing harder.
And really, it does to some extent, even if it can be easily mitigated by taking proper precautions and coding debugging routines into your singletons WITH the realization that you will be debugging a singleton. But see, this isnt too different than ANY other coding philosophy/method/pattern that is out there - it's just that, singletons are relatively new and not widespread, so the current testing methods are ending up comparably incompatible with them. But that is not different in any aspect of programming languages - different styles require different approaches.
One point this objection falls flat in that, it ignores the fact that the reasons applications developed is not for 'testing', and testing is not the only phase/process that goes into an application development. Applications are developed for production use. And as I explained in the 'who needs singletons' section, singletons can cut a GREAT deal from the complexity of having to make a code work WITH and INSIDE many different codebases/applications/third-party services. The time which may be lost in testing, is time gained in development and deployment. This is especially useful in this era of third-party authentication/application/integration - Facebook, Twitter, OpenID, many more and who knows what's next.
Though it is understandable - programmers work in very different circumstances depending on their career. And for people who work in relatively big companies with defined departments tending different, defined software/applications in a comfortable fashion and without the impending doom of budget cuts/layoffs and the accompanying need to do a LOT of stuff with a lot of different stuff in a cheap/fast/reliable fashion, singletons may not seem so necessary. And it may even be nuisance/impediment to what they ALREADY have.
But for those who needs to work in the dirty trenches of 'agile' development, having to implement many different requests (sometimes unreasonable) from their client/manager/project, singletons are a saving grace due to reasons explained earlier.
- Another objection is that its memory footprint is higher
Because a new singleton will exist for each request from each client, this MAY be an objection for PHP. With badly constructed and used singletons, the memory footprint of an application can be higher if many users are served by the application at any given point.
Though, this is valid for ANY kind of approach you can take while coding things. The questions which should be asked are, are the methods, data which are held and processed by these singletons unnecessary? For, if they ARE necessary across many of the requests application is getting, then even if you don't use singletons, those methods and data WILL be present in your application in some form or another through the code. So, it all becomes a question of how much memory will you be saving, when you initialize a traditional class object 1/3 into the code processing, and destroy it 3/4 into it.
See, when put this way, the question becomes quite irrelevant - there should not be unnecessary methods, data held in objects in your code ANYway - regardless of you use singletons or not. So, this objection to singletons becomes really hilarious in that, it ASSUMES that there will be unnecessary methods, data in the objects created from the classes you use.
- Some invalid objections like 'makes maintaining multiple database connnections impossible/harder'
I can't even begin to comprehend this objection, when all one needs to maintain multiple database connections, multiple database selections, multiple database queries, multiple result sets in a given singleton is just keeping them in variables/arrays in the singleton as long as they are needed. This can be as simple as keeping them in arrays, though you can invent whatever method you want to use to effect that. But let's examine the simplest case, use of variables and arrays in a given singleton:
Imagine the below is inside a given database singleton:
$this->connections = array(); (wrong syntax, I just typed it like this to give you the picture - the proper declaration of the variable is public $connections = array(); and its usage is $this->connections['connectionkey'] naturally )
You can set up, and keep multiple connections at any given time in an array in this fashion. And same goes for queries, result sets and so forth.
$this->query(QUERYSTRING,'queryname',$this->connections['particulrconnection']);
Which can just do a query to a selected database with a selected connection, and just store in your
$this->results
array with the key 'queryname'. Of course, you will need to have your query method coded for this - which is trivial to do.
This enables you to maintain a virtually infinite number of (as much as the resource limits allow of course) different database connections and result sets as much as you need them. And they are available to ANY piece of code in any given point in any given codebase into which this singleton class has been instantiated.
OF COURSE, you would naturally need to free the result sets, and connections when not needed - but that goes without saying, and it's not specific to singletons or any other coding method/style/concept.
At this point, you can see how you can maintain multiple connections/states to third-party applications or services in the same singleton. Not so different.
Long story short, in the end, singleton patterns are just another method/style/philosophy to program with, and they are as useful as ANY other when they are used in the correct place, in the correct fashion. Which is not different from anything.
You will notice that in most of the articles in which singletons are bashed, you will also see references to 'globals' being 'evil'.
Let's face it - ANYthing that is not used properly, abused, misused, IS evil. That is not limited to any language, any coding concept, any method. Whenever you see someone issuing blanket statements like 'X is evil', run away from that article. Chances are very high that it's the product of a limited viewpoint - even if the viewpoint is the result of years of experience in something particular - which generally ends up being the result of working too much in a given style/method - typical intellectual conservatism.
Endless examples can be given for that, ranging from 'globals are evil' to 'iframes are evil'. Back around 10 years ago, even proposing the use of an iframe in any given application was heresy. Then comes Facebook, iframes everywhere, and look what has happened - iframes are not so evil anymore.
There are still people who stubbornly insist that they are 'evil' - and sometimes for good reason too - but, as you can see, there is a need, iframes fill that need and work well, and therefore the entire world just moves on.
The foremost asset of a programmer/coder/software engineer is a free, open and flexible mind.
Singletons are considered by many to be anti-patterns as they're really just glorified global variables. In practice there are relatively few scenarios where it's necessary for a class to have only one instance; usually it's just that one instance is sufficient, in which case implementing it as a singleton is completely unnecessary.
To answer the question, you're right that singletons are overkill here. A simple variable or function will do. A better (more robust) approach, however, would be to use dependency injection to remove the need for global variables altogether.
In your example you're dealing with a single piece of seemingly unchanging information. For this example a Singleton would be overkill and just using a static function in a class will do just fine.
More thoughts: You might be experiencing a case of implementing patterns for the sake of patterns and your gut is telling you "no, you don't have to" for the reasons you spelled out.
BUT: We have no idea of the size and scope of your project. If this is simple code, perhaps throw away, that isn't likely to need to change then yes, go ahead and use static members. But, if you think that your project might need to scale or be prepped for maintenance coding down the road then, yes, you might want to use the Singleton pattern.
First, I just want to say that I don't find much uses to the Singleton pattern. Why would one want to keep a single object thorough the whole application? Especially for databases, what if I want to connect to another database server? I have to disconnect and reconnect every time...? Anyway...
There are several drawbacks to using globals in an application (which is what the traditional use of the Singleton pattern does):
Difficult to unit test
Dependency injection issues
Can create locking issues (multi-threaded application)
Use static classes instead of a singleton instance provides some of the same drawbacks as well, because the biggest problem of singleton is the static getInstance method.
You can limit the number of instances a class can have without using the traditional getInstance method:
class Single {
static private $_instance = false;
public function __construct() {
if (self::$_instance)
throw new RuntimeException('An instance of '.__CLASS__.' already exists');
self::$_instance = true;
}
private function __clone() {
throw new RuntimeException('Cannot clone a singleton class');
}
public function __destruct() {
self::$_instance = false;
}
}
$a = new Single;
$b = new Single; // error
$b = clone($a); // error
unset($a);
$b = new Single; // works
This will help on the first the points mentioned above: unit testing and dependency injection; while still making sure a single instance of the class exist in your application. You could, per example, just pass the resulting object to your models (MVC pattern) for them to use.
Consider simply how your solution differs from the one presented in the PHP docs. In fact, there is just one "small" difference: your solution provides callers of the getter with a PDO instance, while the one in the docs provides callers of Database::singleton with a Database instance (they then use the getter on that to get a PDO instance).
So what conclusion do we reach?
In the documentation code, callers get a Database instance. The Database class may expose (in fact, it should expose if you 're going to all this trouble) a richer or higher-level interface than the PDO object it wraps.
If you change your implementation to return another (richer) type than PDO, then the two implementations are equivalent. There's no gain to be had from following the manual implementation.
On the practical side, Singleton is a pretty controversial pattern. This is mainly because:
It's overused. Novice programmers grok Singleton much easier than they grok other patterns. They then go on to apply their newfound knowledge everywhere, even if the problem at hand can be solved better without Singleton (when you 're holding a hammer, everything looks like a nail).
Depending on the programming language, implementing a Singleton in an airtight, non-leaky manner can prove to be a titanic task (especially if we have advanced scenarios: a singleton depending on another singleton, singletons that can be destroyed and re-created, etc). Just try to search for "the definitive" Singleton implementation in C++, I dare you (I own Andrei Alexandrescu's groundbreaking Modern C++ Design, which documents much of the mess).
It imposes additional workload both when coding the Singleton and when writing code to access it, workload which you can do without by following a few self-imposed constraints on what you try to do with your program variables.
So, as a final conclusion: your singleton is just fine. Not using Singleton at all is just fine most of the time as well.
Your interpretation is correct. Singletons have their place but are overused. Often, accessing static member functions is sufficient (notably, when you do not need to control time-of-construction in any way). Better, you can just put some free functions and variables in a namespace.
When programming there is not "right" and "wrong"; there is "good practice" and "bad practice".
Singletons are generally created as a class to be reused later. They need to be created in such a way that the programmer doesn't accidentally instantiate two instances while drunkenly coding at midnight.
If you have a simple little class that shouldn't be instantiated more than once, you don't need to make it a singleton. It's just a safety net if you do.
it's not always bad practice to have global objects. If you know that you're going to use it globally/everywhere/all the time, it may be one of the few exceptions. However, globals are generally considered "bad practice" in the same way that goto is considered bad practice.
I don't see any point to this at all. If you implemented the class in such a way that the connection string was taken as a parameter to the constructor and maintained a list of PDO objects (one for each unique connection string) then maybe there would be some benefit, but the implementation of singleton in this instance seems like a pointless exercise.
You are not missing anything, as far as I can see. The example is pretty flawed.
It would make difference, if the singleton class had some non-static instance variables.
In a theoretical database access class, I found that there are quite a few helper functions that I use in the class, which have nothing to do the class's instance (and others, that could be manipulated to be unrelated to the class's instance using dependency injection).
For example, I have a function that gets a string between two other strings in a variable. I've been thinking of moving that to a String_Helper class, or something of the sort. This function has already been made static.
Also, I have a function that queries a database, query($sql). The connection details are provided by the instance, but I've been considering making it static, and using query($sql, $connection). Developers would then be able to call it statically and not need to instantiate the database class at all.
For me, the questions are:
Is it worth it to do something like this? Functions like the query function make me wonder if this is not just me trying to make everything as static as possible, without any real need to. Under what circumstances would you consider this useful?
I know static functions are harder to test, but if I make sure that their code is completely dependency free (or uses dependency injection where necessary), then they're just as easy to test as everything else, surely?
It isn't a concern at the moment, but if, in the future, I decided to extend the classes with the static functions, it would be impossible for me to make the current code use my extended functions. I've thought of Singletons, but the same problem arises: the code would be calling Singleton_Class::getInstance(), and not My_Extended_Singleton_Class::getInstance(). Dependency Injection seems to be the only way to solve this issue, but it might lead to a clunkier API, as every dependency has to be given to an object on __construct().
I have a container class, which holds certain pieces of information statically so that they can be accessed anywhere in the script (global scope). If I can't use static functions or singletons, a class that contained instances of different variables would be great. One could use for example Container::$objects['MyClass'] = $MyClass_object;, and then the rest of the code could just access Container::$objects['MyClass']. If I extended the MyClass class, I could use Container::$objects['MyClass'] = $MyExtendedClass_object;, and the code that used Container::$objects['MyClass'] would use MyExtendedClass, rather than MyClass. This is by far the best way to do it, in my opinion, but I'd like to know what you think about it.
Ok, let me answer these one by one...
1. Is it worth doing something like this
Yes and no. Splitting out the helper functions into their own classes is a good idea. It keeps the "scope" of each of the classes rigidly defined, and you don't get creap. However, don't make a method static just because you can. The query method is there to make your life easier by managing the connection, so why would you want to lose that benefit?
2. They are harder to test
They are not harder to test. Static methods that depend on state are harder to test (that access static member variables or global variables). But static methods in general are just as easy to test as instance methods (in fact, they can be easier since you don't need to worry about instantiation).
3. Extending the classes
This is a valid concern. If you put String_Helper::foo() in the class itself, you'll run into issues. But an option would be to set the name of the string helper as a class variable. So you could then do {$this->stringHelper}::foo() (note, PHP 5.3 only). That way to override the class, all you need to do is change the string helper class in that instance. The Lithium framework does this a lot...
4. Global Registry
I would stay away from this. You're basically just making every class a singleton without enforcing it. Testing will be a nightmare since you're now dependent on global scope. Instead, I'd create a registry object and pass it to classes via the constructor (Dependency Injection). You still accomplish the same thing since you have a store for the objects/classes, but you're no longer dependent on a global scope. This makes testing much easier.
In general
When you're looking at doing things like this, I like to stop when I hit questions like this. Stop and sit down and think *What actual problem am I trying to solve?". Enumerate the problem explicitly. Then pull our your supposed solutions and see if they actually solve them. If they do, then think about the future and if those solutions are really maintainable in the long run (Both from a bug fix standpoint, and with respect to feature additions). Only if you're happy with both of those answers should you even consider doing it. Oh, and also remember to keep it simple. Programming is not about making the most complex, most clever or most amazing solution. It's about making the simplest solution that solves the problem...
I hope that helps...
Good Luck!