Kort sagt: PHP er dynamisk typet: En værdis type fastlægges først under kørslen, og uden yderligere angivelser omdanner PHP værdier automatisk efter behov. Siden PHP 7 kan parametre, returværdier og egenskaber dog forsynes med typer, og declare(strict_types=1) gør kontrollen streng. Den, der kender reglerne og bruger strikte sammenligninger med ===, undgår en hel klasse af logik- og sikkerhedsfejl.
Dynamisk typet, men ikke typeløs
I PHP behøver man ikke angive en type ved $preis = 19.90;. PHP genkender, at der er tale om et kommatal. Forbindes værdien senere med en tekststreng, omdanner PHP den. Denne adfærd kaldes type juggling, altså automatisk typeomdannelse. Det gør starten let, men kan føre til overraskende resultater.
For beslutningstagere er det relevant, fordi mange ældre PHP-applikationer blev skrevet uden typeangivelser. Sådan kode er sværere at kontrollere og modernisere. Nyere projekter bruger typer konsekvent, hvilket gør fejl synlige tidligere og først for alvor lader den statiske analyse virke med værktøjer som PHPStan eller Psalm.
PHP's typer i overblik
PHP-manualen nævner ni interne typer, som ethvert udtryk kan have. Sædvanligvis inddeles de i tre grupper:
| Gruppe | Typer | Eksempel |
|---|---|---|
| Skalare typer | bool, int, float, string |
true, 42, 3.5, "Text" |
| Sammensatte typer | array, object, callable |
[1, 2], new DateTime() |
| Særlige typer | null, resource |
null, en åbnet fil |
Til typekontrol anbefaler manualen is_*()-funktionerne som is_int(). Til undersøgelse egner sig get_debug_type(), som siden PHP 8.0.0 leverer de gængse typenavne, mens den ældre gettype() for eksempel returnerer "integer" og "double".
Ud over den automatiske omdannelse findes den udtrykkelige: Med en cast som (int) $wert eller med settype() fastlægger koden selv, hvilken type en værdi skal have. Det er sædvanligt ved input fra formularer, for alt, der kommer ind via $_GET eller $_POST, er først en tekststreng eller et array. En cast kontrollerer dog ikke, om værdien var meningsfuld: Af "abc" bliver der stiltiende 0. Til input er en ægte kontrol med filter_var() derfor som regel det bedre valg.
Klasser og interfaces er også typer i PHP. En funktion kan altså kræve, at en parameter er et objekt af en bestemt klasse eller opfylder et bestemt interface. Hvordan klasser, interfaces og enums spiller sammen, forklarer siden Objektorientering i PHP.
Typedeklarationer: fra PHP 7.1 til 8.3
Typedeklarationer fastlægger, hvilke værdier en funktion modtager og returnerer. Typesystemet er vokset over mange versioner. Ifølge manualens ændringslog kom blandt andet disse muligheder til:
| Version | Nyt |
|---|---|
| 7.1.0 | nullable typer (?int), void, iterable |
| 7.2.0 | object |
| 7.4.0 | typede klasseegenskaber |
| 8.0.0 | union-typer (flere tilladte typer i én angivelse), mixed, returtypen static |
| 8.1.0 | intersection-typer (A&B), returtypen never |
| 8.2.0 | DNF-typer, literaltypen true, null og false som selvstændige typer |
| 8.3.0 | typede konstanter i klasser, interfaces, traits og enums |
DNF står for disjunktiv normalform og tillader kombinationer som (A&B)|null. Den, der planlægger PHP-versioner, kan ud fra denne tabel også se, hvilke sprogmidler en applikation forudsætter.
strict_types: omdannelse eller TypeError
Uden yderligere angivelse arbejder PHP i omdannende tilstand. En funktion med int-parametre modtager så også 1.5 og gør det til 1; siden PHP 8.1 er denne tabsgivende omdannelse markeret som forældet. Med declare(strict_types=1) i begyndelsen af filen kaster PHP i stedet en 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, i stedet for stiltiende 3
To finesser er vigtige. For det første gælder strict_types for kald fra den fil, hvor det står, ikke for de funktioner, der er defineret dér. Kalder en fil uden strict_types den samme funktion, omdannes der. For det andet er et heltal tilladt, hvor der forventes et kommatal, også i den strenge tilstand.
Løse og strikte sammenligninger
Operatoren == sammenligner efter typeomdannelse, === sammenligner værdi og type uden omdannelse. Manualen anbefaler i de fleste tilfælde === og !==, fordi omdannelsesreglerne ikke altid er indlysende.
<?php
var_dump(0 == "a"); // PHP 7: true, PHP 8: false
var_dump("1" == "01"); // true, begge er numeriske tekststrenge
var_dump("1" === "01");// false, samme type, men en anden tekststreng
var_dump(1 == true); // true
var_dump(1 === true); // false
Med PHP 8.0 blev sammenligninger mellem tal og ikke-numeriske tekststrenge mere fornuftige. Ældre applikationer kan efter opgraderingen opføre sig anderledes, f.eks. i switch-blokke. Udtrykket match, der også kom med PHP 8.0, sammenligner altid strikt. Hvordan løse sammenligninger fører til sårbarheder, for eksempel ved kontrol af tokens eller adgangskoder, beskriver indlægget Type juggling: løse sammenligninger som sikkerhedsrisiko.
Typer, opgraderinger og PHP2Shell
Et strengt typesystem gør applikationskode mere robust, men det beskytter ikke mod fejl i selve fortolkeren. PHP2Shell-sårbarhederne CVE-2026-109618 og CVE-2026-109619 ligger i PHP's hukommelses- og forespørgselshåndtering. De er rettet i PHP 8.5.12, 8.4.27, 8.3.36 og 8.2.35; derefter skal alle PHP-processer genstartes.
Typesystemet spiller alligevel en rolle, nemlig ved opgraderingen. Applikationer, der stadig sidder fast på PHP 8.1 eller ældre, får ikke længere officielle opdateringer fra PHP-projektet. Velskrevet kode med typer kan løftes betydeligt lettere til en understøttet version, fordi værktøjer finder uforeneligheder tidligt. Ved ældre projekter hjælper vores migrering til en understøttet PHP-version.
Aktivér strict_types trinvis i nye og gennemarbejdede filer. Så vokser typesikkerheden, uden at gammel kode går i stykker på én gang.
Hvordan hjælper PHP SOS konkret?
- Vi undersøger, hvilken PHP-version jeres applikation mindst har brug for, og sammenholder det med de rettede versioner.
- Vi lader statisk analyse køre over koden og markerer steder med løse sammenligninger i sikkerhedsrelevante kontroller.
- Vi planlægger opgraderinger, så ændrede sammenligningsregler testes på forhånd.
- Vi indspiller PHP-opdateringen, genstarter alle workers og dokumenterer status.
Ofte stillede spørgsmål
Er PHP stærkt eller svagt typet?
PHP er dynamisk typet: En variabels type fastlægges først under kørslen. Uden strict_types omdanner PHP værdier efter behov. Med typedeklarationer og strict_types kan koden dog gøres meget streng.
Hvad gør declare(strict_types=1)?
Det slår den automatiske omdannelse af skalare værdier fra for kald fra den pågældende fil. Passer en værdi ikke til den deklarerede type, kaster PHP en TypeError. Eneste undtagelse er et heltal, hvor der forventes et kommatal.
Hvorfor er 0 == "a" falsk i PHP 8, men sand i PHP 7?
Til og med PHP 7 blev en ikke-numerisk tekststreng omdannet til et tal ved sammenligning med et tal, så »a« blev til 0. Siden PHP 8.0 sammenligner PHP i dette tilfælde ikke længere numerisk, og resultatet er false.
Beskytter typer mod sårbarheder i selve PHP?
Nej. Typer forhindrer fejl i jeres applikationskode. Sårbarheder i fortolkeren som PHP2Shell lukkes kun ved en PHP-opdatering. Moderne typefunktioner forudsætter dog aktuelle PHP-versioner og er dermed en god anledning til at opgradere.