Статические свойства

405
26 апреля 2017, 13:17

Отметил для себя необычное поведение статических свойств в экземплярах класса есть код:

    class A{
        public static $key=0;
        public function getKey(){
            return self::$key;
        }
    }
    class B extends A {}
    A::$key = 1;
    $b = new B();
    echo $b->getKey();

Здесь все понятно мы изменили статическое свойство класса A::$key = 1; со стороны клиента. И после этого любой экземпляр класса А или наследник этого класса (в данном случае В) будет иметь измененное значение статического свойства $key

Но следующий код мне стал непонятным - в нижеприведенном коде мы изменили статическое свойство экземпляра класса, что автоматически затронуло статическое свойство класса. Это что ? - некая глобальная переменная в рамках всех наследников этого класса? Вот код

<?php 
    class A{
        protected static $key=0;
        public function plus(){
            ++self::$key;
        }
        public function getKey(){
            return self::$key;
        }
    }
    class B extends A {}
    $a = new A();
    echo $a->getKey().'</br>';
    $a->plus();
    echo $a->getKey().'</br>';
    $b = new B();
    echo $b->getKey().'</br>';

выдал

0
1
1

Вот еще код

<?php 
    class A{
        protected static $key=0;
        public function plus(){
            ++self::$key;
        }
        public function getKey(){
            return self::$key;
        }
    }
    class B extends A {}
    $a = new A();
    echo $a->getKey().'</br>';
    $b = new B();
    $a->plus();
    echo $a->getKey().'</br>';
    echo $b->getKey().'</br>';

выдал

0
1
1

в итоге любое изменение статического свойства в любом наследнике меняет автоматически статическое свойство во ВСЕХ экземплярах - наследниках. Это ж альтернатива глобальным переменным или я чего то не понимаю и почему то об этом в учебниках не пишут.

на основе слов @perfect

поставил эксперимент

<?php 
    class A{
        protected static $key=0;
        public function plus(){
            ++self::$key;
        }
        public function getKey(){
            return self::$key;
        }
    }
    class B extends A {}
    class C extends A {}
    $b = new B();
    $c = new C();
    $b->plus();
    echo $c->getKey().'</br>';

выдал

1

в итоге у них глобальная видимость - где бы экземпляры классов не находились

Но это еще не все, как показа практика @chernomyrdin обращаясь к одной и той же статической переменной - можно обращаться к различным участкам оперативной памяти. В итоге "в одной и той же переменной" могут храниться разные значения

<?php 
    class A {
        protected static $key=0;
        public function getGlobalKey(){
            return self::$key;
        }
        //применяем позднее статическое связывание
        public function getCurrentKey(){
            return static::$key;
        }
        public function plusGlobalKey(){
            ++self::$key;
        }
        //применяем позднее статическое связывание
        public function plusCurrentKey(){
            ++static::$key;
        }
    }
    class B extends A{
        protected static $key=0;
    }
    class C extends B{}
    $a = new A();
    $a->plusGlobalKey();
    $b = new B();
    echo $a->getCurrentKey().'<br/>';
    echo $b->getCurrentKey().'<br/>';
    echo $b->getGlobalKey().'<br/>';
    $a->plusGlobalKey();
    echo '<hr/>';
    echo $a->getCurrentKey().'<br/>';
    echo $b->getCurrentKey().'<br/>';
    echo $b->getGlobalKey().'<br/>';
    $b->plusCurrentKey();
    echo '<hr/>';
    echo $a->getCurrentKey().'<br/>';
    echo $b->getCurrentKey().'<br/>';
    echo $b->getGlobalKey().'<br/>';
    echo '<hr/>';
    $c = new C();
    echo $c->getCurrentKey().'<br/>';
    echo $c->getGlobalKey().'<br/>';

выводит

1
0
1
-----------------
2
0
2
-----------------
2
1
2
-----------------
1
2

Резюме: @perfect - объяснил почему так происходит

@chernomyrdin - подтолкнул к теме позднего статического связывания - в последнем примере я как раз понял как оно работает

Answer 1

Важно понять, что статические свойства общие для всех экземпляров класса и существуют в единичном виде (такие поля хранит сам класс). Каждое изменение каким либо экземпляром класса статического свойства отражается на всех остальных экземплярах.

В вашем случае вы один раз выполнили функцию $a->plus(); и с нуля у вас получилась единица в обоих экземплярах.

Что бы вы достаточно смогли разобраться я нарисовал картинку объясняющую принцип хранения статистических переменных внутри памяти.

Область видимости статических переменных ограничена самим классом для защиты от внешнего изменения (в отличие от глобальных переменных) и используется для использования потомками только этого класса (например для обмена какой либо информацией)

Answer 2

Со статиками в PHP все сложно, начиная с того как к ним обращатся self::$key и static::$key причем поведение различное в 5.x и 7.0

Потом вот пример для размышления:

class A {
    public function inc () {
        static $value = 0;
        return get_called_class() . '::' . ++$value;
    }
}
class B extends A {}
$a = new A;
echo $a->inc(), "\n";
$b = new B;
echo $b->inc(), "\n";
echo $a->inc(), "\n";
echo $b->inc(), "\n";
$c = new A;
echo $c->inc(), "\n";
echo $c->inc(), "\n";
echo $a->inc(), "\n";

Результат работы:

A::1
B::1
A::2
B::2
A::3
A::4
A::5
READ ALSO
Не работает cron | CentOs 7 | Yii2

Не работает cron | CentOs 7 | Yii2

Почему не выполняются консольные команды cron?

335
Добавление в текущую URL-строку из action формы

Добавление в текущую URL-строку из action формы

К примеру текущий url у меня такой:

228
Настройка 404 ошибки в php

Настройка 404 ошибки в php

Сейчас на сайте, если происходит запрос к несуществующей статье или разделу текстом вывозится, что такой статьи или раздела не существует,...

359