PHP 8.4.1 Released!

Nicht abwärtskompatible Änderungen

PHP-Kern

Vergleich zwischen Zeichenketten und Zahlen

Einfache (nicht-strikte) Vergleiche zwischen Zahlen und nicht-numerischen Zeichenketten erfolgen nun durch Umwandlung der Zahl in eine Zeichenkette und den Vergleich der Zeichenketten. Vergleiche zwischen Zahlen und numerischen Zeichenketten funktionieren weiterhin wie bisher. Insbesondere bedeutet dies, dass 0 == "keine Zahl" nun als falsch angesehen wird.

Vergleich Vor der Änderung Nach der Änderung
0 == "0" true true
0 == "0.0" true true
0 == "foo" true false
0 == "" true false
42 == " 42" true true
42 == "42foo" true false

Andere inkompatible Änderungen

  • match ist nun ein reserviertes Schlüsselwort.

  • mixed ist nun ein reserviertes Wort, kann also nicht zur Benennung einer Klasse, Schnittstelle oder eines Traits verwendet werden und darf auch nicht in Namespaces verwendet werden.

  • Assertion-Fehler werden nun standardmäßig ausgelöst. Wenn das alte Verhalten gewünscht wird, kann in den INI-Einstellungen assert.exception=0 gesetzt werden.

  • Methoden mit dem gleichen Namen wie die Klasse werden nicht mehr als Konstruktoren interpretiert. Stattdessen sollte die Methode __construct() verwendet werden.

  • Die Möglichkeit, nicht-statische Methoden statisch aufzurufen, wurde entfernt. Deshalb schlägt is_callable() fehl, wenn eine nicht-statische Methode mit einem Klassennamen geprüft wird (muss mit einer Objektinstanz überprüft werden).

  • Die Typumwandlungen (real) und (unset) wurden entfernt.

  • Die INI-Direktive track_errors wurde entfernt. Das bedeutet, dass php_errormsg nicht mehr verfügbar ist. Stattdessen kann die Funktion error_get_last() verwendet werden.

  • Die Möglichkeit, Konstanten ohne Berücksichtigung der Groß- und Kleinschreibung zu definieren, wurde entfernt. Das dritte Argument von define() kann nicht mehr true sein.

  • Die Möglichkeit, einen Autoloader mit einer __autoload()-Funktion anzugeben, wurde entfernt. Stattdessen sollte spl_autoload_register() verwendet werden.

  • Der Parameter errcontext wird nicht mehr an benutzerdefinierte Fehlerbehandlungen übergeben, die mit der Funktion set_error_handler() gesetzt wurden.

  • Die Funktion create_function() wurde entfernt. Stattdessen können anonyme Funktionen verwendet werden.

  • Die Funktion each() wurde entfernt. Stattdessen sollte foreach oder ArrayIterator verwendet werden.

  • Die Möglichkeit, die Bindung von this an Closures aufzuheben, die mittels Closure::fromCallable() oder ReflectionMethod::getClosure() aus einer Methode erzeugt wurden, wurde entfernt.

  • Die Möglichkeit, die Bindung von this an echte Closures aufzuheben, die this verwenden, wurde ebenfalls entfernt.

  • Die Möglichkeit, die Funktion array_key_exists() mit Objekten zu verwenden, wurde entfernt. Stattdessen können isset() oder property_exists() verwendet werden.

  • Das Verhalten der Funktion array_key_exists() entspricht bezüglich des Typs des Parameters key nun dem Verhalten der Funktion isset() und dem normalen Array-Zugriff. Alle Schlüsseltypen unterliegen nun den üblichen Einschränkungen und Array- und Objektschlüssel lösen einen TypeError aus.

  • Jedes Array, das eine Zahl n als ersten numerischen Schlüssel hat, verwendet n+1 für seinen nächsten impliziten Schlüssel, auch wenn n negativ ist.

  • Die voreingestellte Stufe von error_reporting ist nun E_ALL; zuvor waren E_NOTICE und E_DEPRECATED ausgeschlossen.

  • display_startup_errors ist nun standardmäßig aktiviert.

  • Die Verwendung von parent innerhalb einer Klasse, die keine übergeordnete Klasse hat, führt nun bei der Kompilierung zu einem schweren Fehler.

  • Der Operator @ unterdrückt nun keine schweren Fehler (E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR und E_PARSE) mehr. Error-Handler, die erwarten, dass error_reporting 0 ist, wenn @ verwendet wird, sollten so angepasst werden, dass sie stattdessen die Fehler-Maske prüfen:

    <?php
    // Dies ersetzen
    function my_error_handler($err_no, $err_msg, $filename, $linenum) {
    if (
    error_reporting() == 0) {
    return
    false;
    }
    // ...
    }

    // mit Folgendem
    function my_error_handler($err_no, $err_msg, $filename, $linenum) {
    if (!(
    error_reporting() & $err_no)) {
    return
    false;
    }
    // ...
    }
    ?>

    Darüber hinaus sollte in Produktivumgebungen darauf geachtet werden, dass keine Fehlermeldungen angezeigt werden, da dies zu Informationslecks führen kann. Es sollte sichergestellt werden, dass in Verbindung mit der Fehleraufzeichnung display_errors=Off verwendet wird.

  • #[ wird nicht mehr als Beginn eines Kommentars interpretiert, weil diese Syntax nun für Attribute verwendet wird.

  • Vererbungsfehler aufgrund von inkompatiblen Methodensignaturen (Verletzung des Liskovschen Substitutionsprinzip, LSP) führen nun immer zu einem schweren Fehler. Vorher wurde in manchen Fällen eine Warnung erzeugt.

  • Die Rangfolge des Verkettungsoperators hat sich gegenüber Bitverschiebungen sowie Addition und Subtraktion geändert.

    <?php
    echo "Summe: " . $a + $b;
    // wurde früher wie folgt interpretiert:
    echo ("Summe: " . $a) + $b;
    // wird nun interpretiert als:
    echo "Summe: " . ($a + $b);
    ?>

  • Ein Parameter mit einem Standardwert, der bei der Ausführung zu null aufgelöst wird, wird nicht mehr implizit als nullbarer Parameter gekennzeichnet. Stattdessen muss explizit entweder ein nullbarer Typ oder der Standardwert null verwendet werden.

    <?php
    // Dies ersetzen
    function test(int $arg = CONST_RESOLVING_TO_NULL) {}
    // mit
    function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
    // oder
    function test(int $arg = null) {}
    ?>

  • Einige Warnungen wurden in Error-Exceptions umgewandelt:

    • Der Versuch, in eine Eigenschaft eines Nicht-Objekts zu schreiben. Zuvor wurde dadurch implizit ein stdClass-Objekt für null, false und leere Zeichenketten erstellt.
    • Der Versuch, ein Element an ein Array anzuhängen, für das bereits der Schlüssel PHP_INT_MAX verwendet wird.
    • Der Versuch, einen ungültigen Typ (Array oder Objekt) als Array-Schlüssel oder Zeichenketten-Offset zu verwenden.
    • Der Versuch, in einen Array-Index eines skalaren Wertes zu schreiben.
    • Der Versuch, ein Nicht-Array/Traversable zu entpacken.
    • Der Versuch, auf unqualifizierte Konstanten zuzugreifen, die nicht definiert sind. Zuvor führten Zugriffe auf unqualifizierte Konstanten zu einer Warnung und wurden als Zeichenketten interpretiert.
    • Wenn die falsche Anzahl von Argumenten an eine interne Funktion übergeben wird, die keinen Parameter mit variabler Länge hat, wird ein ArgumentCountError geworfen.
    • Wenn ungültige zählbare Typen an count() übergeben werden, wird ein TypeError geworfen.

    Einige Hinweise wurden in Warnungen umgewandelt:

    • Der Versuch, eine undefinierte Variable zu lesen.
    • Der Versuch, eine undefinierte Eigenschaft zu lesen.
    • Der Versuch, einen undefinierten Array-Schlüssel zu lesen.
    • Der Versuch, eine Eigenschaft eines Nicht-Objekts zu lesen.
    • Der Versuch, auf einen Array-Index eines Nicht-Arrays zuzugreifen.
    • Der Versuch, ein Array in eine Zeichenkette zu konvertieren.
    • Der Versuch, eine Ressource als Array-Schlüssel zu verwenden.
    • Der Versuch, null, einen Boolean oder einen Float als Zeichenketten-Offset zu verwenden.
    • Der Versuch, einen Zeichenketten-Offset zu lesen, der außerhalb des zulässigen Bereichs liegt.
    • Der Versuch, einem Zeichenketten-Offset eine leere Zeichenkette zuzuweisen.

  • Der Versuch, einem Zeichenketten-Offset mehrere Bytes zuzuweisen, führt nun zu einer Warnung.

  • Unerwartete Zeichen in Quelldateien (z. B. NUL-Bytes außerhalb von Zeichenketten) führen nun statt zu einer Warnung beim Kompilieren zu einer ParseError-Exception.

  • Nicht abgefangene Exceptions durchlaufen nun einen "sauberen Shutdown", was bedeutet, dass nach einer nicht abgefangenen Exception die Destruktoren aufgerufen werden.

  • Der bei der Kompilierung auftretende schwere Fehler "Only variables can be passed by reference" wurde in die Laufzeit verschoben und in die Error-Exception "Argument cannot be passed by reference" umgewandelt.

  • Einige "Only variables should be passed by reference"-Hinweise wurden in die Exception "Argument cannot be passed by reference" umgewandelt.

  • Der für anonyme Klassen erzeugte Name hat sich geändert. Er enthält nun den Namen des ersten Elternteils oder der ersten Schnittstelle:

    <?php
    new class extends ParentClass {};
    // -> ParentClass@anonymous
    new class implements FirstInterface, SecondInterface {};
    // -> FirstInterface@anonymous
    new class {};
    // -> class@anonymous
    ?>

    Auf den oben gezeigten Namen folgen noch ein NUL-Byte und ein eindeutiges Suffix.

  • Verweise auf nicht-absolute Trait-Methoden in Anpassungen von Trait-Aliasen müssen nun eindeutig sein:

    <?php
    class X {
    use
    T1, T2 {
    func as otherFunc;
    }
    function
    func() {}
    }
    ?>

    Wenn sowohl T1::func() als auch T2::func() existieren, wurde dieser Code bisher stillschweigend akzeptiert, und es wurde angenommen, dass func sich auf T1::func bezieht. Nun erzeugt er stattdessen einen schweren Fehler und es muss explizit entweder T1::func oder T2::func geschrieben werden.

  • Die Signatur von abstrakten Methoden, die in Traits definiert sind, wird nun anhand der Methode der implementierenden Klasse überprüft:

    <?php
    trait MyTrait {
    abstract private function
    neededByTrait(): string;
    }

    class
    MyClass {
    use
    MyTrait;

    // Fehler, da der Rückgabetyp nicht übereinstimmt.
    private function neededByTrait(): int { return 42; }
    }
    ?>

  • Deaktivierte Funktionen werden nun genauso behandelt wie nicht existierende Funktionen. Wenn eine deaktivierte Funktion aufgerufen wird, wird sie als unbekannt gemeldet, und es ist nun möglich, eine deaktivierte Funktion neu zu definieren.

  • data://-Stream-Wrapper sind nicht mehr beschreibbar, was dem dokumentierten Verhalten entspricht.

  • Die arithmetischen und bitweisen Operatoren +, -, *, /, **, %, <<, >>, &, |, ^, ~, ++ und -- lösen nun ausnahmslos einen TypeError aus, wenn einer der der Operanden ein Array, eine Ressource oder ein nicht überladenes Objekt ist. Die einzige Ausnahme hiervon ist die Array-Zusammenführung Array + Array, die weiterhin unterstützt wird.

  • Die Umwandlung vom Typ Float in den Typ String erfolgt nun immer unabhängig von der Locale.

    <?php
    setlocale
    (LC_ALL, "de_DE");
    $f = 3.14;
    echo
    $f, "\n";
    // Vorher: 3,14
    // Jetzt: 3.14
    ?>

    Siehe printf(), number_format() und NumberFormatter() für Möglichkeiten, die Formatierung von Zahlen anzupassen.

  • Die Unterstützung für die veraltete Verwendung von geschweiften Klammern für den Offset-Zugriff wurde entfernt.

    <?php
    // Anstelle von:
    $array{0};
    $array{"key"};
    // schreiben Sie:
    $array[0];
    $array["key"];
    ?>

  • Wenn der final-Modifikator auf eine private Methode angewendet wird, wird nun eine Warnung erzeugt, es sei denn, die Methode ist der Konstruktor.

  • Wenn im Konstruktor eines Objekts exit() aufgerufen wird, wird der Destruktor des Objekts nicht mehr aufgerufen. Dies entspricht dem Verhalten, wenn ein Konstruktor eine Exception auslöst.

  • Namen mit Bezug auf einen Namensraum dürfen keine Leerzeichen mehr enthalten: Während Foo\Bar als Namensraum-Name erkannt wird, wird Foo \ Bar nicht erkannt. Umgekehrt sind reservierte Schlüsselwörter nun als Namensraumsegmente erlaubt, was auch die Interpretation des Codes verändern kann: new\x ist nun gleichbedeutend mit constant('new\x'), nicht mit new \x().

  • Verschachtelte ternäre Ausdrücke müssen nun explizit in Klammern gesetzt werden.

  • Die Funktionen debug_backtrace() und Exception::getTrace() referenzieren nun keine Parameter mehr. Es ist nicht mehr möglich, über einen Backtrace die Parameter einer Funktion zu ändern.

  • Die Handhabung numerischer Zeichenketten wurde geändert, damit sie intuitiver und weniger fehleranfällig ist. Nachfolgende Leerzeichen sind nun in numerischen Zeichenketten erlaubt, um mit der Behandlung von führenden Leerzeichen übereinzustimmen. Dies betrifft hauptsächlich:

    • Die Funktion is_numeric()
    • Vergleiche zwischen Zeichenketten
    • Typdeklarationen
    • Inkrement- und Dekrement-Operationen

    Das Konzept einer "vorangestellten numerischen Zeichenkette" wurde größtenteils aufgegeben; die Fälle, in denen dies beibehalten wird, dienen dazu, die Umstellung zu erleichtern. Zeichenketten, die eine E_NOTICE "A non well-formed numeric value encountered" ausgaben, geben nun eine E_WARNING "A non-numeric value encountered" aus, und alle Zeichenketten, die eine E_WARNING "A non-numeric value encountered" ausgaben, lösen nun einen TypeError aus. Dies betrifft vor allem:

    • Arithmetische Operationen
    • Bitweise Operationen

    Diese Änderung von E_WARNING zu TypeError betrifft auch die E_WARNING "Illegal string offset 'string'" für unzulässige Zeichenketten-Offsets. Das Verhalten von expliziten Umwandlungen von Zeichenketten in int/float hat sich nicht geändert.

  • Magische Methoden werden nun auf ihre Parameter und Rückgabetypen geprüft, falls sie diese deklariert haben. Die Signaturen sollten der folgenden Liste entsprechen:

    • __call(string $name, array $arguments): mixed
    • __callStatic(string $name, array $arguments): mixed
    • __clone(): void
    • __debugInfo(): ?array
    • __get(string $name): mixed
    • __invoke(mixed $arguments): mixed
    • __isset(string $name): bool
    • __serialize(): array
    • __set(string $name, mixed $value): void
    • __set_state(array $properties): object
    • __sleep(): array
    • __unserialize(array $data): void
    • __unset(string $name): void
    • __wakeup(): void

  • Array-Schlüssel, die an die Funktion call_user_func_array() übergeben werden, werden nun als Namen der Parameter interpretiert. In früheren Versionen wurden sie stillschweigend ignoriert.

  • Die Deklaration einer Funktion namens assert() innerhalb eines Namensraums ist nicht mehr erlaubt und erzeugt einen E_COMPILE_ERROR. Die Funktion assert() unterliegt einer speziellen Verarbeitung durch die Engine, was zu einem inkonsistenten Verhalten führen kann, wenn eine Funktion mit demselben Namen innerhalb eines Namensraums definiert wird.

Umstellung von Ressourcen auf Objekte

Mehrere Ressourcen wurden in Objekte umgewandelt. Die Überprüfung des Rückgabewerts mit der Funktion is_resource() sollte durch eine Überprüfung auf false ersetzt werden.

COM und .Net (Windows)

Die Möglichkeit, Konstanten ohne Berücksichtigung der Groß-/Kleinschreibung aus Typbibliotheken zu importieren, wurde entfernt. Das zweite Argument der Funktion com_load_typelib() kann nicht mehr false sein; com.autoregister_casesensitive kann nicht mehr deaktiviert werden. Das bedeutet, dass #case_insensitive-Markierungen in com.typelib_file ignoriert werden.

CURL

CURLOPT_POSTFIELDS akzeptiert keine Objekte mehr als Arrays. Um ein Objekt als Array zu interpretieren, muss eine explizite Umwandlung mittels (array) durchgeführt werden. Dasselbe gilt auch für andere Optionen, die Arrays akzeptieren.

Datum und Uhrzeit

Die Funktionen mktime() und gmmktime() benötigen nun mindestens einen Parameter. Die Funktion time() kann verwendet werden, um den aktuellen Zeitstempel zu erhalten.

DOM

Nicht implementierte Klassen aus der Erweiterung DOM, die keinerlei Funktion hatten und Testdaten enthielten, wurden entfernt. Diese Klassen wurden auch aus der neuesten Version des des DOM-Standards entfernt:

  • DOMNameList
  • DomImplementationList
  • DOMConfiguration
  • DomError
  • DomErrorHandler
  • DOMImplementationSource
  • DOMLocator
  • DOMUserDataHandler
  • DOMTypeInfo
  • DOMStringExtend

Nicht implementierte Methoden aus der Erweiterung DOM, die keinerlei Funktion hatten, wurden entfernt:

  • DOMNamedNodeMap::setNamedItem()
  • DOMNamedNodeMap::removeNamedItem()
  • DOMNamedNodeMap::setNamedItemNS()
  • DOMNamedNodeMap::removeNamedItemNS()
  • DOMText::replaceWholeText()
  • DOMNode::compareDocumentPosition()
  • DOMNode::isEqualNode()
  • DOMNode::getFeature()
  • DOMNode::setUserData()
  • DOMNode::getUserData()
  • DOMDocument::renameNode()

Enchant

Exif

Die Funktion read_exif_data() wurde entfernt; stattdessen sollte die Funktion exif_read_data() verwendet werden.

Filter

GD

  • Die veraltete Funktion image2wbmp() wurde entfernt.

  • Die veralteten Funktionen png2wbmp() und jpeg2wbmp() wurden entfernt.

  • Bei der Funktion imagecropauto() akzeptiert der Standardparameter mode den Wert -1 nicht mehr. Stattdessen sollte IMG_CROP_DEFAULT verwendet werden.

  • Unter Windows wurde die Datei php_gd2.dll in php_gd.dll umbenannt.

GMP

Die Funktion gmp_random() wurde entfernt. Stattdessen sollte eine der Funktionen gmp_random_range() und gmp_random_bits() verwendet werden.

Iconv

iconv-Implementierungen, die errno beim Auftreten von Fehlern nicht korrekt setzen, werden nicht mehr unterstützt.

IMAP

Funktionen für die Internationalisierung

  • Die veraltete Konstante INTL_IDNA_VARIANT_2003 wurde entfernt.

  • Die veraltete Konstante Normalizer::NONE wurde entfernt.

LDAP

MBString

OCI8

  • Die Klassen OCI-Lob und OCI-Collection wurden umbenannt in OCILob bzw. OCICollection, um die Namenskonformität zu gewährleisten, die in PHP 8 durch die arginfo-Tools für Anmerkungen zum Typ (arginfo type annotation tooling) erzwungen wird.

  • Mehrere Alias-Funktionen wurden als veraltet markiert.

  • Die Funktion oci_internal_debug() und ihr Alias ociinternaldebug() wurden entfernt.

ODBC

  • Die Funktion odbc_connect() verwendet Verbindungen nicht mehr wieder.

  • Bei der Funktion odbc_exec() wurde der nicht verwendete Parameter flags entfernt.

OpenSSL

  • Den Funktionen openssl_seal() und openssl_open() muss nun der Parameter method übergeben werden, da der bisherige Standardwert "RC4" als unsicher eingestuft wird.

Reguläre Ausdrücke (Perl-kompatibel)

Wenn ungültige Escape-Sequenzen übergeben werden, werden sie nicht mehr als Literale interpretiert. Dieses Verhalten erforderte bisher den Modifikator X, der nun ignoriert wird.

PHP Data Objects

  • Der Standardmodus für die Fehlerbehandlung wurde von "silent" auf "exceptions" geändert. Siehe Fehler und Fehlerbehandlung für Details.

  • Die Signaturen einiger PDO-Methoden haben sich geändert:

    • PDO::query(string $query, ?int $fetchMode = null, mixed ...$fetchModeArgs)
    • PDOStatement::setFetchMode(int $mode, mixed ...$args)

PDO-ODBC

Die php.ini-Direktive pdo_odbc.db2_instance_name wurde entfernt.

PDO-MySQL

Die Methode PDO::inTransaction() meldet nun den tatsächlichen Transaktionsstatus der Verbindung, anstatt einer ungefähren Angabe, die von PDO verwaltet wird. Wenn eine Abfrage mit einem "impliziten Commit" ausgeführt wird, gibt PDO::inTransaction() anschließend false zurück, da die Transaktion nicht mehr aktiv ist.

PostgreSQL

  • Die veraltete pg_connect()-Syntax mit mehreren Parametern anstelle einer Verbindungszeichenkette wird nicht mehr unterstützt.

  • Die veraltete Signatur von pg_lo_import() und pg_lo_export(), die die Verbindung als letzten Parameter übergibt, wird nicht mehr unterstützt. Die Verbindung sollte stattdessen als erster Parameter übergeben werden.

  • Die Funktion pg_fetch_all() gibt für Ergebnismengen mit null Zeilen nun ein leeres Array statt false zurück.

Phar

Um mögliche Sicherheitslücken aufgrund von Objektinstanziierung, Autoloading usw. zu schließen, werden Metadaten, die mit phar verknüpft sind, nicht mehr automatisch deserialisiert.

Reflection

  • Die Signaturen der Methoden

    • ReflectionClass::newInstance($args)
    • ReflectionFunction::invoke($args)
    • ReflectionMethod::invoke($object, $args)

    wurden geändert in:

    • ReflectionClass::newInstance(...$args)
    • ReflectionFunction::invoke(...$args)
    • ReflectionMethod::invoke($object, ...$args)

    Code, der sowohl mit PHP 7 als auch mit PHP 8 kompatibel sein muss, kann die folgenden Signaturen verwenden, um mit beiden Versionen kompatibel zu sein:

    • ReflectionClass::newInstance($arg = null, ...$args)
    • ReflectionFunction::invoke($arg = null, ...$args)
    • ReflectionMethod::invoke($object, $arg = null, ...$args)

  • Die Methode ReflectionType::__toString() gibt nun eine vollständige Debug-Darstellung des Typs zurück und ist nicht mehr veraltet. Insbesondere enthält das Ergebnis bei nullbaren Typen den Hinweis, der anzeigt, dass null zugewiesen werden kann. Das Format des Rückgabewertes ist nicht stabil und kann sich zwischen den PHP-Versionen ändern.

  • Die export()-Methoden von Reflection wurden entfernt. Stattdessen können Reflection-Objekte in Zeichenketten umgewandelt werden.

  • Die Methoden ReflectionMethod::isConstructor() und ReflectionMethod::isDestructor() geben nun auch für die Schnittstellenmethoden __construct() und __destruct() true zurück. Zuvor galt dies nur für Methoden von Klassen und Traits.

  • Die Methode ReflectionType::isBuiltin() wurde in die Klasse ReflectionNamedType verschoben. Die Klasse ReflectionUnionType verfügt nicht über diese Methode.

Sockets

  • Bei der Funktion socket_addrinfo_lookup() wurden die veralteten flags AI_IDN_ALLOW_UNASSIGNED und AI_IDN_USE_STD3_ASCII_RULES entfernt.

Standard-PHP-Bibliothek (SPL)

Standard-Bibliothek

  • Die Funktion assert() wertet Zeichenketten-Parameter nicht mehr aus. Stattdessen werden sie genauso behandelt wie jeder andere Parameter. Statt assert('$a == $b') sollte assert($a == $b) verwendet werden. Außerdem wurden die INI-Direktive assert.quiet_eval und die Konstante ASSERT_QUIET_EVAL entfernt, weil sie keine Wirkung mehr haben.

  • Die Funktion parse_str() kann nicht mehr ohne Angabe eines Ergebnis-Arrays verwendet werden.

  • Der Filter string.strip_tags wurde entfernt.

  • Der Parameter needle der Funktionen strpos(), strrpos(), stripos(), strripos(), strstr(), strchr(), strrchr() und stristr() wird nun immer als Zeichenkette interpretiert. Zuvor wurde needle als ASCII-Codepunkt interpretiert, wenn es keine Zeichenkette war. Das vorherige Verhalten kann durch einen expliziten Aufruf von chr() wiederhergestellt werden.

  • Bei den Funktionen strpos(), strrpos(), stripos(), strripos(), strstr(), stristr() und strrchr() darf der Parameter needle nun leer sein.

  • Bei den Funktionen substr(), substr_count(), substr_compare() und iconv_substr() darf der Parameter length nun null sein. Wenn null angegeben wird, verhalten sich die Funktionen so, als ob der Parameter für die Länge nicht angegeben worden wäre. Daher wird in diesem Fall anstelle einer leeren Zeichenkette der Rest der Zeichenkette zurückgegeben.

  • Bei der Funktion array_splice() darf der Parameter length nun null sein. Wenn null angegeben wird, verhält sich die Funktion so, als ob der Parameter nicht angegeben worden wäre. Daher löscht die Funktion in diesem Fall alles von offset bis zum Ende des Arrays.

  • Bei den Funktionen vsprintf(), vfprintf() und vprintf() muss der Parameter args nun ein Array sein. Zuvor wurde jeder Typ akzeptiert.

  • Bei der Funktion password_hash() wird die Option 'salt' nicht mehr unterstützt. Wenn die Option 'salt' verwendet wird, wird eine Warnung erzeugt und das angegebene Salz wird ignoriert und stattdessen ein generiertes Salz verwendet.

  • Die Funktion quotemeta() gibt nun eine leere Zeichenkette zurück, wenn eine leere Zeichenkette übergeben wurde. Zuvor wurde false zurückgegeben.

  • Die folgenden Funktionen wurden entfernt:

  • Die Konstante FILTER_SANITIZE_MAGIC_QUOTES wurde entfernt.

  • Der Aufruf der Funktion implode() mit Parametern in umgekehrter Reihenfolge ($pieces, $glue) wird nicht mehr unterstützt.

  • Die Funktion parse_url() unterscheidet nun zwischen fehlenden und leeren Anfragen und Fragmenten:

    • http://example.com/foo → query = null, fragment = null
    • http://example.com/foo? → query = "", fragment = null
    • http://example.com/foo# → query = null, fragment = ""
    • http://example.com/foo?# → query = "", fragment = ""
    Zuvor waren query und fragment in allen oben genannten Fällen null.

  • Die Funktionen var_dump() und debug_zval_dump() geben Gleitkommazahlen nun aus, indem sie serialize_precision statt precision verwenden. Bei einer Standardkonfiguration bedeutet dies, dass Gleitkommazahlen von diesen Debugging-Funktionen nun mit voller Genauigkeit ausgegeben werden.

  • Wenn das von __sleep() zurückgegebene Array nicht existierende Eigenschaften enthält, werden diese nun stillschweigend ignoriert. Zuvor wurden solche Eigenschaften so serialisiert, als hätten sie den Wert null.

  • Beim Start ist die Standard-Locale nun immer "C". Standardmäßig werden keine Locales von der Umgebung übernommen. Zuvor war LC_ALL auf "C" gesetzt, während LC_CTYPE von der Umgebung übernommen wurde. Allerdings haben einige Funktionen die übernommene Locale ohne expliziten Aufruf von setlocale() nicht berücksichtigt. Ein expliziter Aufruf von setlocale() ist nun immer erforderlich, wenn eine Komponente der Locale von ihrem Standardwert abweichen soll.

  • In der Funktion crypt() wurde der veraltete DES-Fallback entfernt. Wenn ein unbekanntes Salt-Format an crypt() übergeben wird, schlägt die Funktion nun mit *0 fehl, anstatt auf einen schwachen DES-Hash zurückzugreifen.

  • Die Funktion crypt() schlägt bei der Angabe von Runden, die außerhalb des Bereichs für SHA256/SHA512 liegen, nun mit *0 fehl, anstatt auf die nächstgelegene Grenze zu setzen. Dies entspricht dem Verhalten der glibc.

  • Das Ergebnis von Sortierfunktionen kann sich ändern, wenn das Array Elemente enthält, die als gleich bewertet werden.

  • Alle für Callbacks geeigneten Funktionen, bei denen nicht explizit angegeben ist, dass sie per Referenz übergebene Parameter akzeptieren, geben nun eine Warnung aus, wenn eine Callback-Funktion mit Referenz-Parametern verwendet wird. Beispiele sind array_filter() und array_reduce(). Dies war bereits bei den meisten Funktionen der Fall, aber nicht bei allen.

  • Der HTTP-Stream-Wrapper, der von Funktionen wie file_get_contents() verwendet wird, meldet nun HTTP/1.1 statt HTTP/1.0. Dies ändert nichts am Verhalten des Clients, kann aber dazu führen, dass Server anders reagieren. Um das alte Verhalten beizubehalten, muss die Stream-Kontext-Option 'protocol_version' gesetzt werden, z. B.

    <?php
    $ctx
    = stream_context_create(['http' => ['protocol_version' => '1.0']]);
    echo
    file_get_contents('http://example.org', false, $ctx);
    ?>

  • Der Aufruf der Funktion crypt() ohne explizites Salz wird nicht mehr unterstützt. Wenn ein starker Hash mit automatisch generiertem Salz erzeugt werden soll, kann stattdessen password_hash() verwendet werden.

  • Die Funktionen substr(), mb_substr(), iconv_substr() und grapheme_substr() setzen Offsets, die außerhalb einer Zeichenkette liegen, nun einheitlich auf die Grenzen der Zeichenkette. Zuvor wurde in einigen Fällen false anstelle einer leeren Zeichenkette zurückgegeben

  • Unter Windows führen die Funktionen für die Ausführung von Programmen, die die Shell verwenden (proc_open(), exec(), popen() usw.) nun konsequent den Befehl %comspec% /s /c "$commandline" aus, was den gleichen Effekt hat wie die Ausführung von $commandline (ohne zusätzliche Anführungszeichen).

Sysvsem

  • Bei der Funktion sem_get() wurde der Parameter auto_release geändert und akzeptiert nun boolsche Werte (bool) anstelle von ganzen Zahlen (int).

Tidy

Tokenizer

  • Das Token T_COMMENT enthält keinen abschließenden Zeilenumbruch mehr. Der Zeilenumbruch gehört nun zum nachfolgenden T_WHITESPACE-Token. Es ist wichtig zu beachten, dass auf T_COMMENT nicht immer ein Leerzeichen folgt. Es könnte auch ein T_CLOSE_TAG oder das Ende der Datei folgen.

  • Die Namen innerhalb eines Namensraums werden nun durch die Token T_NAME_QUALIFIED (Foo\Bar), T_NAME_FULLY_QUALIFIED (\Foo\Bar) und T_NAME_RELATIVE (namespace\Foo\Bar) dargestellt. Das Token T_NS_SEPARATOR wird nur als einfaches Begrenzungszeichen für den Namensraum verwendet. Es ist syntaktisch nur zulässig, wenn es in Verbindung mit einer gruppierten use-Deklaration verwendet wird.

XMLReader

XMLReader::open() und XMLReader::xml() sind nun statische Methoden. Sie können immer noch als Instanzmethoden aufgerufen werden, aber erbende Klassen müssen diese Methoden als statisch deklarieren, wenn sie sie überschreiben.

XML-RPC

Die Erweiterung XML-RPC wurde nach PECL verschoben und ist nicht mehr Teil der PHP-Distribution.

Zip

Die Konstante ZipArchive::OPSYS_Z_CPM wurde entfernt (dieser Name hat einen Tippfehler); stattdessen sollte ZipArchive::OPSYS_CPM verwendet werden.

Zlib

PHP-Test-Suites für Windows

Das Skript zur Durchführung von Tests wurde von run-test.php in run-tests.php umbenannt, damit es dem Namen in php-src entspricht.

add a note

User Contributed Notes 2 notes

up
20
retry, abort, fail
2 years ago
The change in string to int comparison mentioned above (e.g. '' == 0 now equates to false) has some other nasty consequences:

$a = '';

// php 8

if ( $a < 0 ) echo 'true'; // echos true
if ( $a < -1) echo 'true'; // echos true
if ( $a < -100 ) echo 'true'; // echos true

// php 7

if ( $a < 0 ) echo 'true'; // no output
if ( $a < -1) echo 'true'; // no output
if ( $a < -100 ) echo 'true'; // no output

So in a situation where you may have a web form input and expected an empty value to equate to 0, watch out not only for == 0, != 0, and <= 0 comparisons, but ALL < or <= comparisons to negative integers.
up
0
aphpguy at galaxy dot za dot net
1 year ago
If you have older projects that break with PHP7 to 8 migration due to the loose comparison issue:

i.e. if ($a == 0) different behaviour between PHP 7 and PHP 8
(for case like $a = "" or $a = "123foo" and other cases listed at top)

replace in old code:

if ($a == 0) { .. }

with

if (cmp_eq($a, $b)) { .. }

Tested with a wide range of scenarios, even against arrays, booleans, file handles, pipe handles, objects, scalars and numbers.

So old code still behave like before.
Then both PHP8.x and older PHP up to ver 7.x will give the exact same boolean true or false output for loose comparisons.

function cmp_eq($a, $b) {
// If both $a and $b are of type strings, compare them as strings
if (is_string($a) && is_string($b)) { return $a == $b; } // may not be === because php says '42' equals '042' true yet '42' === '042' is false.

// If both $a and $b are numeric strings, compare them as numbers
if (is_numeric($a) && is_numeric($b)) { return $a == $b; }

// If $a is an empty string and $b is 0, or vice versa, return true
if (($a === '' && $b === 0) || ($a === 0 && $b === '')) { return true; }

// If $a is a non-numeric string and $b is 0, or vice versa, return true
if ((is_string($a) && ($a !== '') && ($b === 0)) || (($a === 0) && is_string($b) && ($b !== ''))) {
return true;
}
// special case '123abc' == 123 .. php 7 casts 123abc to 123, then 123 == 123 results in true. lets mimic that.
if ((is_string($a) && ($a !== '') && (is_numeric($b)) && ((bool)$b))) {
$number = filter_var($a, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); //"-234.56xyz"
return $number == $b;
}
if (is_numeric($a) && ((bool)$a) && is_string($b) && ($b !== '')) {
$number = filter_var($b, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); //"-234.56xyz"
return $a == $number;
}

// If $a is a number and $b is a non-numeric string, cast $a to string and compare
if (is_numeric($a) && is_string($b)) { return strval($a) == $b; }

// If $b is a number and $a is a non-numeric string, cast $b to string and compare
if (is_string($a) && is_numeric($b)) { return $a == strval($b); }

// If $a and $b are both non-numeric strings, compare them directly, we should return true if they are the same
return $a == $b;
} // end func cmp_eq

Note: the better way would be to port code to PHP 8, use strict variable typing and rather make use of the === and !== operators.

But in some cases having lots of old code to quickly patch, this might help.
To Top