Philipp Hasenfratz: Pass-by-Reference automatisch?

Beitrag lesen

Halihallo Peter

PHP4 also have reference count feature. For example, memory for variables is
shared when it assigned to other variable. If contents has been changed, PHP4
allocate new memory for it.
|
For example, programmer does not have to use pass by reference for large
parameters for better performance with PHP4.

Ist das wirklich der Fall? Sonst liest man doch oft, dass man Pass-by-Reference verwenden solle, um zu verhindern, dass Variablendaten unnötig kopiert werden und so die Geschwindigkeit beeinträchtigen; hier steht nun, dass das automatisch passiert, sofern die neue Variable nicht verändert wird. Aber dass o.g. Beitrag ohne Beantstandung durch andere PHP-Leser schon 3 Jahre durchgehalten hat, macht mich stuzig ...

Das ist IMHO schon richtig. Ich habe mich zwar noch nie durch den PHP
Quellcode gekämpft, weiss jedoch in etwa wie dies alles funktioniert:

Ein kleiner Exkurs gefällig? : ;)

Eine Variable in PHP/Perl/... ist nichts anderes als ein Pointer auf
einen Speicherbereich, welcher z.B. die aktuelle Länge, die Daten an
sich, ob es eine Referenz ist, ob die Variable eine Klasseninstanz
ist (wenn ja, von welcher) und den Reference Counter enthält. Falls
man also z.B.

$a=5;

schreibt, wird ein Speicherbereich alloziiert (reserviert, geholt,
erstellt), welcher den Wert '5' aufnehmen kann. Zudem wird der
Reference Counter auf 1 gesetzt, da die Variable $a jetzt
genau "einmal existiert". Falls nun folgendes geschieht:

$a=5;
$b=$a;

Nun, es ist klar, dass $a und $b denselben Wert haben. Muss jetzt
wirklich jeweils Speicher für $a _und_ $b reserviert werden? - Nein.
Solange die beiden Variablen denselben Wert enthalten (also nicht
geändert werden), können $a und $b auf denselben Speicherbereich
verweisen, wo '5' definiert ist; PHP muss sich nur merken, wie viele
"Variablen" (oder eben besser: Pointer/Zeiger) auf diesen
Speicherbereich referenzieren, denn sonst kann PHP nicht wissen, wann
der Speicher wieder freigegeben werden darf. Falls jedoch $b der
Wert 7 zugewiesen wird, kann dies nicht einfach im gemeinsamen
Speicherbereich von $a und $b geschehen, sonst würde $a auch 7
enthalten. Folglich muss hier bei einer Änderung neuer Speicher
alloziiert werden und $b weist nun auf diesen Speicher[1].

So, nun was bringt dir das?

1. Bei alten PHP-Versionen - wie ich aus dem Posting folgere - wird
   bei jeder Zuweisung neuer Speicher alloziiert.

$a = 5;     // einmal Speicher für $a, sprich der Wert '5'
   $b = $a;    // einmal Speicher für $b, auch für Wert '5'

2. Funktionsaufrufe:

  1. $a = 5;
  2. function getA($b) {
    4)   each $b
  3. }
  4. getA($a);
  5. undef($a);   // $a ist nun nicht mehr definiert

was geschieht hier?

1) Speicher für den Wert '5' wird alloziiert, $a entspricht diesem
    Speicherbereich (auf der Ebene von C ist es ein Pointer auf den
    Speicherbereich, s. [1])
 3) Das erste Argument wird in $b gespeichert. Nach der Kenntnis von
    oben braucht man also nicht den gesamten Inhalt von $a zu
    kopieren und in $b zu speichern, da $b nach getA($a) genau
    denselben Wert wie $a hat. $a und $b zeigen[1] einfach auf
    denselben Speicherbereich. Wenn man aber in getA() $b verändert,
    dann muss (frühestens) neuer Speicher alloziiert werden, um den
    neuen zugewiesenen Wert zu speichern.
 5) Die lokale Variable $b verlässt den Funktion-Scope und wird somit
    vernichtet. Der ReferenceCounter des Speicherbereichs für den
    Wert '5' wird also um 1 dekrementiert, da er nurmehr von $a
    "verwendet" wird.
 7) Funktionsaufruf. Der ReferenceCounter von $a wird um 1 erhöht,
    denn der Inhalt von $a wird nun auch von durch Variable $b
    "verwendet".
 8) Bei undef() (Perl-ish) wird eine Variable undefiniert, sprich
    sie existiert nachher nicht mehr. Zurück zu unserem PHP-Kontext
    hiesse dies jedoch nicht, dass der Wert nicht mehr anderswo
    noch definiert ist. Es findet hier lediglich ein weiterer
    decrement des Reference-Counters statt, in dem Beispiel oben
    würde er zurück auf 0 gehen. 0 heisst für PHP: Es gibt keine
    PHP-Variable mehr, die auf diesen Speicherbereich, wo '5'
    gespeichert ist, verweist und somit kann auch der gesamte
    Speicherbereich für den Wert '5' freigegeben werden.

Als zusätzliche Lektüre empfehle ich:
http://ch2.php.net/manual/de/language.references.php
insbesondere:
  http://www.zend.com/zend/art/ref-count.php

[1] Die Zuweisung oder die Referenz ist im PHP-Script selber
unsichtbar, dies geschieht auf der Ebene von C. Also nicht mit einer
PHP-Skalar-Referenz verwechseln. Ebenso will ich hier nicht den
Glauben herbeiführen, dass jeder vorkommende Wert genau in einem
Speicherbereich gespeichert ist, sondern jede Zuweisung einer
Variable zu einer anderen wird einfach durch ReferenceCounter auf
den neu-gemeinsamen Speicher gelöst.

Also: Ja, "Call-By-Reference" sind implizit, weil jede
Variablenzuweisung nur noch über inkrementieren und Zuweisung des
selben Speicherbereichs gelöst ist und nicht mehr einfach der gesamte
Inhalt kopiert wird, früher musste so ja bei jedem FunctionCall die
Variable kopiert werden, da die Variable in der Funktion verändert
werden konnte, _ohne_ Einfluss auf die Variable des caller-Kontextes,
ohne ReferenceCounter oder anderem GarbageCollection artet dies
eben in wilde Kopieraktionen bei jedem Funktionsaufruf aus (so wie
bei Call-By-Value).

Ich möchte dir jedoch darin wiedersprechen, dass dies "Call-By-
Reference automatisch?" ist. Es ist eben nicht Call-By-Reference,
sondern eine Konsequenz in der PHP-internen Repräsentation von Werten
und Variablen.

Hope That Helped ;)

Viele Grüsse

Philipp

--
If a project is completed on schedule, it wasn't debugged properly.