PHP zvals und Referenzen erklärt
Heute schauen wir uns kurz an, wie PHP Variablen speichert und wie Referenzen funktionieren. Los geht's.
Symbols und zvals
Jede PHP Variable besteht aus einem Symbol (dem Name der Variable) und einer zval (Zend Value), einem speziellen Daten-Container. Diese zval speichert nebst dem Datentyp und dem Wert, auch wie viele Symbols sie hat (refcount) und ob diese Symbols als Referenzen definiert wurden (is_ref).
Im PHP Souce Code ist die zval einfach eine simple Struktur:
typedef struct _zval_struct {
zvalue_value value;
zend_uint refcount;
zend_uchar type;
zend_uchar is_ref;
}
refcount
refcount ist wichtig, damit PHP für gleiche Variablen (im Sinne von $a = $b = 42) dieselben Daten nicht mehrmals speichern muss.

Der refcount-Zähler wird also inkrementiert, wenn ein neues Symbol hinzugefügt wird und dekrementiert, falls ein Symbol gelöscht wird (z.B. mit unset()). Wenn refcount Null (0) erreicht, kann die zval aus dem Speicher gekickt werden. Achtung: Die zval weiss nicht welche Symbols auf sie zeigen.
is_ref
Das is_ref-Flag wird gesetzt, fall eine Variable einer anderen per Referenz zugewiesen wurde.

Wieso dieses Flag so wichtig ist, sehen wir gleich.
Copy-on-Write
Wir haben also gesehen, dass PHP versucht Arbeitspeicher zu sparen und unnötiges Kopieren zu verhindern. Doch wann wird kopiert? Nun, zvals (oder die "Daten") werden dann kopiert, wenn nicht mehr sichergestellt werden kann, dass alle Symbols auf die selben Daten verweisen werden oder können. Also z.B. wenn $a und $b zuerst gleich sind, danach aber $b geändert wird.

Solange $a und $b gleich sind, gibt es keinen Grund die Daten zu kopieren. Wird $b aber verändert, muss die zval kopiert werden. Daneben gibt es noch zwei andere Szenarien, wann zvals aufgeteilt werden müssen. Bei beiden geht es darum, wenn ein drittes Symbol ins Spiel kommt.
Referenz auf is_ref = 0
Nehmen wir an, dass $a und $b "gleich" sind. Würde $c nun ebenfalls $a zugewiesen, würde einfach ein weiteres Symbol erstellt werden. Wenn aber $c per Referenz an $a (oder $b) zugewiesen wird, muss PHP die zval kopieren. Denn $c soll ja nur die selben Daten wie $a referenzieren, nicht aber wie $b.

Zuweisung auf is_ref = 1
Und dann gibt es noch das Gegenteil davon: Zwei Variablen $a und $b referenzieren sich, und eine dritte Variable $c wird normal $a (oder $b) zugewiesen. Da die Referenz zwischen $a und $b nicht zerstört werden darf, muss $c einen eigenen Daten-Container nutzen.

Dieses Verfahren, dass Daten nicht kopiert werden, solange es nicht nötig ist, nennt sich copy-on-write oder copy-on-change.
Wann wird kopiert?
Bei PHP gibt es dazu ein paar einfache Grundregeln.
Wenn Variablen einander zugewiesen werden, sehen die Regeln so aus:
Wenn
refcount=1:
- Erfolgt die Zuweisung normal wird
refcountauf2gesetzt undis_refbleibt0- Erfolgt die Zuweisung per Referenz wird
refcountauf2gesetzt undis_refauf1Wenn
refcountgrösser1:
- Erfolgt die Zuweisung normal und
is_refist0, kannrefcountum1erhöht werden. Istis_refaber1, dann muss eine neue zval erstellt werden.- Erfolgt die Zuweisung per Referenz und
is_refist1, kannrefcountum1erhöht werden. Istis_refaber0, dann muss die bestehende zval aufgeteilt werden.
Werden Variablen neue Werte zugewiesen, sehen die Regeln so aus:
Wenn
refcount=1:
- Der bestehende Wert und Datentyp kann überschrieben werden.
Wenn
refcountgrösser1:
- Wenn
is_refgleich0ist, dann muss eine neue zval erstellt werden.- Wenn
is_refgleich1ist, dann kann der bestehenden Wert und Datentyp überschrieben werden.
Eigentlich ganz simpel, und doch können damit so viele Kombinationen abgedeckt werden. :)
Ähnliche Artikel
- Properties: Neue Get-/Set-Syntax für PHP?
- *knock, knock* - Wer ist da? - PHP 5.4!!111!!eins!!
- Statische Methoden sind einfach nur Funktionen - also Vorsicht!




