PHP autoload and static variable in function
Asked Answered
X

2

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?

Xerosere answered 9/9, 2015 at 8:29 Comment(11)
3v4l.org/MKSS9 Looks okay to me.Jujutsu
And to me : codepad.org/oB6SotsiRumormonger
It's ok if all class in one file. If one class in one file, it's error.Xerosere
Why it is not 1,2,3 ?!?! :/Selangor
Oh, it troubled me too.Xerosere
Is __autoload really important to reproduce this problem? Any difference if you import the classes manually? If it works the same without __autoload, you should take it out of the picture. Otherwise make more explicitly that this is only happening when using __autoload.Preside
PS: it does seem like autoloading is a crucial part of this. Using three require_once statements instead results in 1,1,1.Preside
My guess is that you are using opcache. And if you disable it, the problem will go away.Knickknack
Which version of php are you using?Cadet
It is not enabled by default, it is a compile time option...Knickknack
@Knickknack My mistake, will delete the comment :)Jujutsu
G
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.

Grefer answered 9/9, 2015 at 14:8 Comment(5)
How does that explain how B returns 2 too?Jujutsu
@JonStirling B inherits from Base, not from A.Grefer
Ah yes, I think that makes sense.Jujutsu
What do you mean by that a class is bound?Xerosere
@Xerosere The moment where the class is made available, internally (in source code) it's called class binding (early binding (immediately), delayed binding (what happens here), ...). Basically the merging of the class hierarchy in a class - and only after that you can use that class.Grefer
P
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.

Phaidra answered 9/9, 2015 at 13:34 Comment(4)
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 CLUELESSCadet
maybe it is some kind of bug in PHP while autoloadingPhaidra
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.Cadet
@Cadet No, it's not a bug. PHP is just not backing up the initial value of the static variable (see my answer).Grefer

© 2022 - 2024 — McMap. All rights reserved.