Перейти к содержимому
Теория · Функции · урок 8 из 11

Область видимости

Автомат с кофе — закрытый ящик. Снаружи не видно, что происходит у него внутри. А сам он не заглядывает к вам в карманы: он работает только с тем, что вы опустили в прорезь.

Функция в PHP устроена так же. Посмотрим, что будет, если функция попробует взять переменную из файла:

PHP
<?php

$discount = 5;

function finalPrice($price)
{
    return $price - $discount; // ✗
}

echo finalPrice(100), "\n";
TEXT
Warning: Undefined variable $discount

Внутри finalPrice переменной $discount нет, хотя в файле она стоит выше. Это предупреждение, а не остановка: PHP подставляет вместо неё null, в арифметике null считается нулём, и программа печатает 100. Скидка молча потерялась.

Своя область у каждой функции

Область видимости — это набор переменных, которые видит участок кода. У файла своя область, у каждой функции — своя. Внутри функции видны только её параметры и переменные, которые она создала сама. Такие переменные называют локальными.

Самое неожиданное — одинаковые имена. Переменная с тем же именем внутри функции — это другая переменная, и запись в неё не трогает переменную файла.

Нажимайте «Следующий шаг» и следите за двумя переменными $total: одна живёт в рамке {main}, другая — в рамке add.

ВживуюДве переменные с именем $totalшаг 1 из 7 · рамок: 1

В файле появляется переменная $total со значением 10.

Рамка {main} — переменные файла, рамка add — переменные вызова

Программа напечатала 10 6. Запись $total = $x + 1 внутри add создала новую локальную переменную, и $total файла осталась 10. Когда вызов закончился, переменные функции исчезли вместе с её рамкой.

Этот вопрос часто задают на собеседовании: почему функция не видит переменную, объявленную снаружи? Ответ: у тела функции своя область видимости. В некоторых языках, например в JavaScript, функция видит переменные вокруг себя, а в PHP — нет.

Как передать значение внутрь

Параметр

Значение снаружи передают параметром — так по объявлению функции видно, что ей нужно:

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
<?php

function nextTicket()
{
    static $number = 100;
    $number++;
    return 'A' . $number;
}

echo nextTicket(), ' ', nextTicket(), "\n"; // A101 A102
echo nextTicket(), "\n"; // A103

Разберём по шагам:

  1. static $number = 100; выполняется один раз — при первом вызове.
  2. Каждый вызов увеличивает $number и возвращает номер талона.
  3. Следующий вызов видит не 100, а то, что осталось с прошлого раза.

Снаружи $number по-прежнему не видна: static продлевает жизнь переменной, но не открывает её файлу.

Частая ошибка

Ждут, что переменная, созданная внутри функции, будет видна после вызова:

PHP
<?php

function setup()
{
    $limit = 10;
}

setup();
echo $limit, "\n"; // ✗
TEXT
Warning: Undefined variable $limit

Переменная $limit жила в рамке вызова setup() и исчезла вместе с ней. Снаружи PHP ищет $limit среди переменных файла, не находит её и печатает пустую строку. Исправление — вернуть значение через return 10; и сохранить его: $limit = setup();.

Главное

  • У каждой функции своя область видимости: внутри видны только параметры и локальные переменные.
  • Переменная файла внутри функции не видна: чтение даёт Warning и null, а одинаковое имя внутри — другая переменная.
  • Значение передают внутрь параметром; global связывает имя с переменной файла, но прячет зависимость.
  • Переменная static получает начальное значение один раз и хранит его между вызовами.