Лекция
Привет, Вы узнаете о том , что такое статические переменные, Разберем основные их виды и особенности использования. Еще будет много подробных примеров и описаний. Для того чтобы лучше понимать что такое статические переменные, статические методы, позднее статическое связывание, особенности ооп, статическое свойство , настоятельно рекомендую прочитать все из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend) .
что значит слово «static» в PHP и зачем оно применяется?
Ключевое слово static имеет в PHP четыре различных значения. Разберем их в хронологическом порядке, как они появлялись в языке.
function foo() { $a = 0; echo $a; $a = $a + 1; } foo(); // 0 foo(); // 0 foo(); // 0
В PHP переменные локальны. Это значит, что переменная, определенная и получившая значение внутри функции (метода), существует только во время выполнения этой функции (метода). При выходе из метода локальная переменная уничтожается, а при повторном входе — создается заново. В коде выше такой локальной переменной является переменная $a — она существует только внутри функции foo() и каждый раз при вызове этой функции создается заново. Инкремент переменной в этом коде бессмысленен, поскольку на следующей же строчке кода функция закончит свою работу и значение переменной будет потеряно. Сколько бы раз мы не вызвали функцию foo(), она всегда будет выводить 0…
Однако все меняется, если мы перед присваиванием поставим ключевое слово static:
function foo() { static $a = 0; echo $a; $a = $a + 1; } foo(); // 0 foo(); // 1 foo(); // 2
Ключевое слово static, написанное перед присваиванием значения локальной переменной, приводит к следующим эффектам:
Такое использование слова static называется статическая локальная переменная.
Подводные камни статических переменных
Разумеется, как всегда в PHP, не обходится без «подводных камней».
Камень первый — статической переменной присваивать можно только константы или константные выражения. Вот такой код:
static $a = bar();
с неизбежностью приведет к ошибке парсера. К счастью, начиная с версии 5.6 стало допустимым присвоение не только констант, но и константных выражений (например — «1+2» или "[1, 2, 3]"), то есть таких выражений, которые не зависят от другого кода и могут быть вычислены на этапе компиляции
Камень второй — методы существуют в единственном экземпляре.
Тут все чуть сложнее. Для понимания сути приведу код:
class A { public function foo() { static $x = 0; echo ++$x; } } $a1 = new A; $a2 = new A; $a1->foo(); // 1 $a2->foo(); // 2 $a1->foo(); // 3 $a2->foo(); // 4
Вопреки интуитивному ожиданию «разные объекты — разные методы» мы наглядно видим на этом примере, что динамические методы в PHP «не размножаются». Даже если у нас будет сто объектов этого класса, метод будет существовать лишь в одном экземпляре, просто при каждом вызове в него будет пробрасываться разный $this.
Такое поведение может быть неожиданным для неподготовленного к нему разработчика и послужить источником ошибок. Нужно заметить, что наследование класса (и метода) приводит к тому, что все-таки создается новый метод:
class A { public function foo() { static $x = 0; echo ++$x; } } class B extends A { } $a1 = new A; $b1 = new B; $a1->foo(); // 1 $b1->foo(); // 1 $a1->foo(); // 2 $b1->foo(); // 2
Вывод: динамические методы в PHP существуют в контексте классов, а не объектов. И только лишь в рантайме происходит подстановка "$this = текущий_объект"
class A { public static $x = 'foo'; public static function test() { return 42; } } echo A::$x; // 'foo' echo A::test(); // 42
Для доступа к таким свойствам и методам используются конструкции с двойным двоеточием («Paamayim Nekudotayim»), такие как ИМЯ_КЛАССА::$имяПеременной и ИМЯ_КЛАССА:: имяМетода().
Само собой разумеется, что у статических свойств и статических методов есть свои особенности и свои «подводные камни», которые нужно знать.
Особенность первая, банальная — нет $this. Об этом говорит сайт https://intellect.icu . Собственно это проистекает из самого определения статического метода — поскольку он связан с классом, а не объектом, в нем недоступна псевдопеременная $this, указывающая в динамических методах на текущий объект. Что совершенно логично.
Однако, нужно знать, что в отличие от других языков, PHP не определяет ситуацию «в статическом методе написано $this» на этапе парсинга или компиляции. Подобная ошибка может возникнуть только в рантайме, если вы попытаетесь выполнить код с $this внутри статического метода.
Код типа такого:
class A { public $id = 42; static public function foo() { echo $this->id; } }
не приведет ни к каким ошибкам, до тех пор, пока вы не попытаетесь использовать метод foo() неподобающим образом:
$a = new A; $a->foo();
(и сразу получите «Fatal error: Using $this when not in object context»)
Особенность вторая — static не аксиома!
class A { static public function foo() { echo 42; } } $a = new A; $a->foo();
Вот так, да. Статический метод, если он не содержит в коде $this, вполне можно вызывать в динамическом контексте, как метод объекта. Это не является ошибкой в PHP.
Обратное не совсем верно:
class A { public function foo() { echo 42; } } A::foo();
Динамический метод, не использующий $this, можно выполнять в статическом контексте. Однако вы получите предупреждение «Non-static method A::foo() should not be called statically» уровня E_STRICT. Тут решать вам — или строго следовать стандартам кода, или подавлять предупреждения. Первое, разумеется, предпочтительнее.
И кстати, все написанное выше относится только к методам. Использование статического свойства через "->" невозможно и ведет к фатальной ошибке.
Разработчики языка PHP не остановились на двух значениях ключевого слова «static» и в версии 5.3 добавили еще одну «фичу» языка, которая реализована тем же самым словом! Она называется «позднее статическое связывание» или LSB (Late Static Binding).
Понять суть LSB проще всего на несложных примерах:
class Model { public static $table = 'table'; public static function getTable() { return self::$table; } } echo Model::getTable(); // 'table'
Ключевое слово self в PHP всегда значит «имя класса, где это слово написано». В данном случае self заменяется на класс Model, а self::$table — на Model::$table.
Такая языковая возможность называется «ранним статическим связыванием». Почему ранним? Потому что связывание self и конкретного имени класса происходит не в рантайме, а на более ранних этапах — парсинга и компиляции кода. Ну а «статическое» — потому что речь идет о статических свойствах и методах.
Немного изменим наш код:
class Model { public static $table = 'table'; public static function getTable() { return self::$table; } } class User extends Model { public static $table = 'users'; } echo User::getTable(); // 'table'
Теперь вы понимаете, почему PHP ведет себя в этой ситуации неинтуитивно. self был связан с классом Model тогда, когда о классе User еще ничего не было известно, поэтому и указывает на Model.
Как быть?
Для решения этой дилеммы был придуман механизм связывания «позднего», на этапе рантайма. Работает он очень просто — достаточно вместо слова «self» написать «static» и связь будет установлена с тем классом, который вызывает данный код, а не с тем, где он написан:
class Model { public static $table = 'table'; public static function getTable() { return static::$table; } } class User extends Model { public static $table = 'users'; } echo User::getTable(); // 'users'
Это и есть загадочное «позднее статическое связывание».
Нужно отметить, что для большего удобства в PHP кроме слова «static» есть еще специальная функция get_called_class(), которая сообщит вам — в контексте какого класса в данный момент работает ваш код.
Подобно методам, при определении в контексте класса анонимные функции не связаны с содержащим их классом и не имеют доступа через $this
.
Статические анонимные функции не обладают такой широтой вариантов использования, как обычные анонимные функции. Стоит отметить, что статические анонимные функции немного улучшают производительность и могут использоваться в любых экземплярах при отсутствии необходимости привязки содержащего класса к анонимной функции.
Каждый раз, когда мы создаем (создаем) новый объект, мы можем отслеживать это через статическое свойство. Таким образом, мы можем подсчитать количество объектов, созданных для данного класса.
На данный момент, PHP не имеет встроенной функции, которая подсчитывает количество объектов в классе, поэтому можно создать это самим.
Мы создаем статическое свойство (поскольку оно не привязано к объекту, а к классу), и мы помещаем его внутри конструктора. Поскольку конструктор вызывается каждый раз, когда создается экземпляр объекта, мы добавляем приращение статического значения, сохраняющего счет на 1 при каждом экземпляре объекта, мы можем отслеживать количество объектов в классе.
Итак, в приведенном ниже PHP-коде мы создали программу, которая подсчитывает количество объектов, созданных для класса в PHP.
class animals { public static $count=0; public function __construct($type, $year) { $this->type= $type; $this->year= $year; animals::$count++; return true; } } $animal1= new animals("Dog", 2018); $animal2= new animals("Cat", 2012); $animal3= new animals("Mouse", 2010); echo "The number of objects in the class is " . animals::$count; ?>
Таким образом, в этом коде мы создаем класс с именем animals.
Мы объявляем публичное статическое свойство с именем $count и устанавливаем его равным 0. Эта переменная будет использоваться для подсчета количества объектов, созданных в классе.
Затем мы создаем конструктор для класса. Так как это класс, представляющий животных, каждый созданный объект является объектом животного (представляет собой животное). Мы хотим передать в animals свойства Клички и года рождения.
Поэтому в конструкторе мы передаем аргументы $type и $year, представляющие Кличку и год животного.
Затем мы используем ключевое слово $this, чтобы присвоить значение типа и года переменным $type и $year.
Затем мы используем оператор increment для увеличения свойства animals::$count.
Поскольку конструктор вызывается каждый раз, когда создается объект, мы можем использовать этот факт, чтобы отслеживать, сколько объектов создано. Первоначально переменная animals::$count равна 0. Однако с каждым экземпляром, который создается, счет увеличивается на 1. Таким образом, мы можем узнать, сколько объектов было создано.
Поскольку мы создали 3 животных, в конце этой программы вы увидите, что в программе выведется, что создано 3 объекта.
Вы могли бы сделать эту программу немного более сложной.
Например, что, если объект уничтожен? Что делать, если мы удалим один или несколько объектов после их создания?
В этом случае вам также нужно будет создать функцию деструктора для класса. Когда объект уничтожается (если вы удаляете объект), вы помещаете его в функцию деструктора, оператора декремента для переменной animals::$count. Поэтому, если объект уничтожен, счетчик уменьшается на 1. Таким образом, вы можете отслеживать, сколько объектов в настоящее время существует для класса.
Итак, ниже приведен код, который отслеживает все существующие в настоящее время объекты в классе. Если объект создан, счетчик увеличивается на 1. Если объект уничтожен, счетчик уменьшается на 1.
class animals
{ public static $count=0; public function __construct($type, $year) { $this->type= $type; $this->year= $year; animals::$count++; return true; } public function __destruct() { animals::$count--; } } $animal1= new animals("Mouse", 2011); $animal2= new animals("Dog", 2022); unset($animal2); $animal3= new animals("Dug", 2033); echo "The number of objects in the class is " . animals::$count;
Таким образом, весь код в основном такой же, но теперь у нас есть деструктор класса, и мы намеренно удаляем объект $animal2. Внутри деструктора мы имеем переменную animals::$count, уменьшающуюся на 1 каждый раз, когда вызывается деструктор. И функция деструктора вызывается, когда мы удаляем объект с помощью функции unset () PHP. Поэтому всякий раз, когда мы удаляем объект, счетчик уменьшается на 1.
Итак, теперь, когда мы запускаем наш код, теперь, когда мы удалили один из объектов, счет будет равен 2.
Вместо указания названия класса можно использоать ключевое слово self то есть вместо animals::$count (только)внутри класса можно исползовать self::$count.
Поэтому использование статической переменной - очень эффективный и простой способ отслеживать количество объектов в классе.
Поскольку статическая переменная не привязана к объекту и вместо этого привязана к классу, она не зависит от какого-либо объекта в классе. Поэтому он имеет внешний вид, так сказать, и может отслеживать все объекты в классе.
Таким образом, вы можете отслеживать количество объектов в классе в PHP.
так же применяются статиеские методы или свойства когда ненужна иницаализация объекта и переменные метода не зависят от свойств объекта
Анализ данных, представленных в статье про статические переменные, подтверждает эффективность применения современных технологий для обеспечения инновационного развития и улучшения качества жизни в различных сферах. Надеюсь, что теперь ты понял что такое статические переменные, статические методы, позднее статическое связывание, особенности ооп, статическое свойство и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)
Комментарии
Оставить комментарий
Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)
Термины: Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)