The static keyword in PHP5

With PHP5, PHP introduced some more robust object oriented capabilities to the language. I’ve been diving into this quite a bit lately and learning a lot. I figured all the stuff I discovered about the static keyword would be enough fodder for a post. Most of this information can probably be gleamed straight from the docs, but I for one didn’t really soak up the denseness of the documentation my first few times around.

Static Members

What isn’t immediately obvious, is that static members are shared among all the instances of the class that has the static member. In other words, it is like a global variable for that class and instances of that class. While you can’t access a static member directly from an instantiation of the class, you can create methods that access or manipulate the static member. Time for a quick example.

  1. class Foo {
  2.   static $var = 0;
  3.   function increment() { self::$var++; }
  4.   function get() { return self::$var; }
  5. }
  6.  
  7. $f1 = new Foo();
  8. $f1->get();  // returns 0
  9. Foo::$var; // returns 0
  10. $f1->increment();
  11. $f2 = new Foo();
  12. $f2->get();  // returns 1
  13. $f2->increment();
  14. $f1->get();  // returns 2
  15. Foo::$var; // returns 2

Now, the other interesting find is that the static member is global not only to that class and instances of that class, but also all sub-classes and instances of those sub-classes. You can prevent this propagation down inheritance tree, by declaring the static member as private or by redeclaring that static member inside the sub-classes, as well as the methods that work on the static method.

  1. class Foo {
  2.   static $var = 0;
  3.   function increment() { self::$var++; }
  4.   function get() { return self::$var; }
  5. }
  6. class Bar extends Foo { }
  7. Foo::$var++;
  8. Bar::$var;  // returns 1

Static Methods

The main area that I got hung up with static methods was using inherited static method calls. For the work I was doing, I wanted to be able to call a static method and within the static method know which class this method was called on. Unfortunately, everything I tried didn’t work.

  1. class Foo {
  2.   static function get_my_class() { return get_class(); }
  3.   function get_my_class2() { return get_class($this); }
  4. }
  5. class Bar extends Foo {}
  6. Bar::get_my_class();  // returns ‘Foo’
  7. $b = new Bar();
  8. $b->get_my_class2();  // returns ‘Bar’

It turns out that static methods belong to the class in which they’re defined and they have no clue where they got called from. Similarly, the same idea can be applied when thinking about static members. The class that has the actual code, determines what variable is affected. Consider one last example:

  1. class Foo {
  2.   static $var = 0;
  3.   function increment() { self::$var++; }
  4.   function get() { return self::$var; }
  5. }
  6. class Bar extends Foo {
  7.   static $var = 23;
  8.   function increment() { self::$var++; }
  9. }
  10. $f = new Foo();
  11. $b = new Bar();
  12. $b->get(); // returns 0 (Foo)
  13. $b->increment();  // increment Bar’s $var
  14. Bar::$var; // returns 24 (Bar)
  15. $b->get(); // returns 0

2 Comments »

  1. joel boonstra said,

    February 12, 2007 @ 2:30 pm

    Luke,

    Have you tried the ‘__CLASS__’ magic constant inside the base and inherited classes? I don’t know for sure if it would behave differently from using the get_class() function, but it might.

    One place I like to use static data members is to store an instance of the class object to implement Singleton. You’d have a private $_instance static member, and then a static public member function that instantiates $_instance if not already set, and then returns $_instance. You could also declare the __construct() method to be private (or protected) to disallow direct class instantiation.

    I like PHP5.

  2. Luke said,

    February 13, 2007 @ 2:16 pm

    Joel,

    I tried a ton of different things when messing with that. In fact, it turns out that in PHP4 you can figure out the class name by going through the backtrace, though for some reason this was removed in PHP5.

    The get_class() example I used wasn’t a very good one, but it was the clearest way I could think of to show an example of the problem. The __CLASS__ magic constant does behave differently, as it will always return the class name from which it is called. If you replace my get_class() function calls with __CLASS__, you end up getting ‘Foo’ for both of those functions.

    As you seem to be suggesting, if I used the __CLASS__ constant in the inherited classes, then it would return the correct inherited class name. In the scenario I was working on, I didn’t want to clutter every inherited class with this duplicated code.

RSS feed for comments on this post · TrackBack URI

Leave a Comment