Перейти к содержимому
Поиск
Php Разработка

PHP: полный мануал с примерами, функциями и ООП

Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Александр НекрасовИзменено:
Практический мануал PHP: от переменных и функций к объектной модели интернет-магазина
PHP 8.5.11149 глав4458 карточек справочника
Дерево руководства

Глава 10 · С нуля → практика

Область видимости: аргументы, global и состояние

Почему функция не видит соседнюю переменную, где оправдан global и как не смешать состояние разных задач.

Местные значения функции: подготовить подпись, сохранив исходную цену

В каталоге цена товара 150 рублей. Для оформления доставки нужно получить 200, сохранив исходную цену 150 для карточки. Функция получает значение через аргумент и работает со своим местным параметром. Одинаковое написание переменной внутри и снаружи не связывает их автоматически. Сначала изучены вызов, параметр и return.

Две области, два разных назначения значения
  1. Снаружи $priceRubles = 150 — цена каталога.
  2. addDelivery($priceRubles, 50): местный $priceRubles получает 150.
  3. Внутри параметр увеличивается до 200.
  4. return отдаёт 200 в наружную $payable.
  5. Внешняя $priceRubles по-прежнему 150.
Местный расчёт возвращает новый итогСамостоятельный пример
<?php
function addDelivery($priceRubles, $deliveryRubles)
{
    $priceRubles = $priceRubles + $deliveryRubles;
    return $priceRubles;
}
$priceRubles = 150;
$payable = addDelivery($priceRubles, 50);
echo 'Цена в каталоге: ', $priceRubles, ' руб.', "\n";
echo 'К оплате с доставкой: ', $payable, ' руб.', "\n";
Ожидаемый результат
Цена в каталоге: 150 руб.
К оплате с доставкой: 200 руб.

Присваивание внутри функции изменило местный параметр. Внешняя payable получила возвращённые 200. Местная переменная не обязана называться так же, как внешняя: соответствие создают аргументы, а не совпадение имён.

Функция не видит обычную внешнюю переменную лишь потому, что её объявление написано ниже присваивания. Условие if и цикл foreach, напротив, сами по себе не создают такой отдельной области. Следующий пример проверяет место создания подписи, пока не вводя global.

Подпись, присвоенная в условии, доступна после негоСамостоятельный пример
<?php
$stock = 2;
$caption = 'Нет в наличии';
if ($stock > 0) {
    $caption = 'В наличии: ' . $stock . ' уп.';
}
echo $caption, "\n";
Ожидаемый результат
В наличии: 2 уп.

Присваивание внутри if меняет ту же caption из текущей области. Исходная подпись существует до условия, поэтому при stock = 0 тоже будет что вывести. Это отличается от собственной местной переменной функции.

global: явная связь с состоянием одного выполнения

В старом обработчике несколько действий отмечают подготовленные документы общим счётчиком. Конструкция global $preparedCount; связывает местное имя с одноимённой переменной глобальной области. После неё изменение действительно видно снаружи. Эта функция выполняет побочное действие и не возвращает готовую подпись.

Увидеть изменение общего состояния после двух вызововСамостоятельный пример
<?php
$preparedCount = 0;
function markPreparedDocument(): void
{
    global $preparedCount;
    $preparedCount = $preparedCount + 1;
}
markPreparedDocument();
markPreparedDocument();
echo 'Подготовлено документов: ', $preparedCount, "\n";
Ожидаемый результат
Подготовлено документов: 2

Первый вызов изменил глобальное число 0 → 1, второй 1 → 2. : void сообщает об отсутствии полезного результата; внешняя программа читает изменённый счётчик отдельно. Пример только отмечает подготовку, а не создаёт файлы документов.

У этого решения скрытая зависимость от имени preparedCount и общего состояния. Для двух независимых наборов удобнее явный параметр и возвращённое значение либо отдельный объект состояния после изучения ООП. global не разделяет память между всеми посетителями сайта и не сохраняет число в базе. Ниже подробно разобраны $GLOBALS, include, static и ссылочные крайние случаи.

Граница функции — граница имен

Наглядная модель

У каждой функции своё рабочее место

Два магазина считают цены с разными настройками. Передача аргументов позволяет выполнить оба расчёта рядом, не смешав данные.

  • Расчёт для магазина А

    Вызов получает цену 100 и ставку 10%.

    • Локальные переменные

      Параметры принадлежат этому вызову функции.

  • Расчёт для магазина Б

    Другой вызов получает цену 100 и ставку 20%.

    • Свои локальные переменные

      Настройки А не нужно перезаписывать ради магазина Б.

Глобальная переменная — общая точка доступа за пределами функции. global явно подключает её внутри функции, но создаёт зависимость от общего состояния. В главе разобрано, где такой доступ встречается и почему параметры часто проще проверять.

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

Вне функций переменная относится к глобальной области текущего выполнения. Внутри функции есть собственная локальная область: одноименное $price в функции не обязано быть ценой из вызывающего кода. Блоки if и foreach сами по себе не создают отдельной области переменных. После цикла переменная элемента остается определенной, а после foreach по ссылке может оставаться привязанной к массиву. Файл include наследует область того места, где его подключили; отдельный файл не равен изоляции.

Явная передача зависимости
  1. Контроллер получает настройки магазина
  2. Передает ставку аргументом
  3. Функция рассчитывает результат
  4. Контроллер решает, куда его вывести
Получить две цены из одной функции с явными настройкамиСамостоятельный пример
<?php
function grossPrice(int $netKopecks, int $taxPercent): int {
    $extraKopecks = intdiv($netKopecks * $taxPercent, 100);
    return $netKopecks + $extraKopecks;
}
$firstShop = grossPrice(10000, 20);
$secondShop = grossPrice(10000, 0);
echo 'Магазин A, итог: ', $firstShop, ' коп.', "\n";
echo 'Магазин B, итог: ', $secondShop, ' коп.', "\n";
echo 'Разница: ', $firstShop - $secondShop, ' коп.', "\n";
Ожидаемый результат
Магазин A, итог: 12000 коп.
Магазин B, итог: 10000 коп.
Разница: 2000 коп.

Первый вызов получает местные netKopecks=10000 и taxPercent=20; intdiv возвращает 2000, затем return — 12000 в firstShop. Второй вызов получает собственный taxPercent=0 и возвращает 10000 в secondShop. Настройки первого не протекают во второй. Оба готовых результата используются для подписей и разницы 2000. Это учебная формула процентов; реальные налоги и округление задаются условиями задачи, а не самой областью видимости.

Где global действительно встречается

Разберите вложенный вызов в конце примера справа налево по зависимостям: сначала legacyCurrency читает настройки и возвращает строку RUB; затем priceLabel получает 15000 и эту строку в своих параметрах; intdiv(15000,100) даёт 150, конкатенация формирует «150 RUB», return передаёт её внешнему echo. Такой формат допускает только целые рубли: остаток копеек эта учебная функция не показывает.

В процедурном приложении или WordPress-плагине global бывает частью уже существующего API: например, $wpdb предоставляет объект доступа к базе. Адаптер к такому окружению может прочитать глобальную зависимость и передать ее дальше обычным аргументом или в конструктор. Это осознанная граница совместимости. Делать глобальными корзину, текущего покупателя и промежуточные суммы ради экономии параметров неудобно: порядок вызовов начинает менять результат, а тесты вынуждены восстанавливать скрытое состояние.

Адаптер к процедурным настройкамСамостоятельный пример
<?php
declare(strict_types=1);

$legacyShopSettings = ['currency' => 'RUB'];
function legacyCurrency(): string
{
    global $legacyShopSettings;
    $currency = $legacyShopSettings['currency'] ?? null;
    if (!is_string($currency)) {
        throw new RuntimeException('Не настроена валюта');
    }

    return $currency;
}
function priceLabel(int $kopecks, string $currency): string
{
    return intdiv($kopecks, 100) . ' ' . $currency;
}
echo priceLabel(15000, legacyCurrency()), "\n";
Ожидаемый результат
150 RUB

Только адаптер знает имя глобальной переменной. Бизнес-функция получает валюту явно. В реальном WordPress глобальный объект берут после загрузки WordPress; этот самостоятельный пример моделирует зависимость без доступа к сайту.

$GLOBALS дает доступ к глобальной таблице по имени, а global связывает локальное имя с глобальной переменной. Это не механизм постоянного хранения между запросами и не способ сделать переменную видимой во всех функциях разом. Суперглобальные $_GET, $_POST, $_SERVER доступны без global, но их содержимое все равно следует принять и проверить на границе приложения. Не передавайте весь $_REQUEST глубоко в расчет заказа.

Локальная static: память между вызовами

Дать последовательные номера строкам локального отчётаСамостоятельный пример
<?php
function nextLocalNumber(): int {
    static $number = 0;
    $number += 1;
    return $number;
}
$firstLine = nextLocalNumber();
echo $firstLine, '. Проверен адрес', "\n";
$secondLine = nextLocalNumber();
echo $secondLine, '. Подготовлена упаковка', "\n";
Ожидаемый результат
1. Проверен адрес
2. Подготовлена упаковка

При первом выполнении инициализируется местный number=0, затем +=1 даёт 1 и return передаёт его в firstLine. Второй вызов продолжает с сохранённого 1 и возвращает 2 в secondLine. Переменная number остаётся внутри функции; внешний код получает только числа. Отчёт здесь учебный: программа отмечает заданные сообщения, а не проверяет реальный адрес. Новый самостоятельный запуск начнёт нумерацию заново, поэтому это не общий ID заказов.

Кеширование через static допустимо, когда ключ учитывает все входы и понятно время жизни. Если в длинном воркере хранить там «текущего клиента», следующая задача может получить старые данные. Лучше хранить состояние в объекте с явным жизненным циклом или передавать контекст задачи. Константа подходит для неизменного правила, конфигурационный объект — для настроек среды; ни тот ни другой не должен прятать изменяемую корзину.

Выбор и проверка

НужноПодход
Передать данные расчетаПараметр и return
Настроить сервис один разКонструктор и внедрение зависимости
Захватить ставку для callbackЗамыкание use или fn
Поддержать старое APIУзкий адаптер к global
Сохранить данные между HTTP-запросамиСессия/база/кеш с явным ключом

Попробуйте сами. Две функции печатают цены, используя global $currency. Как проверить RUB и EUR без влияния одного теста на другой?

Разбор решения

Вынесите форматирование в priceLabel($amount, $currency). Сохраните global только в адаптере старого интерфейса. Два теста вызывают чистую функцию с разными аргументами и не меняют общую переменную.

Источники и обсуждения

Код и руководство с собой

Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.

Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.

Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.