Fehlermeldung "Strenge Standards: Nur Variablen sollten als Referenz übergeben werden"


81
$el = array_shift($instance->find(..))

Der obige Code meldet irgendwie die strenge Standardwarnung, aber dies wird nicht:

function get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Wann wird die Warnung überhaupt gemeldet?


1
Was gibt $ instance-> find (..) zurück?
Silver Light


Ich denke , die Beispiele (oder Logik) könnten falsch herum in der Frage sein, da das 2. Beispiel ( get_arr()Funktion) hat den strengen Standards Hinweis (getestet PHP 5.2 und PHP 5.5) erzeugen.
MrWhite

Antworten:


93

Betrachten Sie den folgenden Code:

error_reporting(E_STRICT);
class test {
    function test_arr(&$a) {
        var_dump($a);
    }
    function get_arr() {
        return array(1, 2);
    }
}

$t = new test;
$t->test_arr($t->get_arr());

Dadurch wird die folgende Ausgabe generiert:

Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

Der Grund? Die test::get_arr()Methode ist keine Variable und im strengen Modus wird eine Warnung generiert. Dieses Verhalten ist äußerst unintuitiv, da die get_arr()Methode einen Array-Wert zurückgibt .

Um diesen Fehler im strengen Modus zu umgehen, ändern Sie entweder die Signatur der Methode, sodass keine Referenz verwendet wird:

function test_arr($a) {
    var_dump($a);
}

Da Sie die Signatur von nicht ändern array_shiftkönnen, können Sie auch eine Zwischenvariable verwenden:

$inter = get_arr();
$el = array_shift($inter);

7
@ user198729: Ich habe nach einer Erklärung oder einem Fix gesucht und festgestellt, dass Sie current () für das erste Element verwenden können. Leider funktioniert end () nicht für das letzte Element, da es "den internen Zeiger auf das letzte Element vorschiebt". current (array_reverse (somefunction ())) funktioniert (ja, es ist albern)
MSpreij

1
Bei Verwendung currentwird davon ausgegangen, dass sich der Array-Zeiger am ersten Element befindet. In den meisten Fällen kann dies eine gültige Annahme sein, auf die Sie jedoch achten sollten.
cmbuckley

1
@leepowers Natürlich würde es dann das gleiche Problem geben, da array_shift()erwartet wird, dass ein Verweis
geändert wird

1
@ user198729 Sie können den $intermediateWert vermeiden, indem Sie ein zusätzliches Klammerpaar verwenden. $el = array_shift( ( get_arr() ) );. Siehe stackoverflow.com/questions/9848295/…
Chloe

1
@Chloe Dies ist die brillanteste Lösung, die ich je gesehen habe, um den Code einfach zu halten !! Danke dir!
Hargobind

7

$instance->find() Gibt einen Verweis auf eine Variable zurück.

Sie erhalten den Bericht, wenn Sie versuchen, diese Referenz als Argument für eine Funktion zu verwenden, ohne sie zuvor in einer Variablen zu speichern.

Dies hilft, Speicherlecks zu vermeiden und wird wahrscheinlich in den nächsten PHP-Versionen zu einem Fehler.

Ihr zweiter Codeblock würde einen Fehler auslösen, wenn er wie folgt geschrieben würde (beachten Sie die &in der Funktionssignatur):

function &get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Eine schnelle (und nicht so schöne) Lösung wäre also:

$el = array_shift($tmp = $instance->find(..));

Grundsätzlich weisen Sie zuerst eine temporäre Variable zu und senden die Variable als Argument.


Es sollte jetzt funktionieren (überprüft). Um eine Referenz zurückzugeben, müssen Sie diese bei der Methodensignatur deklarieren, nicht bei der Rückgabe (mein Fehler).
Sagi

Nein, ich kann die Signatur nicht ändern. Die Zwischenvariable von @ pygorex1 kann dies lösen, sieht aber überflüssig aus, nicht wahr?
user198729

Ich weiß, dass Sie die Signatur nicht ändern können. Ich habe nur erklärt, wie es passiert. Sie müssen eine temporäre (= Zwischen-) Variable verwenden, können dies jedoch in derselben Zeile tun. Schauen Sie sich mein zweites Code-Snippet an.
Sagi

4
Ich habe Ihr zweites Snippet ausprobiert, es funktioniert nicht. Es funktioniert nur in einer separaten Zeile
user198729

3
Tatsächlich. Eine Zuordnung gibt den zugewiesenen Wert zurück . array_shift($tmp = $instance->find(..))weist den Wert von $instance->find(..)zu $tmpund übergibt dann den Wert der Zuweisung an array_shift()- was nicht dasselbe ist wie das Übergeben $tmpselbst, also nicht besser als die ursprüngliche Situation ohne die Zuweisung.
Phils

6

Die Fehlerursache ist die Verwendung der internen PHP-Programmierdatenstrukturfunktion array_shift () [php.net/end].

Die Funktion verwendet ein Array als Parameter. Obwohl im Prototyp von array_shift()im Handbuch ein kaufmännisches Und angegeben ist , gibt es in der erweiterten Definition dieser Funktion weder eine Warnhinweisdokumentation noch eine offensichtliche Erklärung dafür, dass der Parameter tatsächlich als Referenz übergeben wird.

Vielleicht ist das / verstanden /. Ich habe es jedoch nicht verstanden, daher war es für mich schwierig, die Fehlerursache zu ermitteln.

Code reproduzieren:

function get_arr()
{
    return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);

3

Dieser Code:

$monthly_index = array_shift(unpack('H*', date('m/Y')));

Muss geändert werden in:

$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);


0

In solchen offensichtlichen Fällen können Sie PHP jederzeit anweisen, Nachrichten zu unterdrücken, indem Sie "@" vor der Funktion verwenden.

$monthly_index = @array_shift(unpack('H*', date('m/Y')));

Es ist möglicherweise nicht die beste Programmierpraxis, alle zu unterdrücken Fehler auf diese Weise , aber in bestimmten Fällen (wie diesem) ist es praktisch und akzeptabel.

Daher bin ich sicher, dass Ihr Freund "Systemadministrator" mit einem weniger verschmutzten zufrieden sein wird error.log.


Ich weiß nicht, wer diese Antwort abgelehnt hat, aber die vorgestellte Lösung funktioniert und es handelt sich um eine PHP-Standardtechnik. Wirklich enttäuschend ... Das nächste Mal könnte ich keine Frage mehr beantworten ... :(
Julio Marchi

5
Ich würde annehmen, dass dies daran liegt, dass das Unterdrücken der Fehlermeldung das Problem mit dem Code nicht behebt. Was werden Sie tun, wenn sich diese Art von Fehler in einer zukünftigen PHP-Version von E_STRICT zu E_ERROR ändert und Ihr Code jetzt nicht ausgeführt wird und auch keine Fehler / Ausgaben erzeugt?
Luke

@TinoDidriksen, ich verstehe und stimme den Gründen zu, von einigen "schlechten Gewohnheiten" abzuraten, insbesondere für die neuen Generationen. Es gibt jedoch eine Ressource, die verwendet werden kann, wenn (und wenn) sie sicher verwendet werden kann und auf den vorgeschlagenen Kontext anwendbar ist. Wenn der Fehlerunterdrücker "@" abgeschafft werden sollte, wäre er aus der Sprache selbst entfernt worden. Gleich wie "eval" (es mag böse sein, aber es hat seine Zwecke). Ich bin dagegen, dass es nicht um die Verwendung einiger Ressourcen geht, sondern um die Verallgemeinerung eines Ratschlags. Insbesondere für den vorgeschlagenen Fall wäre es nicht schädlich, ihn zu verwenden, auch nicht für Debugging-Zwecke.
Julio Marchi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.