Globals

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Globals

Post by Ambush Commander »

Globals are the sort of things you see in projects that started off small but got really big. They can get really evil after a while.

The thing is PHP makes it really, really really easy to use globals, easy to the point where a MediaWiki developer commented:
PHP loves globals. I hate them. This is not a great
combination, but I manage. I could get rid of most of
them by having a single "HTTP request" object, and using
it to hold everything that's now global (which is exactly
what I'd do in a Java servlet). But that's really
awkward in PHP, and wouldn't really provide much benefit
in readability or maintainability, so I go with the flow
of PHP and use globals. Here's documentation on the
important globals used by the system.
In your opinion, is this analysis of the situation correct? I've been using a single global Registry class, which had to be propogated and then used to retrieve whatever global class I wanted, resulting in several lines of code in order to get to one global class. And I don't like this very much. But global data is evil! Evil I say! But where there's repetition, there's refactorability.

Code: Select all

$Registry =& Registry::instance();
$Mapper_User =& $Registry->getMapperUser();
becomes

Code: Select all

global $wgMapperUser;
Edit - It appears I'm whacking a question I asked previously again... I'm using a Registry built for unit testing now though.
Gambler
Forum Contributor
Posts: 246
Joined: Thu Dec 08, 2005 7:10 pm

Post by Gambler »

Why not

Code: Select all

$mapperUser = &Registry::get('mapperUser');
?

Anyway, you can't completely avoid using globals in PHP, because php has no real namespaces. You can encapsulate data inside classes or functions, but classes and funtions themselves are in global namespace. All you do is decrease probability of name collision by decreasing quantity of global names.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

The closest I usually get to using globals in a large application is having variables global to an entire class ( $this -> someVar ), other then that I just use constants. On occasion I do use globals, I don't really see the big deal, if used properly they are very convenient, everyone regards them with the same distaste they hold for registerglobals (which really is evil, and much harder for beginners to use properly). Plus I love the idea of superglobals, I don't know what I would do if I couldn't access post/get data from anywhere in my application without having to worry about variable scope.


I definitely see the advantages to a registry object, but I never find myself ever having to implement anything like that, when I do need higher levels of organization on my globals I just created multi-arrays on the globalscope, I've yet to have any issues with it and it's certainly straight foward.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

I personally used to really enjoy globals.. until I had the agonizing pain of trying to debug an application full of them. Using globals gives you no sense of where the global comes from, and makes your classes reliant on the globals existing, which is usually bad. I really hate having to worry about instances of overwritting variable within the local scope, which seems to happen quite frequency when using globals.. I generally use common variable names for certain properties and such, and when you overwrite a varible it is difcult too discover what exactly is going wrong. All this is pretty much avoided on having used a registry class.

Before I was introduced to the registry/singleton patterns I used to encapsulate all my classes within a super global array, which I agree is efficient, but I simply would not sacrafice the elegance of a non global application.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

When the number of global variables is too large to keep track of, I contain them within an array

psuedo code:

Code: Select all

$globals['foo'] = 'hello';
$globals['bar'] = 'world';

function takeOverTheWorld () {
      global $globals;
      // its kind of hard to get $globals['foo'] confused with $foo
}

this is actually more elegant [to me] then a registry, don't get me wrong I see where the registry object is the right way to go, I just haven't had the need.


but anyways, I hardly ever find myself using globals... maybe for object to object communication but I try to use constants where I can. Even if I were to use a registry object I would probably just declare the object on the global scope, so I don't have to worry about passing references to all my constructors... to me that is more confusing then using the "global array"
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

I have an application object which, among other things, contains the "global" variables. Here's concept in simplified PHP 5 code (not tested):

Code: Select all

class TApplication {
  private function __construct() {}
  private function __destruct() {}
  static public function __get($name) {
    $o = self::Instance();
    if(!isset($o->$name)) {
      $o->$name = new Stdclass();
    }
    return $o->$name;
  }
  static protected function Instance() {
    static $me = null;
    if($me === null) {
      $me = new TApplication();
    }
    return $me;
  }
}
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

so I don't have to worry about passing references to all my constructors


Since when do you have to pass the object reference in the constructor in Registries?[/u]
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I really hate having to worry about instances of overwritting variable within the local scope, which seems to happen quite frequency when using globals.
As jshpro2 pointed out, you can either use a single globalized array, or you can enforce strict naming conventions where all global variables must be prefixed with $wg or something. Then the problem is gone.
this is actually more elegant [to me] then a registry, don't get me wrong I see where the registry object is the right way to go, I just haven't had the need.
The reason why the Registry object is "good" is because it gives an explicit, hard-coded interface for exactly "what" is global. If you enforce getting the global objects via a method, it can report to you who has taken a reference of the object, and it makes substituting global objects with mock objects or server stubs real easy.
Using globals gives you no sense of where the global comes from, and makes your classes reliant on the globals existing, which is usually bad.
This is why you should always make a point of trying to pass the variable through the parameters if possible.
Since when do you have to pass the object reference in the constructor in Registries?
I think he's talking about with the objects in his domain, he would have to pass the registry object around via the parameters. There are some tricks (i.e. static) to make the registry globally available via class+function definition (which can't be overwritten), but in it's essence, it's still global data.
Why not
Well, it's not explicit, and I feel that if you don't make things explicit, you give up one of the advantages of using a registry in the first place.
josh
DevNet Master
Posts: 4872
Joined: Wed Feb 11, 2004 3:23 pm
Location: Palm beach, Florida

Post by josh »

Very good points Mr. Ambush,

The point that hit me the hardest was keeping track of who can access what data (or who has accessed what data). I can still control who CAN access what data from within the class accessing the data (I am the only programmer on all my projects so I control what exactly each object does). If I ever did switch to a true registry object, it would probably be:

Code: Select all

$reg = new registry();
class something {
   var $reg;
   function something() {
       global $reg;
       $this -> reg &= $reg;
   }
}
but in an example like this I'd just rather use the built in global functions. I will also admit to the fact I have a very awkward style of coding but it suites me well
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

There is a temptation to simply call the registry object during construction and then store a copy of the object in the class. I personally don't like it because it makes var_dump'ing really awkward. jshpro2, I suggest reading this to see how you can do this with just definitions and not globals. $reg is bound to collide with something...
I am the only programmer on all my projects so I control what exactly each object does
Well, even on our pet projects we programmers are fallible.
Gambler
Forum Contributor
Posts: 246
Joined: Thu Dec 08, 2005 7:10 pm

Post by Gambler »

Ambush Commander wrote:Well, it's not explicit, and I feel that if you don't make things explicit, you give up one of the advantages of using a registry in the first place.
Not explicit in what way?

To feyd:
Why do you use singleton to do what can be done with static method and static variable?

Anyway, I've read about this registry pattern, and I don't get it. In php 4 it makes some sence, but PHP has static variables for that kind of things:

Code: Select all

$mapperUser = &SomeClass::$mapperUser;
$mapperUser = 11;
However, you should not do this, because it will mask the fact that mapperUser belongs to SomeClass. So the right way to do this would be:

Code: Select all

SomeClass::$mapperUser = 11;
No namespace problems (as long as your class names do not collide).
No overhead.
No messy syntax.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Not explicit in what way?
I assume that a scheme like that would simply have an array which you would retrieve objects from like $this->objects[$name]; which is not explicit, since you have no way from just looking at the code to know what objects are in that array.
Post Reply