Page 1 of 1

Globals

Posted: Sun Dec 25, 2005 9:06 pm
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.

Posted: Sun Dec 25, 2005 10:22 pm
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.

Posted: Sun Dec 25, 2005 10:55 pm
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.

Posted: Mon Dec 26, 2005 12:00 am
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.

Posted: Mon Dec 26, 2005 12:44 am
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"

Posted: Mon Dec 26, 2005 8:19 am
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;
  }
}

Posted: Mon Dec 26, 2005 10:21 am
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]

Posted: Mon Dec 26, 2005 10:42 am
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.

Posted: Mon Dec 26, 2005 11:33 am
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

Posted: Mon Dec 26, 2005 1:17 pm
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.

Posted: Tue Dec 27, 2005 9:01 am
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.

Posted: Tue Dec 27, 2005 6:01 pm
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.