tags:

views:

174

answers:

4

I've come across some unexpected behavior with static variables defined inside object methods being shared across instances. This is probably known behavior, but as I browse the PHP documentation I can't find instances of statically-defined variables within object methods.

Here is a reduction of the behavior I've come across:

<?php

class Foo {
  public function dofoo() {
    static $i = 0;
    echo $i++ . '<br>';
  }
}

$f = new Foo;
$g = new Foo;

$f->dofoo(); // expected 0, got 0
$f->dofoo(); // expected 1, got 1
$f->dofoo(); // expected 2, got 2

$g->dofoo(); // expected 0, got 3
$g->dofoo(); // expected 1, got 4
$g->dofoo(); // expected 2, got 5

Now, I would have expected $i to be static per instance, but in reality $i is shared between the instances. For my own edification, could someone elaborate on why this is the case, and where it's documented on php.net?

+3  A: 

This is the very definition of static.

If you want members to be specific to an instance of an object, then you use class properties

e.g.

<?php

class Foo
{
    protected $_count = 0;
    public function doFoo()
    {
        echo $this->_count++, '<br>';
    }
}

Edit: Ok, I linked the documentation to the OOP static properties. The concept is the same though. If you read the variable scope docs you'll see:

Note: Static declarations are resolved in compile-time.

Thus when your script is compiled (before it executes) the static is "setup" (not sure what term to use). No matter how many objects you instantiate, when that function is "built" the static variable references the same copy as everyone else.

hobodave
That documentation is for static class properties and methods, not static variables within a method.
Adam Backstrom
Adam: In PHP5 they are one and the same. Static is static.
hobodave
In my mind, `$f->dofoo()` is not the same method as `$g->dofoo()`. Obvious the PHP developers are not of the same mind. :)
Adam Backstrom
You're correct, they aren't the same, but they both act on the same variable because you marked it as static.
Chad
Adam: updated my answer with a few more details.
hobodave
Thanks Dave, that was more along the lines of what I was looking for: the static reference is tied to the line of code (in a way), rather than any instances defined during execution.
Adam Backstrom
A: 

If you expected a 0, you should make $i a class variable instead.

Tim Cooper
That's a little off topic, but in practice I am using the static within the method to lazy-load other objects and act as an accessor.
Adam Backstrom
+1  A: 

That is what static is, it's the same variable across all instances of the class.

You want to write this so that the variable is a private member of the instance of the class.

class Foo {
  private $i = 0;
  public function dofoo() {
    echo $this->i++ . '<br>';
  }
}
Chad
+1  A: 

The static keyword can be used with variables, or used with class methods and properties. Static variables were introduced in PHP 4 (I think, it might have been earlier). Static class members/methods were introduced in PHP 5.

So, per the manual, a static variable

Another important feature of variable scoping is the static variable. A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope.

This is consistant with the behavior you described. If you want a per instance variable, used a regular class member.

Alan Storm