Jump to content

Alternatives to $_GLOBALS


NotionCommotion

Recommended Posts

Sometimes I have various data which I wish to be available to all scripts.  Typically, they are constants which are related, and using PHP's constants makes them difficult to group.

 

As such, my solution has been to create a single global variable such as $GLOBALS['myGlobalVariable'], and dump them all in it.

 

Are there better ways to implement this?  For instance, using a singleton?  Please provide rational why one solution is better than the other.

 

Thank you

<?php
class mySinglton {
    private static $instance = NULL;
    private function __construct() {}
    private function __clone(){}
    public static function mySinglton($values=null)
    {
        if (!self::$instance)
        {
            self::$instance = new stdClass();
            foreach ($values as $key=>$value) {
                self::$instance->$key=$value;
            }
        }
        return self::$instance;
    }
}

class someClass
{
    public $a=1,$b=2,$c=3;
}

$globals=array(
    'foo'=>'bar',
    'daysOfWeek'=>array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'),
    'someClass'=>new someClass
);

$GLOBALS['myGlobalVariable']=$globals;

mySinglton::mySinglton($globals);

testIt();

function testIt()
{
    echo('<pre>'.print_r($GLOBALS['myGlobalVariable'],1).'</pre>');
    echo('<pre>'.print_r($GLOBALS['myGlobalVariable']['foo'],1).'</pre>');

    echo('<pre>'.print_r(mySinglton::mySinglton(),1).'</pre>');
    echo('<pre>'.print_r(mySinglton::mySinglton()->foo,1).'</pre>');
}

?>

 

Link to comment
Share on other sites

Globals has nothing to do with how you implement singleton pattern. Singleton pattern is there to ensure you only have one instance of an object.

 

If you are needing to use globals then it is sign you are doing it wrong. If a class/function requires a variable then you should pass that variable to the class constructor/function as an argument.

  • Like 1
Link to comment
Share on other sites

If you are needing to use globals then it is sign you are doing it wrong. If a class/function requires a variable then you should pass that variable to the class constructor/function as an argument.

 

You mean I need to do some work :(

 

Do you feel this same way regarding a DB connection?  Currently, I create a singleton and call it in any script.

class db {
    private static $instance = NULL;
    private function __construct() {}   //Make private
    private function __clone(){}   //Make private
    public static function db()
    {
        if (!self::$instance)
        {
            try{self::$instance = new PDO("mysql:host=localhost;dbname=myDatabase;charset=utf8",'myUsername','myPassword',array(PDO::ATTR_EMULATE_PREPARES=>false,PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC));}
            catch(PDOException $e){die(library::sql_error($e,null));}
        }
        return self::$instance;
    }
}
Link to comment
Share on other sites

Globals has nothing to do with how you implement singleton pattern. Singleton pattern is there to ensure you only have one instance of an object.

 

If you are needing to use globals then it is sign you are doing it wrong. If a class/function requires a variable then you should pass that variable to the class constructor/function as an argument.

 

Forget about the part about DB connections, and back to the original question.

 

I have a homegrown MVC architecture, and I have an object with a bunch of properties which are used by the controllers and models. I would rather not pass each given property on a need to use basis, but just pass the whole object.

 

Instead of using a global variable or a singleton object, should I be doing something like...

<?php
$bigObject=new bigObject();
$bigObject->bla="blabla";
$controller=new someController($bigObject);
$controller->someTask();

class  controller
{
    protected $bigObject;
    public function __construct($bigObject)
    {
        $this->bigObject=$bigObject;
    }
}

class someController extends controller
{
    public function someTask()
    {
        $model=new someModel($this->bigObject);
        $data=$model->getSomeData();
        //Deal with view
    }
}

class  model
{
    protected $bigObject;
    public function __construct($bigObject)
    {
        $this->bigObject=$bigObject;
    }
}

class someModel extends model
{
    public function getSomeData()
    {
       return array(1,2,3);
    }
}
?>

 

Link to comment
Share on other sites

I would rather not pass each given property on a need to use basis, but just pass the whole object.

Why? The only reason to do this is laziness. It is making your code tightly coupled to whatever this "god" object is.

 

A controller has no interest in your connection settings for instance.

 

Objects should be passed their dependencies (and only their dependencies) at construction time.

 

Most frameworks handle this in an easy to manage manor by providing a configurable dependency injection container which allows you to configure how objects are to be created.

Link to comment
Share on other sites

Why? The only reason to do this is laziness. It is making your code tightly coupled to whatever this "god" object is.

 

Well, yes laziness, but it does make the code more concise.  As of yesterday, I have never heard the term "dependency injection, and just learned about the god object now (http://en.wikipedia.org/wiki/God_object).  Is tightly coupling always a bad thing?  Note that my god object would be only properties, and maybe a method or two to add properties.

 

 

 

Objects should be passed their dependencies (and only their dependencies) at construction time.

 

Most frameworks handle this in an easy to manage manor by providing a configurable dependency injection container which allows you to configure how objects are to be created.

 

If I didn't wish to use a third party framework, do you have general recommendations on how to implement a "configurable dependency injection container"?

Link to comment
Share on other sites

I am starting to come around and agree that my approach was not correct, and I should pass the object as an argument.

 

That being said, defining a bunch of constants is no better than using a global variable (or some surrogate for a global such as a singleton class), right?  Maybe even worse since it is harder to identify all the user defined constants? I suppose I could use get_defined_constants(true)['user'], however.

 

When is it appropriate to use constants throughout an application?

 

 

Link to comment
Share on other sites

Constants and singletons are nothing like global variables. A singleton is a simple design pattern that attempts to ensure that your system has only one instance of the object at a time. You'll still need to pass the object to any classes or objects that need it through dependence injection. And constants are like readability shortcuts - instead of using $errors[404], you'd use $errors[PAGE_NOT_FOUND] where you've previously defined PAGE_NOT_FOUND as a constant that equates to '404'. Unless I'm mistaken, constants are still subject to scope, at least at the class level. This is why, when defining a PDO query return type for instance, you use PDO::FETCH_CLASS or PDO::FETCH_ASSOC instead of just FETCH_CLASS or FETCH_ASSOC.

 

There are many issues with using globals in production code. First, there's the source identification issue you've already touched upon. Where exactly is $myGlobal assigned in a project with 15 directories, each consisting of two to seven classes? Is it even defined within the code you're looking at, or is it defined in third-party code that's been added as a plugin, for example? Beyond that, there's the very real possibility of inadvertently overwriting the value of the global and causing the system to fail in a very difficult to identify and debug manner (see the previous sentences about source definition). Those two alone keep me from using them - I spend enough time debugging random issues because I can't spell worth a darn to spend more poking into the global namespace looking for logic errors that lead to overwritten variables.

 

Basically, you'll find it easier to read and maintain your code if you create the object you need and then pass that object (or the relevant portions of that object) to the classes that need it. If you're creating a helper class - let's say you've created a class that handles a specific type of calculation that your business logic demands you perform on a regular basis, or does table formatting, or whatever - you can instantiate that object and pass it to your controllers from the kickoff script. Or you can make the helper methods static and call them as 'Helper::formatMyTable($tableData);' - this makes it far easier when suddenly your table has 46 columns instead of the 2 you expect. You know to go to the Helper class and look for the formatMyTable() method, as opposed to simply 'fomatMyTable($tableData);' because, in this case, where the heck is the formatMyTable() function?

Link to comment
Share on other sites

Constants and singletons are nothing like global variables. A singleton is a simple design pattern that attempts to ensure that your system has only one instance of the object at a time. You'll still need to pass the object to any classes or objects that need it through dependence injection. And constants are like readability shortcuts ...

 

Thank you for your reply maxxd,

 

My original plan for a singleton object was to invoke it in the parent script and not pass it to any classes that need it since it was global in nature, and I could access a property in it as mySuperSingleton::mySuperSinglton()->someProperty.  Effectively, I would be doing the same thing as using a global variable which I now understand is not desirable.

 

My contention regarding constants is that they could be abused just the same as globals, and I am sure I have been guilty of doing so.

 

For instance, what if in the entry point of my script, I queried the DB and defined 500 constants based on the returned records?  Now those constants are global throughout all my script.  In practice, I didn't declare 500 constants, but I have done a few.

 

Another area I've used constants is for defining file paths to my root directory, my class directory, etc, etc.  This seems more acceptable, but I don't completely understand the future repercussions.

 

Other uses I have done are for defining constants such as my Google maps key or my recaptcha keys.  Again, seems more acceptable, but again would like advice from others.

 

So, my question is what are acceptable uses for constants, and when are their use detrimental for reasons similar to using global variables?

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.