18

Up until today, I thought I had a fairly good grasp of how the static modifier worked. I know that (in laymans terms) a static variable in a function does not 'reset' across calls to that function, and I know that static variables and functions on a class are accessible by calling upon them through the class itself (not an instantiation of the class).

My problem is this: today I found that if I declare a static variable inside of a non-static function on a class, all instantiations of that class share that static variable in separate calls to the member function.

For example:

class A {
    public function GetValue() {
        static $value = 0;
        $value++;
        return $value;
    }
}

$instance_1 = new A();
$instance_2 = new A();
echo $instance_1->GetValue();
echo $instance_1->GetValue();

echo $instance_2->GetValue();
echo $instance_2->GetValue();

echo $instance_1->GetValue();
echo $instance_1->GetValue();

Notice that the GetValue function is neither declared as static or used in a static way (as in, called on the class itself).

Now, I always assumed that this would output: 121234

Instead, I find that it will output: 123456

Like I say, I would understand this if the static variable $value was inside of a static function. However, with it being inside a non-static function I just assumed that it would only be 'tied' to the function 'within' each individual instantiation.

I guess my question is twofold, then... 1) is this a bug or expected behaviour? 2) do other languages treat these 'static inside non-static' variables the same way, or is this unique to PHP?

Narcissus
  • 3,144
  • 3
  • 27
  • 40
  • I've seen several questions on SO about behavior of `static` in PHP. Would seem that this is an area lacking documentation - either in quantity or quality. – AJ. Jul 06 '11 at 18:16
  • *(reference)* [static variables](http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static) – Gordon Jul 06 '11 at 18:21
  • that's suck. I thought "static" in this case means that variable will not be reset for this 'object', but not for the 'class'. Again anti-intuitive behavior. And if in other languages behavior is same - they all are just stupid idiots. This method is not static, so method belongs to object instance. Variable belongs to method, so variable should belong only to object, not class. Ahh... – OZ_ Jul 06 '11 at 18:24
  • 1
    @Gordon: to be fair, after looking at that link again (which I did initially), the 'most recent' comment that I can find that addresses this particular case is dated 13-Dec-2005 08:22 :) – Narcissus Jul 06 '11 at 18:27
  • @OZ_: You're thinking about member functions in the wrong way. Read my answer below... – Oliver Charlesworth Jul 06 '11 at 18:31
  • @Oli Charlesworth you're thinking about member functions in the wrong way, read my comment above. – OZ_ Jul 06 '11 at 18:35
  • @OZ_: No, I'm not! PHP derives its OO semantics from Java, C++, etc. The semantics of member functions in C++ are just like I explain in my answer, because that's how they were originally implemented on top of C (back when C++ was just a preprocessor). If you want a per-object member variable, then declare a non-static member variable! – Oliver Charlesworth Jul 06 '11 at 18:36
  • @Oli Charlesworth so they were implemented wrong. And that's suck. I see you like "!" symbol, I can give you some: "!!!!!!!!!!!!!!". – OZ_ Jul 06 '11 at 18:38
  • @OZ_: Who says they were implemented wrong? – Oliver Charlesworth Jul 06 '11 at 18:39
  • @Oli Charlesworth, read my explanation of my opinion. And calm down. – OZ_ Jul 06 '11 at 18:41
  • @OZ_: I'm perfectly calm, thanks. I'm just challenging your assumption that what you believe to be true is actually the case. The behaviour of `static` is not exactly what you expected, that doesn't mean that it was "implemented by idiots". – Oliver Charlesworth Jul 06 '11 at 18:42
  • @Narcissus I just put it there for reference. I didnt mean to imply the solution is in there. – Gordon Jul 06 '11 at 20:19

3 Answers3

7
  1. This is expected.
  2. This is also the case in C++ (and probably others as well).

You should think of non-static class member functions as if they were just like ordinary functions, but with an implicit $this argument that is automatically provided by the interpreter. (That's exactly how they're implemented in most languages.)

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
7

I've copied the following information from this article by Josh Duck: http://joshduck.com/blog/2010/03/19/exploring-phps-static-scoping/

Static variables have been available since PHP 4 and allow you to define a persistent variable that is only accessible from the current function. This allows you to encapsulate state into a function or method and can eliminate the need for classes where a single function will suffice.

When a static variable is defined inside a class method they will always refer to the class on which the method was called. In doing this they act almost like properties referenced through static, though there are subtle differences.

Static variables can’t preserve the calling class scope. This can be potentially problematic if you have an inherited method containing a static variable that is called from both inside and outside its class.

Community
  • 1
  • 1
Bruno Silva
  • 3,077
  • 18
  • 20
3

As far as I know, all languages with static variables treat them this way. Think of static variables as global variables that can only be accessed from a certain scope.

Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • While I like this way of looking at, I think I'm still pigheaded enough to say that I don't think it should be done this way in the first place :s – Narcissus Jul 06 '11 at 18:37
  • If you want a variable that holds its value across class method invocations, @Narcissus, just use a standard member variable. – Don Kirkby Jul 07 '11 at 17:32
  • most of the time I do do this, but I liked the idea of a function being able to cache its own results to return later on, without that cache polluting the class itself, if that makes sense. – Narcissus Jul 08 '11 at 12:05