---
title: 'Основи PHP та глобальні змінні: область видимості та суперглобальні змінні | DevSense'
description: 'Детальний посібник з областей видимості змінних у PHP (локальна, глобальна, статична) та всіх суперглобальних змінних. Дізнайтеся про найкращі практики, пастки безпеки та обмеження PHP 8.1+.'
faq:
    - { question: 'Яка різниця між локальною, глобальною та статичною областями видимості змінних у PHP?', answer: "Локальні змінні існують лише всередині функції, в якій вони оголошені. Глобальні змінні існують поза функціями і доступ до них здійснюється за допомогою ключового слова 'global' або масиву $GLOBALS. Статичні змінні існують локально, але зберігають своє значення між кількома викликами функції." }
    - { question: 'Чому перепризначення змінної $GLOBALS викликає помилку в PHP 8.1+?', answer: "Починаючи з PHP 8.1, двигун Zend Engine забороняє перепризначення масиву $GLOBALS (наприклад, заборонено $GLOBALS = []), щоб оптимізувати швидкість пошуку змінних та забезпечити внутрішню узгодженість. Ви все ще можете змінювати окремі ключі (наприклад, $GLOBALS['myVar'] = 'value')." }
    - { question: 'Як безпечно обробляти завантаження файлів за допомогою $_FILES у PHP?', answer: "Завжди перевіряйте статус завантаження за допомогою $_FILES['field']['error'], валідуйте розмір файлу та MIME-тип на сервері, перевіряйте файл за допомогою is_uploaded_file() та переміщуйте його у безпечну директорію за допомогою move_uploaded_file()." }
    - { question: 'Чому не рекомендується отримувати доступ до $_GET або $_POST напряму в сучасній розробці на PHP?', answer: "Прямий доступ до суперглобальних змінних прив'язує ваш код до глобального стану, що значно ускладнює юніт-тестування та імітацію (mocking) запитів. Це також обходить фільтрацію, збільшуючи ризик XSS та SQL-ін'єкцій. Замість цього використовуйте обгортку запиту (request wrapper)." }
published: '2026-06-07'
---
# PHP Basics: Variable Scopes and Superglobals

**Difficulty Level:** Junior  
**Target PHP Versions:** PHP 7.0+ (with features marked up to PHP 8.3+)

Уявіть, що ви впроваджуєте незначний рефакторинг коду, але ваше робоче середовище падає з фатальною помилкою виконання: `Fatal error: Cannot reassign $GLOBALS`. Або, можливо, ви створили просту контактну форму і згодом виявили, що зловмисник впровадив XSS-вектор безпосередньо через `$_POST`, перехопивши сесії адміністратора.

У PHP області видимості змінних та суперглобальні змінні є основою потоку даних. Проте вони залишаються частим джерелом забруднення областей видимості, витоків пам'яті та критичних вразливостей безпеки для розробників, які тільки знайомляться з цією мовою. Розуміння того, як змінні передаються між областями видимості та як поводяться суперглобальні змінні PHP — особливо в умовах суворих правил сучасних двигунів PHP — є важливим для написання безпечного, тестованого та надійного коду.

---

## Variable Scopes: Local, Global, and Static

Область видимості визначає видимість і життєвий цикл змінних у вашому коді. У PHP змінні не потрапляють автоматично у вкладені області видимості, якщо це не вказано явно.

### Local Scope
* **Point**: Змінні, оголошені всередині функції або методу класу, ізольовані від зовнішнього середовища.
* **Why it matters**: Локальна область видимості запобігає колізіям імен та неочікуваним змінам даних. Змінна з ім'ям `$user` всередині однієї функції не може випадково перезаписати змінну `$user`, визначену в іншому місці.
* **Example**:
  ```php
  // app/Services/CalculationService.php
  
  function calculateTotal(float $price, float $tax): float
  {
      $total = $price + ($price * $tax); // Local variable
      return $total;
  }
  
  // Accessing $total here will throw a Warning (Undefined variable $total)
  ```
* **Consequence**: Як тільки функція завершує роботу, її локальні змінні знищуються, а їхня пам'ять вивільняється. Будь-яка спроба отримати доступ до них із глобальної області видимості призведе до попередження про невизначену змінну.

### Global Scope
* **Point**: Змінні, визначені поза будь-якою функцією чи класом, належать до глобальної області видимості. Однак вони не є автоматично доступними всередині функцій.
* **Why it matters**: Глобальні змінні дозволяють спільно використовувати конфігурації або з'єднання з базою даних у різних файлах, але доступ до них всередині функцій вимагає явних ключових слів.
* **Example**:
  ```php
  // config/database.php
  
  $dbDsn = "mysql:host=127.0.0.1;dbname=app_db";
  
  function connect(): PDO
  {
      // Accessing global scope requires the 'global' keyword
      global $dbDsn; 
      
      return new PDO($dbDsn, "root", "secret");
  }
  ```
* **Consequence**: Використання ключового слова `global` створює приховані залежності. Це значно ускладнює юніт-тестування, оскільки засіб запуску тестів не може легко ізолювати або імітувати (mock) глобальні значення.

### Static Scope
* **Point**: Статична змінна оголошується всередині функції за допомогою ключового слова `static`. Вона існує лише в межах локальної області видимості цієї функції, але зберігає своє значення між наступними викликами цієї функції.
* **Why it matters**: Статичні змінні ідеально підходять для кешування складних обчислень, відстеження глибини рекурсії або створення простих ідентифікаторів послідовності без забруднення глобального простору імен.
* **Example**:
  ```php
  // app/Utils/SequenceGenerator.php
  
  function getNextSequenceId(): int
  {
      static $id = 0; // Initialized only on the first call
      $id++;
      return $id;
  }
  
  echo getNextSequenceId(); // 1
  echo getNextSequenceId(); // 2
  ```
  > [!NOTE]
  > **Примітка щодо версії PHP**: Починаючи з PHP 8.3+, статичні змінні можна ініціалізувати динамічними виразами (наприклад, викликаючи інші функції). До PHP 8.3 їх можна було ініціалізувати лише константними значеннями або літералами.
* **Consequence**: Змінна залишається в пам'яті протягом усього часу роботи поточного процесу PHP. Якщо ваш додаток працює під постійними середовищами виконання (такими як RoadRunner або FrankenPHP), статичні змінні зберігатимуть свій стан між різними HTTP-запитами. Це може призвести до витоку пам'яті або змішування даних користувачів, якщо їх не очищати.

---

## PHP Superglobals

Суперглобальні змінні — це вбудовані асоціативні масиви, які завжди доступні в усіх областях видимості протягом життєвого циклу скрипту. Вам не потрібно використовувати ключове слово `global` для доступу до них.

### 1. `$GLOBALS` (з обмеженнями на перепризначення в PHP 8.1+)
* **Point**: Асоціативний масив, який містить посилання на всі змінні, визначені наразі в глобальній області видимості скрипту.
* **Why it matters**: Він забезпечує програмний динамічний доступ до глобальної області видимості без використання оголошення `global $varName`.
* **Example**:
  ```php
  // app/Utils/DebugHelper.php
  
  $debugMode = true;
  
  function isDebugEnabled(): bool
  {
      // Directly check the global variable through the superglobal array
      return $GLOBALS['debugMode'] ?? false;
  }
  ```
* **Обмеження PHP 8.1+**:
  До версії PHP 8.1 масив `$GLOBALS` можна було перепризначати або передавати за посиланням. Починаючи з PHP 8.1+, перепризначення всього масиву `$GLOBALS` (наприклад, `$GLOBALS = [];` або `$GLOBALS =& $otherArray;`) заборонено і призводить до фатальної помилки на етапі компіляції або виконання. Це обмеження було впроваджено для оптимізації швидкості пошуку змінних у Zend Engine. Ви все ще можете змінювати окремі ключі:
  ```php
  // app/Utils/LegacyRunner.php
  
  // This throws a Compile Error in PHP 8.1+:
  // $GLOBALS = ['app_env' => 'production']; 
  
  // This is fully supported and correct:
  $GLOBALS['app_env'] = 'production'; 
  ```
* **Consequence**: Успадковані кодові бази, які очищали глобальний стан під час завершення юніт-тестів за допомогою `$GLOBALS = []`, мають бути переписані для скидання змінних по ключах.

### 2. `$_SERVER`
* **Point**: Містить заголовки, шляхи, розташування скриптів та змінні середовища веб-сервера.
* **Why it matters**: Необхідний для маршрутизації запитів, перевірки методів запиту (GET, POST) та валідації HTTP-заголовків.
* **Example**:
  ```php
  // public/index.php
  
  $requestUri = $_SERVER['REQUEST_URI'] ?? '/';
  $requestMethod = $_SERVER['REQUEST_METHOD'] ?? 'GET';
  $isHttps = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
  ```
* **Consequence**: Значення, що починаються з `HTTP_` (наприклад, `HTTP_USER_AGENT`, `HTTP_X_FORWARDED_FOR`), надходять безпосередньо від браузера клієнта. Їм ніколи не можна сліпо довіряти, оскільки їх легко підробити.

### 3. `$_GET`
* **Point**: Асоціативний масив змінних запиту, переданих скрипту через URL.
* **Why it matters**: Використовується для передачі нечутливих параметрів навігації, таких як номери сторінок (пагінація), фільтри та пошукові запити.
* **Example**:
  ```php
  // app/Controllers/SearchController.php
  
  // URL: /search.php?query=php&page=2
  $query = $_GET['query'] ?? '';
  $page = (int)($_GET['page'] ?? 1); // Cast to int for safety
  ```
* **Consequence**: Параметри запиту зберігаються в історії браузера та логах веб-сервера. Ніколи не передавайте конфіденційні дані (паролі, API-ключі або токени скидання пароля) через `$_GET`.

### 4. `$_POST`
* **Point**: Асоціативний масив змінних, переданих за допомогою методу HTTP POST (наприклад, через HTML-форми або запити типу application/x-www-form-urlencoded).
* **Why it matters**: Використовується для передачі великих наборів даних, метаданих файлів та конфіденційних даних, які змінюють інформацію на сервері.
* **Example**:
  ```php
  // app/Controllers/RegistrationController.php
  
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
      // PHP 8.0+ allows throw expressions with null coalescing:
      $email = $_POST['email'] ?? throw new InvalidArgumentException('Email is required');
      $password = $_POST['password'] ?? '';
  }
  ```
* **Consequence**: Якщо користувач надсилає форму, розмір якої перевищує значення конфігурації `post_max_size` в `php.ini`, PHP автоматично відкидає ці дані. Масив `$_POST` буде порожнім, і помилка не буде згенерована автоматично.

### 5. `$_SESSION`
* **Point**: Асоціативний масив, що містить змінні сесії, доступні поточному скрипту.
* **Why it matters**: Дозволяє зберігати ідентифікаційні дані користувача та його стан (наприклад, кошик покупок або статус авторизації) між різними HTTP-запитами, які самі по собі не зберігають стан.
* **Example**:
  ```php
  // app/Services/AuthenticationService.php
  
  // PHP 7.0+ allows passing runtime options to session_start()
  session_start([
      'cookie_httponly' => true,
      'cookie_secure' => true,
      'cookie_samesite' => 'Lax',
  ]);
  
  $_SESSION['is_logged_in'] = true;
  $_SESSION['username'] = 'john_doe';
  ```
* **Consequence**: Функція `session_start()` повинна бути викликана перед будь-яким зверненням до `$_SESSION`. Якщо сесійні файли cookie не налаштовані з прапорцем `HttpOnly`, ідентифікатор сесії може бути викрадений через XSS, що поставить під загрозу облікові записи користувачів.

### 6. `$_COOKIE`
* **Point**: Асоціативний масив, що містить файли cookie, надіслані серверу браузером користувача.
* **Why it matters**: Дозволяє зчитувати налаштування клієнта або токени автентифікації типу "Запам'ятати мене".
* **Example**:
  ```php
  // app/Services/ThemeService.php
  
  $userTheme = $_COOKIE['preferred_theme'] ?? 'dark';
  ```
* **Consequence**: Cookie повністю зберігаються на стороні клієнта. Користувач може змінити значення cookie вручну у своєму браузері. Ніколи не довіряйте значенням `$_COOKIE` у критичній бізнес-логіці (наприклад, `$_COOKIE['is_admin'] = 1`).

### 7. `$_ENV`
* **Point**: Асоціативний масив, що містить змінні середовища, передані в процес PHP.
* **Why it matters**: Зберігає конфіденційні дані (паролі баз даних, API-ключі поштових сервісів) у безпеці та окремо від вихідного коду.
* **Example**:
  ```php
  // app/Config/Database.php
  
  $dbPassword = $_ENV['DB_PASSWORD'] ?? 'default_password';
  ```
* **Consequence**: Масив `$_ENV` може бути повністю порожнім, якщо директива `variables_order` у файлі `php.ini` не містить символу `"E"` (наприклад, якщо вона налаштована як `"GPCS"`). Якщо `$_ENV` порожній, використовуйте функцію `getenv()` або оновіть конфігурацію сервера.

### 8. `$_FILES`
* **Point**: Асоціативний масив, що містить метадані про файли, завантажені на сервер за допомогою HTTP POST.
* **Why it matters**: Забезпечує безпечний доступ до властивостей завантаженого файлу (ім'я, тип, розмір, тимчасовий шлях, код помилки) для їх валідації та переміщення.
* **Example**:
  ```php
  // app/Services/UploadService.php
  
  if (isset($_FILES['profile_pic']) && $_FILES['profile_pic']['error'] === UPLOAD_ERR_OK) {
      $tempPath = $_FILES['profile_pic']['tmp_name'];
      
      // Strict security validation
      if (is_uploaded_file($tempPath)) {
          $filename = uniqid('avatar_', true) . '.png';
          move_uploaded_file($tempPath, '/var/www/uploads/' . $filename);
      }
  }
  ```
* **Consequence**: Якщо файли не перемістити за допомогою `move_uploaded_file()` під час виконання запиту, PHP автоматично видалить тимчасовий файл із тимчасової директорії після завершення роботи скрипту.

---

## Limitations, Trade-offs, and Clean Architecture

Хоча глобальні змінні та суперглобальні змінні вбудовані в PHP для простоти використання, сучасні практики інженерії програмного забезпечення не рекомендують використовувати їх безпосередньо в бізнес-логіці.

* **Lack of Testability**: Прямий доступ до `$_GET`, `$_POST` або `$_SERVER` жорстко пов'язує ваш клас сервісу з глобальним станом. Це робить юніт-тестування неможливим, оскільки ви не можете ізолювати контекст виконання, не змінюючи глобальні змінні перед кожним тестом.
* **Security Exposure**: Суперглобальні змінні представляють собою сирі, ненадійні вхідні дані від клієнта. Отримання доступу безпосередньо до `$_POST['username']` замість використання перевіреного об'єкта передачі даних запиту збільшує ризик SQL-ін'єкцій та міжсайтового скриптингу (XSS).
* **The Framework Alternative**: Сучасні PHP-фреймворки (такі як Laravel та Symfony) обгортають суперглобальні змінні в об'єкти Request та Response. Замість читання `$_GET['id']` ви впроваджуєте екземпляр `Request`:
  ```php
  // app/Http/Controllers/UserController.php
  
  // Modern framework approach using Dependency Injection
  public function show(Request $request): Response
  {
      $userId = $request->query('id'); // Mockable and testable
      // ...
  }
  ```

---

## Practical Takeaways

1. **Minimize Scope**: Тримайте змінні якомога локальнішими. Передавайте змінні у функції як аргументи замість отримання доступу до них за допомогою ключового слова `global`.
2. **Handle RoadRunner/FrankenPHP Lifecycles**: Якщо ви використовуєте статичні змінні, очищуйте або скидайте їх, якщо ваше середовище використовує постійні робочі процеси (workers). Інакше виникнуть витоки пам'яті або змішування даних користувачів.
3. **Use Request Wrappers**: Якщо ви пишете на чистому PHP (без фреймворків), створіть клас-обгортку або використовуйте `filter_input()` замість прямого доступу до суперглобальних змінних.
4. **Prepare for PHP 8.1+**: Переконайтеся, що у вашому застарілому коді бібліотек немає місць, де `$GLOBALS` перепризначається або передається за посиланням.

---

## Self-Check Quiz

Перевірте своє розуміння областей видимості та суперглобальних змінних у PHP.

### Question 1: Яким буде результат виконання наступного PHP-коду?
```php
// app/Http/Controllers/TestController.php

$name = "Alice";

function greet(): string
{
    return "Hello, " . $name;
}

echo greet();
```
- А) `Hello, Alice`
- B) `Hello, ` разом із попередженням про невизначену змінну (Undefined Variable Warning)
- C) `Hello, $name`

<details>
<summary>Показати відповідь та пояснення</summary>

**Відповідь: B**  
Змінні, визначені в глобальній області видимості, не є автоматично видимими всередині функцій. Оскільки `$name` не оголошено з ключовим словом `global` і до неї немає доступу через `$GLOBALS['name']` всередині `greet()`, PHP видає попередження про невизначену змінну та вважає її рівною `null`.
</details>

### Question 2: Яке твердження є правильним щодо перепризначення `$GLOBALS`?
- А) `$GLOBALS` можна перепризначати у всіх версіях PHP.
- B) Перепризначення всієї змінної `$GLOBALS` (наприклад, `$GLOBALS = [];`) призведе до фатальної помилки, починаючи з PHP 8.1+.
- C) Зміна окремих ключів, наприклад, `$GLOBALS['user'] = 'Bob';` застаріла та вимкнена в PHP 8.1+.

<details>
<summary>Показати відповідь та пояснення</summary>

**Відповідь: B**  
Починаючи з PHP 8.1, ви більше не можете перепризначати весь масив `$GLOBALS` через оптимізацію таблиці символів у Zend Engine. Проте зміна окремих ключів (наприклад, `$GLOBALS['user'] = 'Bob'`) залишається повністю підтримуваною та робочою.
</details>

### Question 3: Чому слід уникати довіри до `$_FILES['input_name']['type']`?
- А) Цей елемент завжди порожній.
- B) Він визначається на стороні сервера PHP і часто є неправильним.
- C) Він надсилається браузером (клієнтом) і може бути підроблений зловмисником.

<details>
<summary>Показати відповідь та пояснення</summary>

**Відповідь: C**  
MIME-тип у `$_FILES['...']['type']` надається безпосередньо в заголовках запиту клієнтського браузера. Зловмисник може завантажити шкідливий `.php` скрипт, але підробити заголовок так, щоб він виглядав як `image/png`. Завжди перевіряйте MIME-тип на сервері за допомогою `finfo_file()` або розширення `fileinfo`.
</details>