# Типовата система на PHP

> Типовата система на PHP, обяснена: типове данни, декларации на типове от PHP 7.1 до 8.3, strict_types и свободни сравнения с примери и връзка със сигурността.

Източник: https://phpsos.de/bg/php/typsystem/  
Актуалност: 25.10.2026  
Доставчик: PHP SOS, Спешна помощ за PHP и сигурност на сървъри. Незабавна помощ по WhatsApp: https://wa.me/491736494914?text=%D0%97%D0%B4%D1%80%D0%B0%D0%B2%D0%B5%D0%B9%D1%82%D0%B5%2C%20PHP%20SOS%2C%20%D0%B8%D0%BC%D0%B0%D0%BC%D0%B5%20%D0%BD%D1%83%D0%B6%D0%B4%D0%B0%20%D0%BE%D1%82%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%20%D1%81%20%D0%BD%D0%B0%D1%88%D0%B8%D1%8F%20PHP%20%D1%81%D1%8A%D1%80%D0%B2%D1%8A%D1%80.%20%D0%A4%D0%B8%D1%80%D0%BC%D0%B0%3A%20%E2%80%A6%20%D0%A3%D0%B5%D0%B1%D1%81%D0%B0%D0%B9%D1%82%3A%20%E2%80%A6

**Накратко:** PHP е динамично типизиран: типът на една стойност се определя едва по време на изпълнение и без други указания PHP при нужда преобразува стойностите автоматично. От PHP 7 обаче параметрите, върнатите стойности и свойствата могат да се означават с типове, а `declare(strict_types=1)` прави проверката строга. Който познава правилата и използва строги сравнения с `===`, избягва цял клас логически грешки и грешки в сигурността.

## Динамична типизация, но не без типове

В PHP при `$preis = 19.90;` не е нужно да се посочва тип. PHP разпознава, че това е число с плаваща запетая. Ако стойността по-късно се свърже с низ, PHP я преобразува. Това поведение се нарича Type Juggling, т.е. автоматично преобразуване на типове. То улеснява началото, но може да доведе до изненадващи резултати.

За вземащите решения това е важно, защото много по-стари PHP приложения са писани без указване на типове. Такъв код е по-труден за проверка и модернизиране. По-новите проекти използват типовете последователно, което показва грешките по-рано и чак тогава позволява [статичният анализ](https://phpsos.de/bg/php/statische-analyse/) с инструменти като PHPStan или Psalm да заработи истински.

## Типовете на PHP накратко

Ръководството на PHP назовава девет вътрешни типа, които може да има всеки израз. Обикновено те се разделят на три групи:

| Група | Типове | Пример |
|---|---|---|
| Скаларни типове | `bool`, `int`, `float`, `string` | `true`, `42`, `3.5`, `"Text"` |
| Съставни типове | `array`, `object`, `callable` | `[1, 2]`, `new DateTime()` |
| Особени типове | `null`, `resource` | `null`, отворен файл |

За проверка на типове ръководството препоръчва функциите `is_*()`, например `is_int()`. За изследване е подходяща `get_debug_type()`, която от PHP 8.0.0 връща общоприетите имена на типовете, докато по-старата `gettype()` връща например `"integer"` и `"double"`.

Освен автоматичното има и изрично преобразуване: с cast като `(int) $wert` или със `settype()` самият код определя какъв тип трябва да има дадена стойност. Това е обичайно при въвеждане от формуляри, защото всичко, което постъпва през `$_GET` или `$_POST`, първоначално е низ или масив. Cast обаче не проверява дали стойността е била смислена: от `"abc"` мълчаливо се получава `0`. За въвеждани данни затова истинската проверка с `filter_var()` обикновено е по-добрият избор.

Класовете и интерфейсите в PHP също са типове. Една функция може да изисква параметърът да е обект от определен клас или да изпълнява определен интерфейс. Как си взаимодействат класове, интерфейси и enum, обяснява страницата [Обектно-ориентирано програмиране в PHP](https://phpsos.de/bg/php/objektorientierung/).

## Декларации на типове: от PHP 7.1 до 8.3

Декларациите на типове определят какви стойности приема и връща една функция. Типовата система е растяла в продължение на много версии. Според дневника на промените в ръководството са добавени, наред с други, следните възможности:

| Версия | Ново |
|---|---|
| 7.1.0 | nullable типове (`?int`), `void`, `iterable` |
| 7.2.0 | `object` |
| 7.4.0 | типизирани свойства на класове |
| 8.0.0 | Union типове (няколко разрешени типа в една декларация), `mixed`, тип на връщане `static` |
| 8.1.0 | Intersection типове (`A&B`), тип на връщане `never` |
| 8.2.0 | DNF типове, литерален тип `true`, `null` и `false` като самостоятелни типове |
| 8.3.0 | типизирани константи на класове, интерфейси, trait и enum |

DNF означава дизюнктивна нормална форма и позволява комбинации като `(A&B)|null`. Който планира версиите на PHP, вижда от тази таблица и кои езикови средства изисква едно приложение.

## strict_types: преобразуване или TypeError

Без други указания PHP работи в режим на преобразуване. Функция с параметри от тип `int` тогава приема и `1.5` и прави от него `1`; от PHP 8.1 това преобразуване със загуба е отбелязано като остаряло. С `declare(strict_types=1)` в началото на файла PHP вместо това хвърля `TypeError`.

```php
<?php
declare(strict_types=1);

function summe(int $a, int $b): int
{
    return $a + $b;
}

echo summe(1, 2);      // 3
echo summe(1.5, 2.5);  // TypeError, вместо мълчаливо 3
```

Две тънкости са важни. Първо, `strict_types` важи за извикванията от файла, в който стои, а не за функциите, дефинирани там. Ако файл без `strict_types` извика същата функция, се преобразува. Второ, цяло число там, където се очаква число с плаваща запетая, е разрешено и в строгия режим.

## Свободни и строги сравнения

Операторът `==` сравнява след преобразуване на типове, а `===` сравнява стойност и тип без преобразуване. Ръководството препоръчва в повечето случаи `===` и `!==`, защото правилата за преобразуване не винаги са очевидни.

```php
<?php
var_dump(0 == "a");    // PHP 7: true,  PHP 8: false
var_dump("1" == "01"); // true, и двата са числови низове
var_dump("1" === "01");// false, същият тип, но различен низ
var_dump(1 == true);   // true
var_dump(1 === true);  // false
```

С PHP 8.0 сравненията между числа и нечислови низове станаха по-разумни. По-стари приложения могат да се държат различно след надграждането, например в блокове `switch`. Въведеният също с PHP 8.0 израз `match` винаги сравнява строго. Как свободните сравнения водят до уязвимости, например при проверка на токени или пароли, описва статията [Type Juggling: свободните сравнения като риск за сигурността](https://phpsos.de/bg/blog/type-juggling-php/).

## Типове, надграждания и PHP2Shell

Строгата типова система прави кода на приложението по-устойчив, но не предпазва от грешки в самия интерпретатор. Уязвимостите PHP2Shell CVE-2026-109618 и CVE-2026-109619 се намират в управлението на паметта и на заявките в PHP. Отстранени са в PHP 8.5.12, 8.4.27, 8.3.36 и 8.2.35; след това всички PHP процеси трябва да се рестартират.

Въпреки това типовата система играе роля, и то при надграждането. Приложения, които още стоят на PHP 8.1 или по-стара версия, вече не получават официални актуализации от проекта PHP. Добре типизираният код много по-лесно може да се премине към поддържана версия, защото инструментите откриват несъвместимостите рано. При по-стари проекти ни подпомага нашата [миграция към поддържана версия на PHP](https://phpsos.de/bg/leistungen/php-migration-legacy/).

> **Съвет:**
> Активирайте `strict_types` постепенно в нови и преработени файлове. Така типовата сигурност расте, без старият код да се срути изведнъж.

## Как помага PHP SOS конкретно?

- Проверяваме коя минимална версия на PHP изисква Вашето приложение и я съпоставяме с коригираните версии.
- Пускаме статичен анализ върху кода и отбелязваме места със свободни сравнения в проверки, свързани със сигурността.
- Планираме надграждането така, че променените правила за сравнение да бъдат тествани предварително.
- Внедряваме актуализацията на PHP, рестартираме всички worker процеси и документираме състоянието.


## Често задавани въпроси

**PHP със силна или със слаба типизация ли е?**  
PHP е динамично типизиран: типът на дадена променлива се определя едва по време на изпълнение. Без strict_types PHP преобразува стойностите при нужда. С декларации на типове и strict_types обаче кодът може да се направи много строг.

**Какво променя declare(strict_types=1)?**  
За извикванията от съответния файл изключва автоматичното преобразуване на скаларни стойности. Ако дадена стойност не съответства на декларирания тип, PHP хвърля TypeError. Единственото изключение е цяло число там, където се очаква число с плаваща запетая.

**Защо 0 == "a" в PHP 8 е невярно, а в PHP 7 е вярно?**  
До PHP 7 при сравнение с число нечислов низ се преобразуваше в число и от "a" ставаше 0. От PHP 8.0 в този случай PHP вече не сравнява числово и резултатът е false.

**Предпазват ли типовете от уязвимости в самия PHP?**  
Не. Типовете предотвратяват грешки във Вашия код на приложението. Уязвимости в интерпретатора като PHP2Shell се затварят само чрез актуализация на PHP. Съвременните типови функции обаче изискват актуални версии на PHP и затова са добър повод за надграждане.

## Източници

- [Ръководство на PHP: Декларации на типове](https://www.php.net/manual/de/language.types.declarations.php)
- [Ръководство на PHP: Въведение в типовете](https://www.php.net/manual/de/language.types.intro.php)
- [Ръководство на PHP: Оператори за сравнение](https://www.php.net/manual/de/language.operators.comparison.php)
- [PHP 8.0 Release](https://www.php.net/releases/8.0/en.php)
