Question

If I have code which uses a static variable for caching purposes like this:

class BossParty
{
    // ...

    public function getTemplate()
    {
        static $template;

        if ($template == null)
        {
            $template = BossTemplate::get($this->templateID);
        }

        return $template;
    }

    // ...
}

Will $template persist across different instances of BossParty? I've tried checking php.net, but all I can find is info about static class variables.

Was it helpful?

Solution

Yes, the static variable will persist across instances of the class.

Example:

<?php

class Test {
    public function __construct() {
        static $foo;

        if ($foo) {
            echo 'found';
        } else {
            $foo = 'foobar';
        }
    }
}

$test1 = new Test();
$test2 = new Test();
// output "found"

Note that this is true for descendant classes too. If we had a class Child that extended Test, calling parent::__construct (whether explicitly or implicitly) will use the same value of $foo.

OTHER TIPS

@lonesomeday, that seems to be mostly correct. However, in particular related to your followup comment regarding inheritance, the behavior of static variable scope inside functions seems to be more complex. I'm using PHP 5.3.16 for all my examples.

The summary: the behavior of the static keyword when used to scope a variable within an instance function seems to vary based both on inheritance and where in the function call stack you are.

Here are a few examples.

First, this is similar to your initial example: instantiate a static variable within the __construct() method of a class, create two instances of that class, and see how that variable behaves.

<?php
// Example 1
class A {
  public function __construct() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

So far, no surprises. The variable is instantiated once (to 0) and then incremented with each separate instance.

If you extend class A as B, and instantiate one of each (leaving everything else the same), you get the same behavior:

<?php
// Example 2
class A {
  public function __construct() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

Once again, no surprises. Let's go back to the first example and tweak it a bit. First we move the static variable instantiation/increment call to a member method. Note that I've removed class B for this one:

<?php
// Example 3
class A {
  public function __construct() {
    $this->setI();
  }

  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
$o1 = new A();
$o2 = new A();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

Still the same output.

However, when you extend A as B, and leave the same structure in place:

<?php
// Example 4
class A {
  public function __construct() {
    $this->setI();
  }

  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 1"
?>

Note the output: in all other cases, $o2->i became 2, except for this one.

So it seems that if we extend A and move the static instantiation to an instance method, we now seem to have introduced a new scope for the $i variable, whereas in all other cases the instances have shared a scope for that static variable.

Even more confusing, consider this example; it's identical to the previous one, but in this case, class B gets its own implementation of setI(), which simply yields to its parent class's implementation:

<?php
// Example 5
class A {
  public function __construct() {
    $this->setI();
  }
  public function setI() {
    static $i = 0;
    $i++;
    $this->i = $i;
  }
}
class B extends A {
  public function setI() {
    parent::setI();
  }
}
$o1 = new A();
$o2 = new B();
printf("\$o1->i: %d\n", $o1->i); // outputs "$o1->i: 1"
printf("\$o2->i: %d\n", $o2->i); // outputs "$o2->i: 2"
?>

As you can see, $o2->i is now back to being set to 2, which is what we got nearly everywhere (except Example #4)

This, to me, seems very counterintuitive. I would expect that either different instances get their own scopes for that variable, or all instances (including instances of extended classes) share the same scope.

I can't tell if this is a bug in PHP, or if it's expected behavior. The PHP docs on static variable scope say:

A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope.

They don't go into detail as to how 'function scope' is defined in the context of object instances, so I'm not sure if the edge case in Example #4 is expected or not.

Yes it will, it's also documented in the docs, but it's under the section Variables Scope instead of the Static Keyword, which might be the reason you didn't find it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top