Na kratko: PHP je dinamično tipiziran: tip vrednosti je znan šele med izvajanjem, brez nadaljnjih navodil pa PHP vrednosti po potrebi samodejno pretvarja. Od PHP 7 je parametre, vrnjene vrednosti in lastnosti mogoče opremiti s tipi, declare(strict_types=1) pa preverjanje zaostri. Kdor pozna pravila in uporablja stroge primerjave z ===, se izogne celemu razredu logičnih in varnostnih napak.
Dinamično tipiziran, a ne brez tipov
Pri $preis = 19.90; v PHP tipa ni treba navesti. PHP prepozna, da gre za število s plavajočo vejico. Če se vrednost pozneje poveže z nizom, jo PHP pretvori. To obnašanje se imenuje type juggling, torej samodejna pretvorba tipov. Vstop je zato preprost, lahko pa vodi do presenetljivih rezultatov.
Za odločevalce je to pomembno, ker so številne starejše aplikacije PHP napisane brez navedb tipov. Tako kodo je težje preverjati in posodabljati. Novejši projekti tipe dosledno uporabljajo, kar napake razkrije prej in šele omogoči pravi učinek statične analize z orodji, kot sta PHPStan ali Psalm.
Pregled tipov v PHP
Priročnik PHP navaja devet notranjih tipov, ki jih ima lahko vsak izraz. Običajno jih delimo v tri skupine:
| Skupina | Tipi | Primer |
|---|---|---|
| Skalarni tipi | bool, int, float, string |
true, 42, 3.5, "Text" |
| Sestavljeni tipi | array, object, callable |
[1, 2], new DateTime() |
| Posebni tipi | null, resource |
null, odprta datoteka |
Za preverjanje tipov priročnik priporoča funkcije is_*(), na primer is_int(). Za pregled je primerna get_debug_type(), ki od PHP 8.0.0 vrača običajna imena tipov, medtem ko starejša gettype() na primer vrne "integer" in "double".
Poleg samodejne pretvorbe obstaja tudi izrecna: s castom, kot je (int) $wert, ali s settype() koda sama določi, kakšen tip naj ima vrednost. To je običajno pri vnosih iz obrazcev, saj je vse, kar pride prek $_GET ali $_POST, sprva niz ali polje. Cast pa ne preveri, ali je bila vrednost smiselna: iz "abc" molče nastane 0. Za vnose je zato pogosto boljša izbira pravo preverjanje s filter_var().
Razredi in vmesniki (interface) so v PHP prav tako tipi. Funkcija lahko torej zahteva, da je parameter objekt določenega razreda ali da izpolnjuje določen vmesnik. Kako razredi, vmesniki in enumi sodelujejo, razlaga stran Objektno usmerjeno programiranje v PHP.
Deklaracije tipov: od PHP 7.1 do 8.3
Deklaracije tipov določajo, katere vrednosti funkcija sprejme in vrne. Tipski sistem je rasel skozi številne različice. Po dnevniku sprememb priročnika so bile med drugim dodane te možnosti:
| Različica | Novo |
|---|---|
| 7.1.0 | tipi, ki lahko vsebujejo null (?int), void, iterable |
| 7.2.0 | object |
| 7.4.0 | tipizirane lastnosti razredov |
| 8.0.0 | unijski tipi (več dovoljenih tipov v eni navedbi), mixed, vrnjeni tip static |
| 8.1.0 | presečni tipi (A&B), vrnjeni tip never |
| 8.2.0 | tipi DNF, literalni tip true, null in false kot samostojna tipa |
| 8.3.0 | tipizirane konstante razredov, vmesnikov, trait in enum |
DNF pomeni disjunktivno normalno obliko in dovoljuje kombinacije, kot je (A&B)|null. Kdor načrtuje različice PHP, iz te tabele vidi tudi, katera jezikovna sredstva aplikacija zahteva.
strict_types: pretvorba ali TypeError
Brez nadaljnje navedbe PHP deluje v pretvarjalnem načinu. Funkcija s parametri int tedaj sprejme tudi 1.5 in iz tega naredi 1; od PHP 8.1 je ta pretvorba z izgubo označena kot zastarela. Z declare(strict_types=1) na začetku datoteke PHP namesto tega sproži 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, namesto molče 3
Pomembni sta dve podrobnosti. Prvič, strict_types velja za klice iz datoteke, v kateri stoji, ne za tam definirane funkcije. Če isto funkcijo pokliče datoteka brez strict_types, se pretvarja. Drugič, celo število je tam, kjer se pričakuje število s plavajočo vejico, dovoljeno tudi v strogem načinu.
Ohlapne in stroge primerjave
Operator == primerja po pretvorbi tipov, === primerja vrednost in tip brez pretvorbe. Priročnik v večini primerov priporoča === in !==, ker pravila pretvorbe niso vedno očitna.
<?php
var_dump(0 == "a"); // PHP 7: true, PHP 8: false
var_dump("1" == "01"); // true, oba sta numerična niza
var_dump("1" === "01");// false, isti tip, a drugačen niz
var_dump(1 == true); // true
var_dump(1 === true); // false
S PHP 8.0 so postale primerjave med števili in nenumeričnimi nizi smiselnejše. Starejše aplikacije se lahko po nadgradnji obnašajo drugače, na primer v blokih switch. Prav tako od PHP 8.0 uvedeni izraz match primerja vedno strogo. Kako ohlapne primerjave vodijo do varnostnih vrzeli, na primer pri preverjanju žetonov ali gesel, opisuje prispevek Type juggling: ohlapne primerjave kot varnostno tveganje.
Tipi, nadgradnje in PHP2Shell
Strog tipski sistem naredi kodo aplikacije robustnejšo, vendar ne ščiti pred napakami v samem interpreterju. Ranljivosti PHP2Shell CVE-2026-109618 in CVE-2026-109619 ležita v upravljanju pomnilnika in zahtev v PHP. Odpravljeni sta v PHP 8.5.12, 8.4.27, 8.3.36 in 8.2.35; nato je treba znova zagnati vse procese PHP.
Tipski sistem kljub temu igra vlogo, in sicer pri nadgradnji. Aplikacije, ki so še na PHP 8.1 ali starejšem, od projekta PHP ne prejemajo več uradnih posodobitev. Dobro tipizirano kodo je bistveno lažje dvigniti na podprto različico, ker orodja nezdružljivosti odkrijejo zgodaj. Pri starejših projektih pomaga naša selitev na podprto različico PHP.
Funkcijo strict_types vklapljajte postopoma v novih in predelanih datotekah. Tako tipska varnost raste, ne da bi se stara koda naenkrat pokvarila.
Kako PHP SOS pomaga konkretno?
- Preverimo, katero različico PHP vaša aplikacija najmanj potrebuje, in to uskladimo z odpravljenimi različicami.
- Čez kodo poženemo statično analizo in označimo mesta z ohlapnimi primerjavami v varnostno pomembnih preverjanjih.
- Nadgradnje načrtujemo tako, da se spremenjena pravila primerjav predhodno preizkusijo.
- Namestimo posodobitev PHP, znova zaženemo vse workerje in dokumentiramo stanje.
Pogosta vprašanja
Ali je PHP močno ali šibko tipiziran?
PHP je dinamično tipiziran: tip spremenljivke je znan šele med izvajanjem. Brez strict_types PHP vrednosti po potrebi pretvarja. Z deklaracijami tipov in strict_types pa je kodo mogoče narediti zelo strogo.
Kaj povzroči declare(strict_types=1)?
Za klice iz posamezne datoteke izklopi samodejno pretvarjanje skalarnih vrednosti. Če vrednost ne ustreza deklariranemu tipu, PHP sproži TypeError. Edina izjema je celo število tam, kjer se pričakuje število s plavajočo vejico.
Zakaj je 0 == "a" v PHP 8 napačno, v PHP 7 pa resnično?
Do PHP 7 se je nenumerični niz pri primerjavi s številom pretvoril v število, iz "a" je nastala 0. Od PHP 8.0 PHP v tem primeru ne primerja več numerično, rezultat je false.
Ali tipi ščitijo pred varnostnimi vrzelmi v samem PHP?
Ne. Tipi preprečujejo napake v kodi vaše aplikacije. Vrzeli v interpreterju, kot je PHP2Shell, zapre samo posodobitev PHP. Sodobne tipske funkcije pa zahtevajo aktualne različice PHP in so tako dober povod za nadgradnjo.