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.
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.
<?php
// PHP-Code, der nicht mehr funktioniert
function handler(Exception $e) { ... }
set_exception_handler('handler');
// PHP 5 und 7 kompatibel
function handler($e) { ... }
// Nur PHP 7
function handler(Throwable $e) { ... }
?>
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 erzeugen nun ein ParseError-Objekt.
Die Fehlerbehandlung für eval() sollte einen
catch
-Block enthalten, der diesen Fehler behandeln kann.
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.
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 |
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.
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.
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:
<?php
function f() {
// Nur in PHP 5 gültig.
global $$foo->bar;
// In PHP 5 und 7 gültig.
global ${$foo->bar};
}
?>
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:
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
array(3) { [0]=> int(3) [1]=> int(2) [2]=> int(1) }
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
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.
list()-Konstrukte dürfen nicht mehr leer sein; die Folgenden sind nicht mehr erlaubt:
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
list() kann Variablen vom Typ string nicht mehr entpacken. Stattdessen sollte str_split() verwendet werden.
Die Reihenfolge der Elemente eines Arrays, die automatisch durch Zuweisung per Referenz erstellt werden, hat sich geändert. Zum Beispiel:
<?php
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
array(2) { ["b"]=> &int(1) ["a"]=> &int(1) }
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
array(2) { ["a"]=> &int(1) ["b"]=> &int(1) }
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.
<?php
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// Erzeugt in PHP 7 eine Warnung.
squareArray((getArray()));
?>
Das oben gezeigte Beispiel erzeugt folgende Ausgabe:
Notice: Only variables should be passed by reference in /tmp/test.php on line 13
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:
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
var_dump(current($array));
}
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
int(1) int(2) bool(false)
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
int(0) int(0) int(0)
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.
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:
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
int(0)
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
int(0) int(1)
Die Iteration über Objekte, die Traversable nicht implementieren, verhält sich nun genauso wie die Iteration über Arrays per Referenz. Dies führt dazu, dass das verbesserte Verhalten, wenn sich ein Array während des Iterierens ändert auch angewendet wird, wenn Eigenschaften zum Objekt hinzugefügt oder daraus entfernt werden.
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.
Bitweises Verschieben um negative Zahlen führt nun zu einem ArithmeticError:
<?php
var_dump(1 >> -1);
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
int(0)
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2 Stack trace: #0 {main} thrown in /tmp/test.php on line 2
Bitweise Verschiebungen (in beide Richtungen) über die Bitbreite eines int ergeben immer 0. Bisher war das Verhalten solcher Verschiebungen von der Architektur abhängig.
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.
<?php
var_dump(3/0);
var_dump(0/0);
var_dump(0%0);
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
Warning: Division by zero in %s on line %d bool(false) Warning: Division by zero in %s on line %d bool(false) Warning: Division by zero in %s on line %d bool(false)
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
Warning: Division by zero in %s on line %d float(INF) Warning: Division by zero in %s on line %d float(NAN) PHP Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %s line %d
Zeichenketten, die hexadezimale Zahlen enthalten, gelten nicht mehr als numerisch. Zum Beispiel:
<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
bool(true) bool(true) int(15) string(2) "oo"
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
bool(false) bool(false) int(0) Notice: A non well formed numeric value encountered in /tmp/test.php on line 5 string(3) "foo"
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:
<?php
$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
throw new Exception("Ungültige Ganzzahl!");
}
var_dump($int); // int(65535)
?>
\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.
Diese Funktionen sind seit PHP 4.1.0 zugunsten von
call_user_func() und
call_user_func_array() veraltet. Alternativ dazu
können auch die
Variablenfunktionen
und/oder der Operator
...
verwendet werden.
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 wurden entfernt. Details zur Auswahl einer anderen MySQL-API sind unter Auswahl einer API zu finden.
Alle ext/mssql
-Funktionen wurden entfernt.
Die veralteten Aliase datefmt_set_timezone_id() und IntlDateFormatter::setTimeZoneID() wurden zugunsten von datefmt_set_timezone() bzw. IntlDateFormatter::setTimeZone() entfernt.
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.
Der veraltete Alias set_socket_blocking() wurde zugunsten von stream_set_blocking() entfernt.
Die Funktion dl() kann in PHP-FPM nicht mehr verwendet werden. In CLI und integrierten SAPIs ist sie weiterhin verfügbar.
Die PostScript-Type1-Schriftarten werden von der Erweiterung GD nicht mehr unterstützt. Infolgedessen wurden die folgenden Funktionen entfernt:
Es wird empfohlen, stattdessen die TrueType-Schriftarten und die damit verbundenen Funktionen zu verwenden.
Die folgenden INI-Direktiven wurden entfernt, da ihre zugehörigen Funktionen ebenfalls entfernt wurden:
always_populate_raw_post_data
asp_tags
xsl.security_prefs
Die Direktive xsl.security_prefs
wurde entfernt.
Stattdessen sollte die Methode
XsltProcessor::setSecurityPrefs() aufgerufen werden,
um die Sicherheitseinstellungen auf Basis einzelner Prozessoren zu steuern.
Es ist nicht mehr möglich, das Resultat einer new
-Anweisung per Referenz
einer Variablen zuzuweisen:
<?php
class C {}
$c =& new C;
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3
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.
Es ist nicht mehr möglich, ASP-ähnliche Tags oder Skript-Tags zu verwenden, um PHP-Code einzuschließen. Die folgenden Tags sind hiervon betroffen:
Öffnendes Tag | Schließendes Tag |
---|---|
<% |
%> |
<%= |
%> |
<script language="php"> |
</script> |
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.
<?php
class A {
public function test() { var_dump($this); }
}
// Hinweis: Erweitert A NICHT
class B {
public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();
?>
Das oben gezeigte Beispiel erzeugt mit PHP 5.6 folgende Ausgabe:
Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8 object(B)#1 (0) { }
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8 Notice: Undefined variable: this in /tmp/test.php on line 3 NULL
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:
<?php
echo yield -1;
// Wurde zuvor interpretiert als
echo (yield) - 1;
// Und wird nun interpretiert als
echo yield (-1);
yield $foo or die;
// Wurde zuvor interpretiert als
yield ($foo or die);
// Und wird nun interpretiert als
(yield $foo) or die;
?>
Um Unklarheiten zu beseitigen, können Klammern verwendet werden.
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
:
<?php
function foo($a, $b, $unused, $unused) {
//
}
?>
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).
<?php
function foo($x) {
$x++;
var_dump(func_get_arg(0));
}
foo(1);?>
Das oben gezeigte Beispiel erzeugt mit PHP 5 folgende Ausgabe:
1
Das oben gezeigte Beispiel erzeugt mit PHP 7 folgende Ausgabe:
2
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:
<?php
switch (1) {
default:
break;
default:
break;
}
?>
$HTTP_RAW_POST_DATA ist nicht mehr verfügbar.
Stattdessen sollte der
php://input
-Stream
verwendet werden.
#
-Format entfernt
In INI-Dateien ist es nicht mehr möglich, Kommentare durch ein
vorangestelltes #
zu markieren. Stattdessen sollte
ein ;
(Semikolon) verwendet werden. Diese Änderung gilt
nicht nur für die php.ini, sondern auch für Dateien, die von
parse_ini_file() und
parse_ini_string() verarbeitet werden.
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.
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.
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.
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.
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.
Die Anweisungen break
und continue
erlauben keine Konstanten mehr als Argument und lösen einen
E_COMPILE_ERROR
aus.
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.
Die Directive declare(ticks) wird nicht mehr in verschiedene Kompilierungseinheiten übertragen.