Автозагрузка PHP и статическая переменная в функции

=== 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, результат:

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

Почему не результат 1,1,1?

Ответы

Ответ 1

Try

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

против.

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

Первое будет давать int(1) int(2), а последнее дает int(1) int(1).

Почему?

Когда класс привязан, содержимое переменной static копируется именно в тот момент, каким оно является в настоящий момент. Нет резервной копии исходного значения статической переменной.

Это означает, что когда статическая переменная 0, когда класс A привязан, A::e() будет иметь 0 как статическое значение; в случае, если 1, A::e() также будет иметь значение 1.

Аналогично для B::e(), тогда как Base::e() и A::e() независимы при копировании значений (без ссылок). Он также будет иметь ту же статическую переменную Base::e(), которая имеет время привязки B.

Ответ 2

Я провел некоторое исследование по этой проблеме, и это действительно странно.

Статические свойства внутри методов остаются их состоянием между экземплярами объекта. Это может сбить с толку. Также есть две статики: статическая функция, а другая - статическая переменная внутри метода.

Он может быть связан с автозагрузчиком. Я сделал аналогичный пример с вашим, но не использовал статические методы, но использовал статическую переменную внутри метода. Результат - 1:1: 1, используя как автозагрузчик, так и тот же файл.

<?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();

Также, если вы не выполнили Base::e(), результат будет правильным.

Я сделал require_once без автозагрузки, и он все еще работает. Так что это определенно из-за автозагрузчика.

Если вы положили

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

вместо функции автозагрузчика он работает. Почему я не знаю, я пытался найти что-либо, рассматривая статические переменные с автозагрузчиком, но безуспешно. Однако этот ответ может дать вам некоторые подсказки.