PHP Academy · Lektion

Sådan fungerer Zend Engine

Følg PHP fra kildekode over opcodes til eksekvering.

Lektion 1 af 413 trin

Sådan fungerer Zend Engine er en gratis PHP Academy-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i PHP Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. PHP Academy-kurset indeholder 4 lektioner i alt.

Inde i motoren

PHP fortolkes ikke linje for linje direkte fra kildekoden. Zend Engine kompilerer dit script til en mellemliggende repræsentation kaldet opkoder, hvorefter en virtuel maskine udfører dem. Når du forstår dette forløb, bliver det lettere at forstå ydeevne, OPcache og JIT.

I denne lektion følger du vejen fra kildekode → tokens → AST → opkoder → udførelse i VM'en.

Forløbet

Hver anmodning om en PHP-fil går gennem fire faser:

  • Leksikalsk analyse — kildekst → tokens (re2c-baseret skanner)
  • Syntaktisk analyse — tokens → abstrakt syntakstræ (Bison-grammatik)
  • Kompilering — AST → opcode-array (op_array)
  • Udførelse — Zend-VM'en gennemløber opkoderne

Uden OPcache gentages de første tre faser ved hver eneste anmodning.

Tokenisering

Den leksikalske analysator omdanner tegn til tokens som T_VARIABLE, T_ECHO og T_STRING. PHP stiller dette trin til rådighed via token_get_all() / PhpToken, hvilket er præcis det, værktøjer som PHP-CS-Fixer bruger.

<?php
$src = '<?php $x = 1 + 2; echo $x;';

foreach (PhpToken::tokenize($src) as $tok) {
    if ($tok->isIgnorable()) continue;   // skip whitespace
    printf("%-12s %s\n", $tok->getTokenName(), trim($tok->text));
}
?>

AST'en

Tokens analyseres til et træ af noder — en tildelingsnode, hvis børn er en variabel og et binært operatorudtryk. PHP bygger dette AST internt (og nikic/php-parser genskaber en tilsvarende struktur i brugerland til statiske analyseværktøjer som PHPStan).

<?php
// Conceptual AST for:  $x = 1 + 2;
//
//   AST_ASSIGN
//   ├── AST_VAR  ($x)
//   └── AST_BINARY_OP (+)
//       ├── 1
//       └── 2
//
// At compile time PHP folds 1 + 2 into a literal 3
// (constant folding) before generating opcodes.
echo "AST drives opcode generation\n";
?>

Opkoder

Kompileren genererer en op_array: en flad liste af opkoder. Hver opkode har et opkodenummer (f.eks. ZEND_ADD, ZEND_ECHO og ZEND_ASSIGN) samt op til to operander og et resultat, hvor hvert element er en kompileret variabel (CV), en midlertidig værdi (TMP) eller en konstant.

<?php
// Opcodes for:  $x = 1 + 2; echo $x;
//
// line  op            operands           result
//  ---  ------------  -----------------  -------
//   1   ADD           1, 2               ~0
//   1   ASSIGN        $x, ~0
//   1   ECHO          $x
//   1   RETURN        1
//
// ~0 is a temporary; $x is a compiled variable (CV).
echo "op_array is what OPcache stores\n";
?>

Undersøgelse af opkoder

Du kan udskrive de genererede opkoder med udvidelsen VLD eller OPcache-indstillingen opcache.opt_debug_level. Det viser konstantfoldning, eliminering af død kode og hvordan kontrolflow bliver til JMP/JMPZ-opkoder.

# Dump opcodes with VLD
php -d vld.active=1 -d vld.execute=0 script.php

# Or via OPcache optimizer debug (pre/post optimization)
php -d opcache.opt_debug_level=0x10000 script.php   # before opt
php -d opcache.opt_debug_level=0x20000 script.php   # after opt

Kompilerede variabler (CV'er)

Lokale variabler er ikke opslag i hashtabeller i kompileret kode — kompileren tildeler hver af dem en nummereret CV-plads. Anden gang du tilgår $x, er det et arrayindeks og ikke en søgning i symboltabellen. Det er en vigtig årsag til, at lokale variabler er hurtige.

<?php
// Each named local gets a fixed CV slot at compile time:
//   $a -> CV0   $b -> CV1   $sum -> CV2
function add(int $a, int $b): int {
    $sum = $a + $b;   // ADD CV0, CV1 -> CV2
    return $sum;      // RETURN CV2
}
echo add(2, 3) . PHP_EOL;
?>

VM'ens udførelsesløkke

Udføreren (execute_ex) gennemløber op_array'et. Hver opkode er knyttet til en behandlingsfunktion; PHP kan implementere denne fordeling som en enorm switch, beregnede gotoer eller en hybrid (standardvalget og den hurtigste løsning på kompilere, der understøtter det). opline-pegeren bevæger sig fremad; JMP-opkoder flytter den for at styre programforløbet.

<?php
// if ($n > 0) echo 'pos'; compiles roughly to:
//
//   IS_SMALLER 0, $n  -> ~T
//   JMPZ ~T, ->L1        ; if false, skip
//   ECHO 'pos'
// L1:
//   RETURN 1
//
// The VM follows opline; JMPZ rewrites it conditionally.
$n = 5;
if ($n > 0) echo "pos\n";
?>

Hvor OPcache passer ind

OPcache cachelagrer den kompilerede op_array i delt hukommelse og springer leksikalsk analyse, syntaktisk analyse og kompilering over ved efterfølgende anmodninger. OPcache kører også et optimeringspass (konstantfoldning, fjernelse af død kode og sammensmeltning af opkoder). VM'en udfører stadig de cachede opkoder ved hver anmodning — det er her, JIT senere kan hjælpe.

Omkostninger ved funktionskald

Funktionskald opretter en ny VM-stakramme: opkoderne INIT_FCALL, SEND_VAL/SEND_VAR for hvert argument og derefter DO_FCALL. Det forklarer, hvorfor for mange små funktionskald har en målbar omkostning, og hvorfor inlining/JIT har betydning i intensive løkker.

<?php
// square($x) compiles to a call sequence:
//   INIT_FCALL 'square'
//   SEND_VAR   $x
//   DO_FCALL        -> ~R
//   ASSIGN $y, ~R
function square(int $x): int { return $x * $x; }

$total = 0;
for ($i = 1; $i <= 5; $i++) {
    $total += square($i);   // one call sequence per iteration
}
echo $total . PHP_EOL;     // 1+4+9+16+25 = 55
?>

Afslutning af anmodningen

Efter udførelsen rydder PHP anmodningen op: aktive variabler frigives, uddata tømmes, og motoren nulstiller derefter sin allokeringsarena. I den delte-nothing-model i FPM starter hver anmodning rent — derfor kan en fatal fejl i én anmodning ikke ødelægge en anden. OPcache's delte op_arrays overlever mellem anmodninger; udførerens tilstand gør ikke.

Hurtigt tjek

Hvad gemmer OPcache helt præcist for at springe kompilering over?

Opsummering

Zend-forløbet er leksikalsk analyse → syntaktisk analyse → kompilering → udførelse. Kildekode bliver til tokens, derefter et AST og så en op_array med opkoder, som VM'ens udførelsesløkke gennemløber, mens lokale variabler gemmes i nummererede CV-pladser, og funktionskald opretter stakrammer. OPcache cachelagrer op_array'et (sammen med et optimeringspass), så kun udførelsen gentages ved hver anmodning.

Gratis at komme i gang

Lær PHP med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
49
Lektioner
195

Ofte stillede spørgsmål

Er lektionen “Sådan fungerer Zend Engine” gratis?

Ja — hele teksten til “Sådan fungerer Zend Engine” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af PHP Academy-kurset, skal du opgradere til CoddyKit PRO. PHP Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Sådan fungerer Zend Engine”?

Følg PHP fra kildekode over opcodes til eksekvering. Du øver dig i PHP Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på PHP Academy?

Der kræves ingen tidligere erfaring. PHP Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.

Hvor lang tid tager lektionen “Sådan fungerer Zend Engine”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne PHP Academy-lektion?

Ja. Alle PHP Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Sådan fungerer Zend Engine
  2. Hukommelseshåndtering og garbage collection
  3. OPcache og JIT-kompilering
  4. Skriv en basal PHP-udvidelse i C
← Tilbage til PHP Academy