Область видимости
Автомат с кофе — закрытый ящик. Снаружи не видно, что происходит у него внутри. А сам он не заглядывает к вам в карманы: он работает только с тем, что вы опустили в прорезь.
Функция в PHP устроена так же. Посмотрим, что будет, если функция попробует взять переменную из файла:
<?php
$discount = 5;
function finalPrice($price)
{
return $price - $discount; // ✗
}
echo finalPrice(100), "\n";Warning: Undefined variable $discountВнутри finalPrice переменной $discount нет, хотя в файле она стоит выше. Это предупреждение, а не остановка: PHP подставляет вместо неё null, в арифметике null считается нулём, и программа печатает 100. Скидка молча потерялась.
Своя область у каждой функции
Область видимости — это набор переменных, которые видит участок кода. У файла своя область, у каждой функции — своя. Внутри функции видны только её параметры и переменные, которые она создала сама. Такие переменные называют локальными.
Самое неожиданное — одинаковые имена. Переменная с тем же именем внутри функции — это другая переменная, и запись в неё не трогает переменную файла.
Нажимайте «Следующий шаг» и следите за двумя переменными $total: одна живёт в рамке {main}, другая — в рамке add.
1<?php2 3$total = 10;4 5function add(int $x): int6{7 $total = $x + 1;8 return $total;9}10 11$result = add(5);12echo $total, ' ', $result, "\n";
В файле появляется переменная $total со значением 10.
Программа напечатала 10 6. Запись $total = $x + 1 внутри add создала новую локальную переменную, и $total файла осталась 10. Когда вызов закончился, переменные функции исчезли вместе с её рамкой.
Этот вопрос часто задают на собеседовании: почему функция не видит переменную, объявленную снаружи? Ответ: у тела функции своя область видимости. В некоторых языках, например в JavaScript, функция видит переменные вокруг себя, а в PHP — нет.
Как передать значение внутрь
Параметр
Значение снаружи передают параметром — так по объявлению функции видно, что ей нужно:
<?php
$discount = 5;
function finalPrice($price, $discount)
{
return $price - $discount;
}
echo finalPrice(100, $discount), "\n"; // 95Внутри функции $discount — параметр, а не переменная файла. Имена совпадают, но связывает их только вызов: finalPrice(100, $discount) копирует значение 5 в параметр.
global
Можно написать в начале тела global $discount; — тогда имя $discount внутри функции будет связано с переменной файла. Так делают редко: по объявлению функции не видно, что она зависит от переменной снаружи, а изменить эту переменную может любая функция.
Из переменных без передачи внутри функции видны только суперглобальные массивы, например $_GET. PHP создаёт их сам, и они доступны в любом месте программы. Константы из const и define тоже видны везде.
static: память между вызовами
Обычно автомат ничего не помнит о прошлом покупателе: каждый вызов начинается с чистой рамки. Исключение — переменная со словом static: это собственный счётчик автомата.
<?php
function nextTicket()
{
static $number = 100;
$number++;
return 'A' . $number;
}
echo nextTicket(), ' ', nextTicket(), "\n"; // A101 A102
echo nextTicket(), "\n"; // A103Разберём по шагам:
static $number = 100;выполняется один раз — при первом вызове.- Каждый вызов увеличивает
$numberи возвращает номер талона. - Следующий вызов видит не
100, а то, что осталось с прошлого раза.
Снаружи $number по-прежнему не видна: static продлевает жизнь переменной, но не открывает её файлу.
Частая ошибка
Ждут, что переменная, созданная внутри функции, будет видна после вызова:
<?php
function setup()
{
$limit = 10;
}
setup();
echo $limit, "\n"; // ✗Warning: Undefined variable $limitПеременная $limit жила в рамке вызова setup() и исчезла вместе с ней. Снаружи PHP ищет $limit среди переменных файла, не находит её и печатает пустую строку. Исправление — вернуть значение через return 10; и сохранить его: $limit = setup();.
Главное
- У каждой функции своя область видимости: внутри видны только параметры и локальные переменные.
- Переменная файла внутри функции не видна: чтение даёт
Warningиnull, а одинаковое имя внутри — другая переменная. - Значение передают внутрь параметром;
globalсвязывает имя с переменной файла, но прячет зависимость. - Переменная
staticполучает начальное значение один раз и хранит его между вызовами.