- PVSM.RU - https://www.pvsm.ru -
Дисклеймер: данная статья не явит вам какого то откровения и не откроет третий глаз, но позволит разобраться в не очень очевидном вопросе более детально. Мне по крайней мере при ее написании она в этом помогла. Если вы матерый волк в php то можете не читать, опытным человекам думаю не повредит пробежать глазами, освежить так сказать в памяти, остальным будет норм.
Итак...
Статические переменные, в php это особый вид переменных, которые объявляются при помощи ключевого слова static.
static $foo = 3;
От обычных переменных они отличаются тем что (далее в статье эти пункты будут рассмотрены более подробно):
Теперь по порядку.
Это значит что в статическую переменную не может быть присвоен результат работы какой-либо функции или метода, или вообще что-либо что еще не известно на этапе компиляции. То есть вот такое объявление не сработает
static $var = foo();
а вот так вполне возможно
static $var = 'some str';
static $varInt = 3 + 5;
Постараюсь объяснить что тут я имел в виду. Возможно допущу какие-то неточности в терминологии, но суть постараюсь передать как можно точнее. Сравним с обычной переменной. Если внутри функции объявить переменную, то она по умолчанию является локальной переменной, то есть она объявлена в локальной области видимости (области видимости этой функции). В этом случае контекстом данной функции будет локальная область видимости. После того как функция отработала и вернула результат, ее область видимости или ее контекст, со всеми переменными внутри нее будет уничтожена.
Если же мы внутри функции объявляем статическую переменную, то она также объявляется в локальной области видимости, но ее контекстом будет не локальная область видимости, а сама функция.
(Далее самый трудный момент для объяснения, передаю только суть, без подробностей, как объявляются функции в php сколько им выделяется памяти и что в этой памяти лежит). Получается так, при вызове функции, для нее интерпретатором создается локальная область видимости именно в ней объявляются все локальные переменные и ф-ции, и к ней как к своему контексту они и привязаны. Объявляя же переменную в локальной области видимости с помощью static, этой переменной в качестве контекста назначается сама функция, и эта переменная будет существовать до тех пор пока существует сама функция. Это нечто похожее на js, когда функция является объектом, в который можно присваивать произвольные свойства и методы. Тут так же только функция в php является объектом не для php, а для более низкого ЯП.
function echoStaticVar()
{
static $var = 0;
$var++;
var_dump($var);
};
echoStaticVar(); //1
echoStaticVar(); //2
echoStaticVar(); //3
Видно что после прекращения работы функции сборщик не уничтожает переменную $var как это было бы с обычной переменной.
А вот пример который наглядно покажет что статическая переменная принадлежит функции (или хранится в функции, или ее контекстом является функция уж извините не знаю как это правильно назвать).
$one = function ($i)
{
static $var = 0;
$var += $i;
var_dump($var);
};
$two = $one;
$one(1); //1
$one(5); //6
$one(5); //11
$two(5); //16
$two(5); //21
Все работает, как и ожидается, потому что при присвоении $two = $one; не копируется сама функция, а просто обе эти переменные будут ссылаться на одну и ту же область памяти. Соответственно и статическая переменная $var будет одна и для $one и для $two
Немного поменяем пример, а именно не присвоим, а клонируем
//вместо
$two = $one;
//клонируем
$two = clone($one);
$one = function ($i)
{
static $var = 0;
$var += $i;
var_dump($var);
};
$two = clone($one);
$one(1); //1
$one(5); //6
$one(5); //11
$two(5); //5
$two(5); //10
Теперь получилось что $one и $two ссылаются не на одну и ту же функцию с одной статической переменной $var, а на две разные функции, лежащие в разный областях памяти, и имеющие каждая по своей статической переменной $var. Это не особо очевидный момент, по этому на нем можно споткнуться, если вы конечно вообще пишите код в процедурном стиле, что уже наверное считается дурным тоном, но это не точно).
Что можно с этим сделать — это классический пример счетчика вызова функции.
Но в связи с распространением ООП в таком виде статические переменные встречаются редко, так как в основном приходится оперировать классами и методами (о реализации static в них напишу отдельную статью)
Это значит что если статическая переменная уже объявлена, и ей присвоено значение, то последующие присвоения не перезапишут уже присвоенное значение, а вернут существующее.
function staticVar($i)
{
static $var = 0;
$var += $i;
var_dump($var);
};
staticVar(1); //1
staticVar(5); //6
staticVar(5); //11
Видно, что если бы в функции staticVar статической переменной $var каждый раз бы переприсваивалось значение то мы бы всегда получали в результате 1. Но так как при повторном присвоении она не перезаписывается, мы получаем то что мы получаем.
Правда тут есть одно но, которое может все испортить. В рамках одной функции (точнее при первом вызове функции), такую переменную можно перезаписать сколько угодно раз (при последующих все будет работать как и заявлено). Мне это поведение показалось странным и забавным, особенно если поиграться с примерами.
function staticVar($i)
{
static $var = 0;
static $var = 5;
$var += $i;
var_dump($var);
};
staticVar(1); //6
staticVar(5); //11
staticVar(5); //16
Тут переменная $var в первом вызове функции staticVar в первой ее строке была присвоена, потом перезаписана во второй строке. Но уже в дальнейших вызовах ни в первой ни во второй строке она не была переприсвоена, а вернула то что уже было в предыдущем вызове
function staticVar($i)
{
static $var = 0; //присвоена
static $var = 5; //переприсвоена
$var += $i;
static $var = 0; //вернулось значение присвоенное ранее
var_dump($var);
};
staticVar(1); //1
staticVar(5); //6
staticVar(5); //11
Еще страннее при первом вызове staticVar в первой строке она была присвоена, потом во второй строке переприсвоена, затем с ней было произведено действие сложения, и уже после этого при попытки ее переприсвоить даже в рамках первого вызова функции она вернула уже лежащее в ней значение. Меня это довольно сильно позабавило.
Не вижу особого смысла объяснять этот пункт, тем более что из примеров все видно. Пока работает скрипт и пока существует функция для которой объявлена статическая переменная, эта переменная существует.
Как планируется — это первая статья по static, впереди еще ООП, статические поля, методы.
Ну конечно если это хоть кому-то будет интересно и жестко не заминусуется.
Автор: fm-00
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/php-2/330077
Ссылки в тексте:
[1] Источник: https://habr.com/ru/post/467489/?utm_source=habrahabr&utm_medium=rss&utm_campaign=467489
Нажмите здесь для печати.