PHP 5.4 Call-Time-Pass-by-Reference - Einfache Lösung verfügbar?

219

Gibt es eine Möglichkeit, dieses Problem einfach zu beheben, oder muss ich wirklich den gesamten Legacy-Code neu schreiben?

Schwerwiegender PHP-Fehler: Die Referenz für die Anrufzeit wurde in ... in Zeile 30 entfernt

Dies geschieht überall, wenn Variablen als Referenzen im gesamten Code an Funktionen übergeben werden.

Bardiir
quelle

Antworten:

344

Sie sollten den Aufruf in der Funktionsdefinition als Referenz bezeichnen, nicht den tatsächlichen Aufruf. Da PHP die Versionalisierungsfehler in Version 5.3 anzeigt, würde ich sagen, dass es eine gute Idee wäre, den Code neu zu schreiben.

Aus der Dokumentation :

Bei einem Funktionsaufruf gibt es kein Referenzzeichen - nur bei Funktionsdefinitionen. Funktionsdefinitionen allein reichen aus, um das Argument korrekt als Referenz zu übergeben. Ab PHP 5.3.0 erhalten Sie eine Warnung, dass "Call-Time Pass-by-Reference" bei Verwendung &in veraltet ist foo(&$a);.

Zum Beispiel, anstatt zu verwenden:

// Wrong way!
myFunc(&$arg);               # Deprecated pass-by-reference argument
function myFunc($arg) { }

Verwenden:

// Right way!
myFunc($var);                # pass-by-value argument
function myFunc(&$arg) { }
Tim Cooper
quelle
9
Veraltet ist seit PHP 5.0.0, damals mit E_COMPILE_WARNINGLevel-Fehler, als Referenz: php.net/manual/en/…
hakre
5
Ich hatte diesen Fehler, musste aber das & insted des Hinzufügens zur Variablen entfernen.
Diana
2
Ich hatte dies im alten Code für ein Objekt namens event (& $ event) verwendet und musste das kaufmännische Und entfernen, damit die Fehlermeldung verschwindet.
Natalia
1
In all meinen Jahren als Entwickler musste ich & nie auf PHP verwenden. niemals. das war genau das, wonach ich gesucht habe. großartig
Juan Vilar
8
Beachten Sie für die Personen in den Kommentaren, dass das Entfernen des & zu unerwarteten Ergebnissen führen kann, da Änderungen an der Variablen nicht mehr freigegeben werden, sondern nur für den lokalen Funktionsbereich sichtbar sind. Wenn Sie also nicht wissen, was der Code bewirkt, würde ich empfehlen, ihn wie oben beschrieben zu reparieren, anstatt nur das & -Zeichen zu entfernen
xorinzor
8

Für alle, die dies wie ich lesen, weil sie ein riesiges Legacy-Projekt auf 5.6 aktualisieren müssen: Wie die Antworten hier zeigen, gibt es keine schnelle Lösung: Sie müssen wirklich jedes Auftreten des Problems manuell finden und beheben .

Der bequemste Weg, alle problematischen Zeilen in einem Projekt zu finden (abgesehen von der Verwendung eines vollständigen statischen Code-Analysators, der sehr genau ist, aber ich kenne keinen, der Sie sofort an die richtige Position im Editor bringt) verwendete Visual Studio Code, in den ein netter PHP-Linter integriert ist, und seine Suchfunktion, die die Suche nach Regex ermöglicht. (Natürlich können Sie dafür jeden IDE / Code-Editor verwenden, der PHP-Flusen und Regex-Suchen durchführt.)

Verwenden dieses regulären Ausdrucks:

^(?!.*function).*(\&\$)

Es ist möglich, projektweit nach dem Auftreten &$nur in Zeilen zu suchen , die keine Funktionsdefinition sind.

Dies führt immer noch zu vielen Fehlalarmen, erleichtert jedoch die Arbeit.

Der Suchergebnisbrowser von VSCode erleichtert das Durchsuchen und Auffinden der fehlerhaften Zeilen erheblich: Sie klicken einfach durch jedes Ergebnis und achten auf diejenigen, die der Linter rot unterstreicht. Die müssen Sie reparieren.

Pekka
quelle
1
Das habe ich gesucht!
Sonny
4
Genauere Regex verwende ich für diesen Zweck:(?<!function)[:> ][a-zA-Z0-9_]+(?<!foreach|array)\s?\([^()]*&\$
Mojo
Verwenden Sie einfach PHPCs, wird jede Datei, die dies für Sie hat, ausgraben.
Thomas Cheng
6

PHP und Referenzen sind etwas unintuitiv. Bei sachgemäßer Verwendung können Referenzen an den richtigen Stellen große Leistungsverbesserungen bewirken oder sehr hässliche Problemumgehungen und ungewöhnlichen Code vermeiden.

Folgendes führt zu einem Fehler:

 function f(&$v){$v = true;}
 f(&$v);

 function f($v){$v = true;}
 f(&$v);

Keines davon muss scheitern, da es den folgenden Regeln folgen könnte, aber zweifellos entfernt oder deaktiviert wurde, um eine Menge Verwirrung zu vermeiden.

Wenn sie funktioniert haben, beinhalten beide eine redundante Konvertierung in eine Referenz und die zweite beinhaltet auch eine redundante Konvertierung zurück in eine enthaltene Variable mit Gültigkeitsbereich.

Die zweite war früher möglich, um die Übergabe einer Referenz an Code zu ermöglichen, der nicht für die Verwendung mit Referenzen vorgesehen war. Dies ist für die Wartbarkeit äußerst hässlich.

Dies wird nichts tun:

 function f($v){$v = true;}
 $r = &$v;
 f($r);

Insbesondere wird die Referenz wieder in eine normale Variable umgewandelt, da Sie nicht nach einer Referenz gefragt haben.

Das wird funktionieren:

 function f(&$v){$v = true;}
 f($v);

Dadurch wird angezeigt, dass Sie eine Nichtreferenz übergeben, aber eine Referenz möchten, sodass diese in eine Referenz umgewandelt wird.

Dies bedeutet, dass Sie keinen Verweis auf eine Funktion übergeben können, bei der ein Verweis nicht explizit aufgefordert wird, ihn zu einem der wenigen Bereiche zu machen, in denen PHP die Übergabe von Typen strengstens einschränkt oder in diesem Fall eher einen Metatyp darstellt.

Wenn Sie ein dynamischeres Verhalten benötigen, funktioniert dies:

 function f(&$v){$v = true;}
 $v = array(false,false,false);
 $r = &$v[1];
 f($r);

Hier sehen Sie, dass Sie eine Referenz möchten und bereits eine Referenz haben, lassen Sie sie also in Ruhe. Es kann auch die Referenz verketten, aber ich bezweifle dies.

jgmjgm
quelle