Ist in PHP (>= 5.0) die Referenzübergabe schneller?

Lesezeit: 8 Minuten

Ist in PHP 50 die Referenzubergabe schneller
Hanno Fietz

In PHP können Funktionsparameter per Referenz übergeben werden, indem dem Parameter in der Funktionsdeklaration ein kaufmännisches Und vorangestellt wird, wie folgt:

function foo(&$bar)
{
    // ...
}

Jetzt ist mir bewusst, dass dies der Fall ist nicht entwickelt, um die Leistung zu verbessern, aber Funktionen zu ermöglichen, Variablen zu ändern, die normalerweise außerhalb ihres Gültigkeitsbereichs liegen.

Stattdessen scheint PHP Copy On Write zu verwenden, um zu vermeiden, dass Objekte (und möglicherweise auch Arrays) kopiert werden, bis sie geändert werden. Bei Funktionen, die ihre Parameter nicht ändern, sollte der Effekt also derselbe sein, als hätten Sie sie per Referenz übergeben.

Ich habe mich jedoch gefragt, ob die Copy On Write-Logik möglicherweise bei Pass-by-Reference kurzgeschlossen ist und ob dies Auswirkungen auf die Leistung hat.

ETA: Sicherlich gehe ich davon aus, dass es nicht schneller geht, und ich bin mir bewusst, dass Referenzen dafür nicht da sind. Also denke ich, dass meine eigenen Vermutungen ziemlich gut sind, ich suche nur nach einer Antwort von jemandem, der wirklich weiß, was definitiv unter der Haube passiert. In fünf Jahren PHP-Entwicklung fand ich es immer schwierig, qualitativ hochwertige Informationen über PHP-Interna zu bekommen, ohne die Quelle gelesen zu haben.

  • Siehe meine Frage für ein Beispiel, wo Referenzen die Dinge dramatisch verlangsamen können: stackoverflow.com/questions/3117604/…

    – John Carter

    30. Juni 2010 um 10:24 Uhr

Ist in PHP 50 die Referenzubergabe schneller
ikary

In einem Test mit 100 000 Iterationen zum Aufrufen einer Funktion mit einer Zeichenfolge von 20 kB sind die Ergebnisse:

Funktion, die nur den Parameter liest / verwendet

pass by value:      0.12065005 seconds
pass by reference:  1.52171397 seconds

Funktion zum Schreiben / Ändern des Parameters

pass by value:      1.52223396 seconds
pass by reference:  1.52388787 seconds

Schlussfolgerungen

  1. Übergeben Sie den Parameter als Wert ist immer schneller

  2. Wenn die Funktion den Wert der übergebenen Variablen ändert, ist das praktisch dasselbe wie eine Referenzübergabe als eine Wertübergabe

  • Das sind großartige Informationen, aber ich bin neugierig: Welche Version von PHP haben Sie für diesen Test verwendet?

    – Andrew Ensley

    23. Februar 2012 um 16:46 Uhr


  • Das macht nicht wirklich viel Sinn. Das ist eine wirklich sehr, sehr ineffiziente Handhabung von Referenzen.

    – Jonathan

    11. März 2013 um 6:05 Uhr


  • Siehe Antwort unten. Es spricht über die Verwendung großer Arrays und mehr.

    – Zeichnete LeSueur

    17. Oktober 2013 um 13:47 Uhr

  • Berücksichtigt dieser Test die zusätzliche Zeit, die eine Pass-by-Value-Funktion zum Kopieren und Zurückgeben des geänderten Werts benötigt?

    – Chris Middleton

    11. September 2014 um 18:52 Uhr

  • Ich habe festgestellt, dass das Übergeben von Referenzen langsam ist, wenn Sie die erhalten count() des Arrays in der Funktion, die das Array als Referenz abruft.

    – Zeichnete LeSueur

    21. Dezember 2016 um 0:18 Uhr

1646319858 955 Ist in PHP 50 die Referenzubergabe schneller
Paul Dixon

Die Zend-Engine verwendet Copy-on-Write, und wenn Sie selbst eine Referenz verwenden, entsteht ein wenig zusätzlicher Overhead. Kann nur finden diese Erwähnung zum Zeitpunkt des Schreibens und Kommentare in das Handbuch weitere Links enthalten.

(EDIT) Die Handbuchseite auf Objekte und Referenzen enthält ein wenig mehr Informationen darüber, wie sich Objektvariablen von Referenzen unterscheiden.

  • Sie sagen also, dass es tatsächlich der Leistung schadet (auch wenn die Auswirkungen vielleicht sehr unbedeutend sind)? Das ist interessant, danke!

    – Hanno Fietz

    7. Oktober 2008 um 13:25 Uhr

  • Der (etwas akademische) Gesamtleistungsverlust sollte nur auftreten, wenn Sie niemals die ursprüngliche Datenstruktur manipulieren. Wenn Sie es vorhaben, sollten Sie es tatsächlich tun gewinnen Leistung, da Sie Copy-on-Write vermeiden.

    – Tomalak

    7. Oktober 2008 um 14:05 Uhr

  • Ja, zugegeben, das ist ein bisschen akademisch. Es ist nur so, dass ich sehr frustriert war, weil ich missverstanden hatte, wie PHP intern funktioniert, und das hat mich ein bisschen pedantisch gemacht, es herauszufinden. Mir scheint, dass gute Quellen zu PHP-Interna schwieriger zu finden sind als bei anderen Sprachen, zB Python

    – Hanno Fietz

    7. Oktober 2008 um 19:06 Uhr

Ich habe einige Tests dazu durchgeführt, weil ich mir der gegebenen Antworten nicht sicher war.

Meine Ergebnisse zeigen, dass das Übergeben großer Arrays oder Zeichenfolgen als Referenz wesentlich schneller ist.

Hier sind meine Ergebnisse:
Benchmark

Die Y-Achse (Runs) gibt an, wie oft eine Funktion in 1 Sekunde * 10 aufgerufen werden könnte

Der Test wurde für jede Funktion/Variable 8 mal wiederholt

Und hier sind die Variablen, die ich verwendet habe:

$large_array = array_fill(PHP_INT_MAX / 2, 1000, 'a');
$small_array = array('this', 'is', 'a', 'small', 'array');
$large_object = (object)$large_array;
$large_string = str_repeat('a', 100000);
$small_string = 'this is a small string';
$value = PHP_INT_MAX / 2;

Das sind die Funktionen:

function pass_by_ref(&$var) {
}

function pass_by_val($var) {
}

  • Dieser Test spiegelt jedoch keinen realen Anwendungsfall wider. Leute übergeben oft per Referenz, wenn sie nicht mehrere Werte zurückgeben können, z. B. die Übergabe einer Referenz an ein Fehler-Array. Ein besserer Test wäre so etwas: function pass_by_ref($val, &$errors) { if($val < 0) { $errors []= "val < 0"; return false; } else return true; } … und … function pass_by_val($val, $errors) { if($val < 0) { $errors []= "val < 0"; return array("errors" => $errors, "result" => false); } else return array("errors" => $errors, "result" => true);}.

    – Chris Middleton

    11. September 2014 um 18:57 Uhr


  • wäre schön gewesen, auch Variationen zu haben, bei denen innerhalb des Arrays geändert wird und entweder die Änderungen zurückgegeben und erneut übernommen, durch Referenz zurückgegeben und erneut übernommen oder nicht zurückgegeben, sondern aufgrund des referenzierten Parameters erneut übernommen werden. nur sagen.

    – hakre

    25. Dezember 2014 um 12:30 Uhr

  • Keine der Funktionen ändert die Daten im Array.

    – David Spector

    24. Februar 2021 um 13:38 Uhr

Ich habe mit Werten und Referenzen von 10k-Byte-Strings experimentiert, die an zwei identische Funktionen übergeben wurden. Man nimmt das Argument als Wert und das zweite als Referenz. Sie waren allgemeine Funktionen – nehmen Sie ein Argument, führen Sie eine einfache Verarbeitung durch und geben Sie einen Wert zurück. Ich habe 100.000 Aufrufe von beiden durchgeführt und herausgefunden, dass Referenzen nicht darauf ausgelegt sind, die Leistung zu steigern – der Referenzgewinn lag bei 4-5 % und wächst nur, wenn die Zeichenfolge groß genug wird (100.000 und länger, das führte zu einer Verbesserung von 6-7 %). . Also, mein Fazit ist Verwenden Sie keine Referenzen, um die Leistung zu steigern, dafür ist dieses Zeug nicht da.

Ich habe PHP Version 5.3.1 verwendet

Ich bin mir ziemlich sicher, dass nein, es ist nicht schneller. Darüber hinaus heißt es im Handbuch ausdrücklich, nicht zu versuchen, Referenzen zur Leistungssteigerung zu verwenden.

Edit: Ich kann nicht finden, wo das steht, aber es ist da!

1646319859 906 Ist in PHP 50 die Referenzubergabe schneller
Bob Ray

Ich habe versucht, dies mit einem realen Beispiel zu vergleichen, das auf einem Projekt basiert, an dem ich arbeitete. Wie immer sind die Unterschiede trivial, aber die Ergebnisse waren etwas unerwartet. Bei den meisten Benchmarks, die ich gesehen habe, ändert die aufgerufene Funktion den übergebenen Wert nicht wirklich. Ich habe ein einfaches str_replace() darauf ausgeführt.

**Pass by Value Test Code:**

$originalString=''; // 1000 pseudo-random digits

function replace($string) {
    return str_replace('1', 'x',$string);
}
$output="";
/* set start time */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tstart = $mtime;
set_time_limit(0);

for ($i = 0; $i < 10; $i++ ) {
    for ($j = 0; $j < 1000000; $j++) {
        $string = $originalString;
        $string = replace($string);
    }
}

/* report how long it took */
$mtime = microtime();
$mtime = explode(" ", $mtime);
$mtime = $mtime[1] + $mtime[0];
$tend = $mtime;
$totalTime = ($tend - $tstart);
$totalTime = sprintf("%2.4f s", $totalTime);
$output .= "\n" . 'Total Time' .
    ': ' . $totalTime;
$output .= "\n" . $string;
echo $output;

Übergeben Sie den Referenztestcode

Das gleiche außer

function replace(&$string) {
    $string = str_replace('1', 'x',$string);
}
/* ... */
replace($string);

Ergebnisse in Sekunden (10 Millionen Iterationen):

PHP 5
    Value:     14.1007
    Reference: 11.5564

PHP 7
    Value:     3.0799
    Reference: 2.9489

Der Unterschied beträgt einen Bruchteil einer Millisekunde pro Funktionsaufruf, aber für diesen Anwendungsfall ist die Übergabe per Referenz sowohl in PHP 5 als auch in PHP 7 schneller.

(Hinweis: Die PHP 7-Tests wurden auf einem schnelleren Rechner durchgeführt – PHP 7 ist schneller, aber wahrscheinlich nicht viel schneller.)

1646319860 614 Ist in PHP 50 die Referenzubergabe schneller
Melsi

Es gibt nichts Besseres als ein Teststück Code

<?PHP
$r = array();

for($i=0; $i<500;$i++){
$r[]=5;
}

function a($r){
$r[0]=1;
}
function b(&$r){
$r[0]=1;
}

$start = microtime(true);
for($i=0;$i<9999;$i++){
  //a($r);
  b($r);
}
$end = microtime(true);

echo $end-$start;
?>

Endergebnis! Je größer das Array (oder je größer die Anzahl der Aufrufe), desto größer ist der Unterschied. In diesem Fall ist der Aufruf per Referenz also schneller, da der Wert innerhalb der Funktion geändert wird.

Ansonsten gibt es keinen wirklichen Unterschied zwischen “by reference” und “by value”, der Compiler ist schlau genug, nicht jedes Mal eine neue Kopie zu erstellen, wenn es nicht nötig ist.

  • Es könnte genauer sein, “Interpreter” statt “Compiler” zu sagen?

    – mpet

    11. September 2016 um 22:39 Uhr

  • Wenn Sie Benchmarks erstellen, zeigen Sie bitte die resultierenden Zeitwerte an. Da Sie testen, sollten Sie auch Ihre Behauptung getestet haben, dass es keine Rolle spielt, wenn kein Wert geändert wird. Andernfalls kann ein Leser nicht leicht feststellen, was Sie getestet haben, was Sie einfach behaupten.

    – WerkzeugmacherSteve

    18. Juli 2020 um 0:04 Uhr


924590cookie-checkIst in PHP (>= 5.0) die Referenzübergabe schneller?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy