Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are static variables in functions in PHP global across instances?

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.

like image 348
Aistina Avatar asked May 16 '11 10:05

Aistina


People also ask

Are static variables shared between instances?

Static variables are shared among all instances of a class. Non static variables are specific to that instance of a class. Static variable is like a global variable and is available to all methods. Non static variable is like a local variable and they can be accessed through only instance of a class.

Are static variables always global?

Static Variables A static variable can be either a global or local variable. Both are created by preceding the variable declaration with the keyword static. A local static variable is a variable that can maintain its value from one function call to another and it will exist until the program ends.

Can we use static variable globally?

A global variable can be accessed from anywhere inside the program while a static variable only has a block scope. So, the benefit of using a static variable as a global variable is that it can be accessed from anywhere inside the program since it is declared globally.

Are variables in PHP global?

Some predefined variables in PHP are "superglobals", which means that they are always accessible, regardless of scope - and you can access them from any function, class or file without having to do anything special.


2 Answers

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.

like image 127
lonesomeday Avatar answered Sep 20 '22 18:09

lonesomeday


@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.

like image 38
joel boonstra Avatar answered Sep 21 '22 18:09

joel boonstra