Änderungen im Umgang mit Fehlern und Exceptions
Viele schwerwiegende und wiederherstellbare schwerwiegende Fehler wurden in
PHP 7 in Exceptions umgewandelt. Diese Fehler-Exceptions erben von der
Klasse Error, die ihrerseits die Schnittstelle
Throwable implementiert (die neue Basisschnittstelle,
die alle Exceptions erben).
Das bedeutet, dass benutzerdefinierte Funktionen für die Fehlerbehandlung
eventuell nicht mehr ausgelöst werden, da stattdessen Exceptions ausgelöst
werden (was neue schwerwiegende Fehler für nicht abgefangene
Error-Exceptions verursacht).
Eine genauere Beschreibung der Funktionsweise von Fehlern in PHP 7 ist auf
der Seite Fehler in PHP 7 zu
finden. Dieser Migrationsleitfaden zählt lediglich die Änderungen auf, die
die Abwärtskompatibilität betreffen.
Bei der Funktion set_exception_handler() ist nicht mehr
gewährleistet, dass sie Exception-Objekte erhält.
Code, der einen Exception-Handler mit der Funktion
set_exception_handler() unter Verwendung einer
Deklaration vom Typ Exception implementiert, führt
zu einem fatalen Fehler, wenn ein Error-Objekt
ausgelöst wird.
Wenn der Handler sowohl mit PHP 5 als auch mit PHP 7 funktionieren soll,
sollte die Typdeklaration aus dem Handler entfernt werden. Bei Code, der
migriert wird, um nur unter PHP 7 zu funktionieren, genügt es stattdessen,
die Exception-Typdeklaration durch
Throwable zu ersetzen.
Interne Konstruktoren lösen bei Fehlern immer Exceptions aus
Zuvor gaben einige interne Klassen null
oder ein unbrauchbares Objekt
zurück, wenn der Konstruktor fehlschlug. Alle internen Klassen lösen nun in
einem solchen Fall eine Exception aus, so wie es die
benutzerdefinierten Klassen bereits tun.
Parser-Fehler lösen ParseError aus
Parser-Fehler erzeugen nun ein ParseError-Objekt.
Die Fehlerbehandlung für eval() sollte einen
catch
-Block enthalten, der diesen Fehler behandeln kann.
Änderungen des Schweregrads von E_STRICT-Meldungen
Alle E_STRICT
-Meldungen wurden neu eingestuft. Die
Konstante E_STRICT
wurde beibehalten, sodass Aufrufe
wie error_reporting(E_ALL|E_STRICT)
keinen Fehler
verursachen.
Änderungen des Schweregrads von E_STRICT-Meldungen
Situation |
Neue Stufe/Verhalten |
Indizierung durch eine Ressource |
E_NOTICE |
Abstrakte statische Methoden |
Hinweis entfernt, löst keinen Fehler aus |
"Neudefinieren" eines Konstruktors |
Hinweis entfernt, löst keinen Fehler aus |
Inkompatible Signaturen bei der Vererbung |
E_WARNING |
Gleiche (kompatible) Eigenschaft in zwei verwendeten Traits |
Hinweis entfernt, löst keinen Fehler aus |
Nicht-statischer Zugriff auf eine statische Eigenschaft |
E_NOTICE |
Nur Variablen sollten per Referenz zugewiesen werden |
E_NOTICE |
Nur Variablen sollten per Referenz übergeben werden |
E_NOTICE |
Statischer Aufruf nicht-statischer Methoden |
E_DEPRECATED |
Änderungen beim Umgang mit Variablen
PHP 7 verwendet nun beim Parsen von Quelldateien einen abstrakten
Syntaxbaum. Dies hat viele Verbesserungen an der Sprache ermöglicht, die
zuvor aufgrund der Einschränkungen des Parsers in früheren PHP-Versionen
nicht möglich waren. Allerdings hat das auch dazu geführt, dass einige
Spezialfälle aus Gründen der Konsistenz entfernt wurden, was Brüche in der
Abwärtskompatibilität zur Folge hat. Diese Fälle werden in diesem Abschnitt
detailliert beschrieben.
Änderungen beim Umgang mit indirekten Variablen, Eigenschaften und Methoden
Der indirekte Zugriff auf Variablen, Eigenschaften und Methoden wird nun
in strikter Reihenfolge von links nach rechts ausgewertet. In früheren
Versionen war die Reihenfolge der Auswertung in einigen Fällen umgekehrt.
Die folgende Tabelle zeigt, wie sich die Reihenfolge der Auswertung
geändert hat.
Alte und neue Auswertung indirekter Ausdrücke
Ausdruck |
Auswertung in PHP 5 |
Auswertung in PHP 7 |
$$foo['bar']['baz']
|
${$foo['bar']['baz']}
|
($$foo)['bar']['baz']
|
$foo->$bar['baz']
|
$foo->{$bar['baz']}
|
($foo->$bar)['baz']
|
$foo->$bar['baz']()
|
$foo->{$bar['baz']}()
|
($foo->$bar)['baz']()
|
Foo::$bar['baz']()
|
Foo::{$bar['baz']}()
|
(Foo::$bar)['baz']()
|
Code, der die alte Auswertungsreihenfolge von rechts nach links verwendet,
muss mit geschweiften Klammern umgeschrieben werden, um explizit diese
Auswertungsreihenfolge zu verwenden (siehe die obige mittlere Spalte).
Dadurch wird der Code sowohl vorwärtskompatibel mit PHP 7.x als auch
rückwärtskompatibel mit PHP 5.x.
Dies betrifft auch das Schlüsselwort global
. Falls erforderlich, kann die
Syntax mit den geschweiften Klammern verwendet werden, um das frühere
Verhalten zu emulieren:
Änderungen im Umgang mit der Funktion list()
list() weist Variablen nicht mehr in umgekehrter
Reihenfolge zu
list() weist den Variablen nun Werte in der Reihenfolge
zu, in der sie definiert sind, und nicht mehr in umgekehrter Reihenfolge.
Wie unten gezeigt, betrifft dies im Allgemeinen nur Fälle, in denen
list() in Verbindung mit dem Array-Operator
[]
verwendet wird:
Im Allgemeinen ist es nicht empfehlenswert, sich auf die Reihenfolge zu
verlassen, in der die Zuweisungen mit list() erfolgen.
Das ist ein Implementierungs-Detail, das sich in der Zukunft wieder ändern
kann.
Leere list()-Zuweisungen wurden entfernt
list()-Konstrukte dürfen nicht mehr leer sein; die
Folgenden sind nicht mehr erlaubt:
Änderung der Reihenfolge von Array-Elementen, die automatisch durch
Zuweisung per Referenz erzeugt werden
Die Reihenfolge der Elemente eines Arrays, die automatisch durch Zuweisung
per Referenz erstellt werden, hat sich geändert. Zum Beispiel:
Klammern um Funktionsparameter haben keinen Einfluss mehr auf das Verhalten
Wenn in PHP 5 redundante Klammern um Funktionsparameter verwendet wurden,
konnte die Warnung wegen strikter Standards unterdrückt werden, indem der
Parameter per Referenz übergeben wurde. Nun wird die Warnung immer
angezeigt.
Änderungen bei foreach
Am Verhalten der Kontrollstruktur foreach wurden kleinere Änderungen
vorgenommen, die sich vor allem auf die Handhabung des internen
Array-Zeigers und auf die Änderung des Arrays, über das iteriert wird,
beziehen.
foreach ändert den internen Array-Zeiger nicht mehr
Vor PHP 7 wurde der interne Array-Zeiger verändert, während mit foreach
über ein Array iteriert wurde. Dies ist nun, wie im folgenden Beispiel
gezeigt wird, nicht mehr der Fall:
foreach iteriert bei Übergabe per Wert über eine Kopie des Arrays
Wenn foreach im Standardmodus Pass-by-Value verwendet wird, arbeitet es
nun mit einer Kopie des Arrays, über das iteriert wird, und nicht mit dem
Array selbst. Das bedeutet, dass Änderungen, die während des Iterierens am
Array vorgenommen werden, keine Auswirkungen auf die iterierten Werte haben.
Verbessertes Iterationsverhalten von foreach bei Übergabe per Referenz
Bei der Iteration per Referenz kann foreach Änderungen, die während des
Iterierens am Array vorgenommen werden, nun besser verfolgen. Wenn zum
Beispiel während des Iterierens etwas an das Array angehängt wird, führt
das dazu, dass nun auch über die angehängten Werte iteriert wird:
Änderungen im Umgang mit dem Typ int
Ungültige oktale Literale
Bisher wurden oktale Literale, die ungültige Zahlen enthielten,
stillschweigend abgeschnitten (0128
wurde als
012
interpretiert). Nun verursacht ein ungültiges
Oktal-Literal einen Parser-Fehler.
Negative Bitverschiebungen
Bitweises Verschieben um negative Zahlen führt nun zu einem
ArithmeticError:
Bitverschiebungen außerhalb des zulässigen Bereichs
Bitweise Verschiebungen (in beide Richtungen) über die Bitbreite eines
int ergeben immer 0. Bisher war das Verhalten solcher
Verschiebungen von der Architektur abhängig.
Änderungen bei der Division durch Null
Wenn 0 beim Divisionsoperator (/) oder beim Modulusoperator (%) als Divisor
verwendet wird, wurde bisher einen Fehler der Stufe E_WARNING ausgegeben
und false
zurückgegeben. Nun gibt der
Divisionsoperator, wie in IEEE 754 festgelegt, eine Gleitkommazahl entweder
als +INF, -INF oder NAN zurück. Der Modulusoperator gibt nun kein E_WARNING
mehr aus, sondern löst stattdessen eine
DivisionByZeroError-Exception aus.
Änderungen im Umgang mit dem Typ string
Hexadezimale Zeichenketten werden nicht mehr als numerisch betrachtet
Zeichenketten, die hexadezimale Zahlen enthalten, gelten nicht mehr als
numerisch. Zum Beispiel:
filter_var() kann verwendet werden, um zu prüfen, ob ein
string eine hexadezimale Zahl enthält, und auch zur Umwandlung einer
Zeichenkette dieses Typs zu einem int:
\u{
kann zu Fehlern führen
Mit der Einführung der neuen
Unicode-Codepoint-Maskierungssyntax
verursachen Zeichenketten, die \u{
gefolgt von einer
ungültigen Sequenz enthalten, einen fatalen Fehler. Um dies zu vermeiden,
sollte der führende Rückwärtsstrich maskiert werden.
Entfernte Funktionen
Alle ereg*-Funktionen
Alle ereg
-Funktionen wurden entfernt. Es wird empfohlen,
stattdessen PCRE zu verwenden.
Die veraltete Funktion mcrypt_generic_end() wurde
zugunsten von mcrypt_generic_deinit() entfernt.
Darüber hinaus wurden die veralteten Funktionen
mcrypt_ecb() mcrypt_cbc(),
mcrypt_cfb() und mcrypt_ofb()
zugunsten von mcrypt_decrypt() in Kombination
mit der entsprechenden MCRYPT_MODE_*
-Konstante
entfernt.
Alle ext/mysql-Funktionen
Alle ext/mysql-Funktionen wurden
entfernt. Details zur Auswahl einer anderen MySQL-API sind unter
Auswahl einer API zu finden.
Alle ext/mssql-Funktionen
Alle ext/mssql
-Funktionen wurden entfernt.
set_magic_quotes_runtime()
Die Funktion set_magic_quotes_runtime() und ihr Alias
magic_quotes_runtime() wurden entfernt. Sie sind seit
PHP 5.3.0 veraltet und praktisch nutzlos, seit in PHP 5.4.0 die magischen
Anführungszeichen entfernt wurden.
set_socket_blocking()
Der veraltete Alias set_socket_blocking() wurde
zugunsten von stream_set_blocking() entfernt.
dl() in PHP-FPM
Die Funktion dl() kann in PHP-FPM nicht mehr verwendet
werden. In CLI und integrierten SAPIs ist sie weiterhin verfügbar.
GD-Type1-Funktionen
Die PostScript-Type1-Schriftarten werden von der Erweiterung GD nicht mehr
unterstützt. Infolgedessen wurden die folgenden Funktionen entfernt:
-
imagepsbbox()
-
imagepsencodefont()
-
imagepsextendfont()
-
imagepsfreefont()
-
imagepsloadfont()
-
imagepsslantfont()
-
imagepstext()
Es wird empfohlen, stattdessen die TrueType-Schriftarten und die damit
verbundenen Funktionen zu verwenden.
Andere nicht abwärtskompatible Änderungen
Neue Objekte können nicht per Referenz zugewiesen werden
Es ist nicht mehr möglich, das Resultat einer new
-Anweisung per Referenz
einer Variablen zuzuweisen:
Ungültige Klassen-, Schnittstellen- und Traitnamen
Die folgenden Namen können nicht mehr zur Benennung von Klassen,
Schnittstellen und Traits verwendet werden:
Darüber hinaus sollten auch die folgenden Namen nicht verwendet werden.
Auch wenn sie in PHP 7.0 keinen Fehler erzeugen, sind sie für die
zukünftige Verwendung reserviert und sollten als veraltet angesehen werden.
Aufrufe aus inkompatiblen Kontexten wurden entfernt
Ein statischer Aufruf einer nicht-statischen Methode aus einem
inkompatiblen Kontext war
bereits in PHP 5.6 veraltet
und führt nun dazu, dass die aufgerufene Methode eine undefinierte
$this
-Variable hat und einen Veraltet-Hinweis ausgibt.
yield ist nun ein rechtsassoziativer Operator
Das yield-Konstrukt ist nun rechtsassoziativ (Auswertung von rechts nach
links) und es werden keine Klammern mehr benötigt. In der Rangfolge liegt
es nun zwischen print
und =>
.
Dadurch ändert sich das Verhalten wie folgt:
Um Unklarheiten zu beseitigen, können Klammern verwendet werden.
Eine Funktion kann nicht mehrere Parameter mit demselben Namen haben
Es ist nicht mehr möglich, in einer Funktion mehrere Parameter mit
demselben Namen zu definieren. Zum Beispiel führt eine Funktion wie die
folgende zu einem E_COMPILE_ERROR
:
Funktionen, die Parameter analysieren, melden den aktuellen Parameterwert
Die Funktionen func_get_arg(),
func_get_args() und debug_backtrace()
und Backtraces bei Exceptions melden nicht mehr den ursprünglichen Wert,
der an einen Parameter übergeben wurde, sondern stattdessen den aktuellen
Wert (der möglicherweise geändert wurde).
Switch-Anweisungen können nicht mehrere default-Blöcke haben
Es ist nicht mehr möglich, zwei oder mehr default-Blöcke in einer
switch-Anweisung zu definieren. Zum Beispiel löst die folgende
switch-Anweisung einen E_COMPILE_ERROR
aus:
$HTTP_RAW_POST_DATA wurde entfernt
$HTTP_RAW_POST_DATA ist nicht mehr verfügbar.
Stattdessen sollte der
php://input
-Stream
verwendet werden.
Erweiterung JSON durch JSOND ersetzt
Die Erweiterung JSON wurde durch JSOND ersetzt, was zu drei kleineren
Beeinträchtigungen in der Abwärtskompatibilität führt. Erstens darf eine
Zahl nicht mit einem Dezimalpunkt enden (d. h. 34.
muss
entweder durch 34.0
oder 34
ersetzt
werden). Zweitens darf bei Verwendung der wissenschaftlichen Notation der
Exponent e
nicht unmittelbar auf einen Dezimalpunkt
folgen (d. h. 3.e3
muss entweder durch
3.0e3
oder 3e3
ersetzt werden). Und
schließlich wird eine leere Zeichenkette nicht mehr als gültiges JSON
angesehen.
Interne Funktionen schlagen bei Überlauf fehl
Bisher haben interne Funktionen Zahlen, die von Gleitkommazahlen in
Ganzzahlen umgewandelt wurden, stillschweigend abgeschnitten, wenn die
Gleitkommazahl zu groß war, um sie als Ganzzahl darzustellen. Nun wird ein
Fehler der Stufe E_WARNING ausgegeben und null
zurückgegeben.
Korrekturen bei Rückgabewerten von benutzerdefinierten Session-Handlern
Eine Prädikatsfunktion, die von einem benutzerdefinierten Session-Handler
implementiert wird und entweder false
oder -1
zurückgibt, löst einen schwerwiegenden Fehler aus. Ist ein von dieser
Funktion zurückgegebener Wert nicht boolesch, -1
oder
0
, schlägt die Funktion fehl und löst einen Fehler der
Stufe E_WARNING aus.
Sortierreihenfolge gleichwertiger Elemente
Aufgrund von Verbesserungen des internen Sortieralgorithmus kann sich die
Sortierreihenfolge von Elementen, die beim Vergleich als gleichwertig
betrachtet werden, im Vergleich zu vorherigen Versionen ändern.
Hinweis:
Es wird davon abgeraten, sich auf die Reihenfolge der Elemente, die als
gleichwertig betrachtet werden, zu verlassen; sie kann sich jederzeit
ändern.
Falsch platzierte break- und continue-Anweisungen
break
- und continue
-Anweisungen
außerhalb einer Schleife oder einer
switch
-Kontrollstruktur werden nun bei der Kompilierung
erkannt, anstatt wie bisher zur Laufzeit, und lösen einen Fehler der Stufe
E_COMPILE_ERROR
aus.
Mhash ist keine Erweiterung mehr
Die Erweiterung Mhash wurde vollständig in die Erweiterung
Hash integriert. Daher ist es nicht mehr
möglich, mit extension_loaded() zu erkennen, ob Mhash
unterstützt wird. Stattdessen sollte function_exists()
verwendet werden. Darüber hinaus wird Mhash nicht mehr von
get_loaded_extensions() und ähnlichen Funktionen
gemeldet.
declare(ticks)
Die Directive
declare(ticks)
wird nicht mehr in verschiedene Kompilierungseinheiten übertragen.