16

=== Base.php ===

<?php
class Base
{
    public static function e()
    {
        static $number = 0;
        $number++;
        var_dump($number);
    }
}

=== A.php ===

<?php
class A extends Base {}

=== B.php ===

<?php
class B extends Base {}

=== test.php ===

function __autoload($classname)
{
    require_once("{$classname}.php");
}

Base::e();
A::e();
B::e();

php test.php, result is:

int(1)
int(2)
int(2)

Why not result is 1,1,1?

Jelly
  • 189
  • 5

2 Answers2

6

Try

require "Base.php";
Base::e();
require "A.php";
A::e();

vs.

require "Base.php";
require "A.php";
Base::e();
A::e();

The former will yield int(1) int(2), while the latter yields int(1) int(1).

Why?

When a class is bound, the static variable content is copied at exactly that moment how it currently is. There is no backing up of the original value of the static variable.

That implies, when the static variable is 0 when class A is bound, A::e() will have 0 as static value; in case it's 1, A::e() will also have 1 as value.

Similar for B::e() then, as Base::e() and A::e() are independent as the values are copied (no references). It will also have the same static variable Base::e() has at the binding time of B.

bwoebi
  • 23,637
  • 5
  • 58
  • 79
1

I did some research on this problem and it is really weird.

Static properties inside methods remain their state between instances of object. Which may be confusing. Also there are two statics one is the static function and the other one is static variable inside method.

It may be connected with autoloader. I did similar example with your but without using static methods but using static variable inside method. The result is 1:1:1 using both autoloader and same file.

<?php
class Base
{
    public function t()
    {
        static $number = 0;
        $number++;
        var_dump($number);
    }

    public static function e()
    {
        static $number = 0;
        $number++;
        var_dump($number);
    }
}


$base = new Base();
$base->t();

$a = new A();
$a->t();

$b = new B();
$b->t();

Also if you won't execute Base::e() the result is correct.

I've did require_once without autoloading and it still works. So it is definitly because of autoloader.

If you put

require_once "Base.php";
require_once "A.php";
require_once "B.php";

instead of autoloader function it works. Why is that I have no idea I've tried to find anything considering static variables with autoloader but without success. However, this answer may give you some clue.

Robert
  • 19,800
  • 5
  • 55
  • 85
  • I answer two times this question, both wrongly. I'm still unaware of why spliting the files (now we know it's related with the Autoloader) affect the result. TRULY CLUELESS – Joako-stackoverflow Sep 09 '15 at 13:56
  • maybe it is some kind of bug in PHP while autoloading – Robert Sep 09 '15 at 13:57
  • Could be mate but, seems too basic and the impact it's to great to be an error. Could be if it's using a experimental branch of php, but it's unlikely. – Joako-stackoverflow Sep 09 '15 at 14:00
  • @Joako-stackoverflow No, it's not a bug. PHP is just not backing up the initial value of the static variable (see my answer). – bwoebi Sep 09 '15 at 14:10