GLOBALS

Ive often wondered this, and thought it would be a good time to ask
Why shouldnt you use GLOBALS?
Loads of forums say dont use GLOBAL variables, however are we saying pass the variables into the functions?

For example if I have a $db object (which hold the connection credentials etc for a database) which I want to use in another function, for I need to pass the reference $db into the function,  or surly its better to define $db as a global variable and use it in my second function.

I've read articles which suggest NEVER NEVER NEVER use Globals, but surely passing the reference $db into a function isnt/shouldnt be good practice? Or am I thinking wrong here?
tonelm54Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chris HarteThaumaturgeCommented:
The general consensus is that the use of globals is bad practise partly because they are difficult to debug and have excessive overhead. Globals are easy to override, and once you have done that debugging becomes almost impossible.

What ever problem you think you are solving by using globals you will find an easier, more logical, solution that does not use them.
0
Julian HansenCommented:
While not directly addressing the "evil" of globals - this article is good reading to understand the thinking around the patterns that have been developed that specifically avoid globals

http://tutorials.jenkov.com/dependency-injection/dependency-injection-replacing-factory-patterns.html
0
F IgorDeveloperCommented:
If you are interested in make some variables available in your system, try another mechanism.
You can use some Class to get and set specific globals for your application, but do not use GLOBAL as a data store (class attributes instead).
If you declare some global variable more than once, nothing can alert you that your declaration is overwriting some variable in another side of your code.
If you create a class (or even a global function) you are in best position to ensure your code is not interfering with another code. For classes and functions, you are in control over your global resources.


Here is a basic example:

class App {

     var $db;
     var $anotherVar;


    public function connect(){
      //your connection code
      $this->db=$connection:
   }

   public function getDb(){
      if ($this->db===null) {
          $this->connect();
      }
     return $this->db;
  }

}

Open in new window


And then you can access it in your code (after including the class file)


function getData($id){
    App::getDb()->query("...");
  ....
}

Open in new window

0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Ray PaseurCommented:
This is a "simple" question without a simple answer.  There is a lot of deep background thinking that you need to understand why globals are considered harmful.  Here are a couple of articles that scratch the surface, and some of the theory about why globals are a problem.
http://www.experts-exchange.com/articles/18329/SOLID-Design-in-PHP-Applications.html
http://www.experts-exchange.com/articles/18210/Software-Design-Dependencies.html

Singletons are just as bad as globals in many ways.

You may want to make a Google search for "mock objects" and "unit testing."

1. You cannot test anything that is global.
By that, we mean you cannot substitute a mock object for a global variable, because if you substitute it in one place, you've also substituted it in every place.  Now go back and consider your $db variable from the question.  If you create the $db in the initialization code and pass it into your methods and functions, you can use automated test tools to create a mock object for the $db, and you can mock it in each place it is used separately without affecting the other code or functionality of the site.  With the global, you must test on your live database (WTF?!), or you must use a mirror database.  With dependency injection (see the articles linked above) you can isolate the $db on a case-by-case basis.

2. You cannot remove a dependency on a global.
It's global, after all - how do you unset() a global without causing "global" disruption in other parts of your application?  No problem if you're the only programmer on a project, at least not until you make a mistake in a global element of the application.  But if there is more than one programmer working on a project (and anything of value will have more than one programmer) and the programmers have come to depend on a global, any change to the global means all the programmers must rerun all of their tests.  They may even be forced to rewrite their tests.

3. Class members (properties and methods) are confusing enough.
But at least there is a hierarchy of visibility among class members.  Globals are all-or-nothing, and once your code is exposed to a global, you're at the mercy of every bit of programming that runs as a part of the app, whether you wrote it or not.  In other words, if you use my global, you have to trust my global, whether you like it or not.  And I'm doing things with my global that you may never encounter until you experience a run time failure because I did not initialize my global correctly.  In contrast, if you use your own class members, whether by direct reference or dependency injection, you do not have to trust my programming -- your work can be decoupled and tested separately, and changes in my work do not affect your work.

4. But what about PHP superglobal variables?
Yes, superglobal variables are every bit as bad as the global variables you create yourself.  They are an artifact of PHP's long history, and we can't get rid of them without disrupting the design of existing web applications.  In retrospect, the authors of PHP did not know very much about computer science.  If they had, we would never have had something as unfortunate as Register Globals.  There is one saving grace, however.  We know the superglobals by their names and where they live, so we can deal with them carefully.

Those are some of my thoughts, now on to the question of "I have a lot of dependencies and it's hard to remember how to write my function calls because of all the things I have to inject into the functions."  That can be a real problem because PHP function arguments are positional parameters, so you have to remember them in sequential order.  If you have a class method that needs half-a-dozen dependencies (also called function arguments) it's easy to confuse the order.  So here's a design pattern that uses type hinting and a parameter object to simplify this problem.  It lets you use named parameters which can be easy to remember.  The order of your arguments does not matter.
http://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html

HTH, ~Ray
1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
tonelm54Author Commented:
Ok, so if I understand right I need to pass the reference of a database object, for example this wont work:-
<?php
class db {
     public function getDb(){
  		return "true";
  }
}

$dbConn = new db;

echo $dbConn->getDb();


class db2 {
     public function test(){
  		$dbConn->getDb();
  }
}

$ttt = new db2();
echo $ttt->test();

?>

Open in new window


However if I passed the variable of the database object to a new object can I reference it that, something like:-
<?php
class db {
     public function getDb(){
  		return "true";
  }
}

class db2 {
	var $db2Conn;
	
     public function __construct($dbConnection) {
  		$db2Conn = $dbConnection;
  }
	public function test() {
		$this->db2Conn->getDb();
	}
}



$dbConn = new db;
echo $dbConn->getDb();

$ttt = new db2($dbConn);
echo $ttt->test();

?>

Open in new window

0
Julian HansenCommented:
Mostly - you need to add $this as below to be able to set the internal class variable.

public function __construct($dbConnection) {
   $this->db2Conn = $dbConnection; // Missing $this reference
}

Open in new window

0
Ray PaseurCommented:
This is hyper-simplified, but maybe it will illustrate the essential moving parts of dependency injection, showing how the $mysqli object is not used as a global, but is injected into the function.  Injection into object methods is exactly the same as injection into inline functions.  You just name the thing you want to inject among the variables that are listed in the function definition, and use the thing inside the function or method.
http://iconoun.com/demo/mysqli_di_example.php

<?php // demo/mysqli_di_example.php

/**
 * Demonstrate Dependency Injection with a MySQLi Object
 *
 * Man Page References:
 * http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration
 * http://php.net/manual/en/mysqli.overview.php
 * http://php.net/manual/en/class.mysqli.php
 * http://php.net/manual/en/class.mysqli-stmt.php
 * http://php.net/manual/en/class.mysqli-result.php
 * http://php.net/manual/en/class.mysqli-warning.php
 */

// RAISE THE ERROR REPORTING LEVEL TO THE HIGHEST POSSIBLE SETTING
ini_set('display_errors', TRUE);
error_reporting(E_ALL);
echo '<pre>';

// DATABASE CONNECTION AND SELECTION VARIABLES - GET THESE FROM YOUR HOSTING COMPANY
$db_host = "localhost"; // PROBABLY THIS IS OK
$db_name = "??";
$db_user = "??";
$db_word = "??";

// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);

// DID THE CONNECT/SELECT WORK OR FAIL?
if ($mysqli->connect_errno)
{
    $err
    = "CONNECT FAIL: "
    . $mysqli->connect_errno
    . ' '
    . $mysqli->connect_error
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW WHAT THE DB CONNECTION OBJECT LOOKS LIKE
// var_dump($mysqli);


// A FUNCTION THAT USES AN INJECTED DATABASE CONNECTION
function run_a_query($db, $query)
{
    if (!$res = $db->query($query))
	{
	    $err
	    = 'QUERY FAILURE:'
	    . ' ERRNO: '
	    . $mysqli->errno
	    . ' ERROR: '
	    . $mysqli->error
	    . ' QUERY: '
	    . $sql
	    ;
	    trigger_error($err, E_USER_ERROR);
	}
	$data = $res->fetch_object();
	return $data;
}


// USE THE FUNCTION BY INJECTING THE $mysqli OBJECT AND THE QUERY
$set = run_a_query($mysqli, 'SELECT 2+2 AS ANSWER');
var_dump($set);

Open in new window

0
Ray PaseurCommented:
I'm marking this as a "Good Question" since it inspired this article.  Thanks for asking a question that a lot of others can benefit from!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.