Текуща ситуация: PHP2Shell. Две критични уязвимости в PHP (CVSS 9,2) позволяват злонамерен код без вход. Корекции от 21.10.2026 г.Какво да направите сега →

Типовата система на PHP

PHP е динамично типизиран, но от PHP 7 насам получава все по-строга типова система. Тук ще видите типовете, важните версии и защо строгите сравнения предотвратяват грешки в сигурността.

Актуалност 5 мин. четенеЗнания за PHP

Накратко: PHP е динамично типизиран: типът на една стойност се определя едва по време на изпълнение и без други указания PHP при нужда преобразува стойностите автоматично. От PHP 7 обаче параметрите, върнатите стойности и свойствата могат да се означават с типове, а declare(strict_types=1) прави проверката строга. Който познава правилата и използва строги сравнения с ===, избягва цял клас логически грешки и грешки в сигурността.

Динамична типизация, но не без типове

В PHP при $preis = 19.90; не е нужно да се посочва тип. PHP разпознава, че това е число с плаваща запетая. Ако стойността по-късно се свърже с низ, PHP я преобразува. Това поведение се нарича Type Juggling, т.е. автоматично преобразуване на типове. То улеснява началото, но може да доведе до изненадващи резултати.

За вземащите решения това е важно, защото много по-стари PHP приложения са писани без указване на типове. Такъв код е по-труден за проверка и модернизиране. По-новите проекти използват типовете последователно, което показва грешките по-рано и чак тогава позволява статичният анализ с инструменти като 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.

Декларации на типове: от 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
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
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: свободните сравнения като риск за сигурността.

Типове, надграждания и 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.

Съвет

Активирайте 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 и какво сте забелязали. Ние се свързваме с Вас, уточняваме ситуацията и работим отдалечено, докато инцидентът бъде приключен и документиран.

Незабавна помощ