xref: /PHP-8.0/UPGRADING (revision 09062704)
1PHP 8.0 UPGRADE NOTES
2
31. Backward Incompatible Changes
42. New Features
53. Changes in SAPI modules
64. Deprecated Functionality
75. Changed Functions
86. New Functions
97. New Classes and Interfaces
108. Removed Extensions and SAPIs
119. Other Changes to Extensions
1210. New Global Constants
1311. Changes to INI File Handling
1412. Windows Support
1513. Other Changes
1614. Performance Improvements
17
18
19========================================
201. Backward Incompatible Changes
21========================================
22
23- Core:
24  . `match` is now a reserved keyword.
25  . Assertion failures now throw by default. If the old behavior is desired,
26    then set `assert.exception=0` in INI settings.
27  . Methods with the same name as the class are no longer interpreted as
28    constructors. The __construct() method should be used instead.
29  . Removed ability to call non-static methods statically.
30    Thus `is_callable` will fail when checking for a non-static method with a
31    classname (must check with an object instance).
32  . Removed (real) cast.
33  . Removed (unset) cast.
34  . Removed track_errors ini directive. This means that $php_errormsg is no
35    longer available. The error_get_last() function may be used instead.
36  . Removed the ability to define case-insensitive constants. The third
37    argument to define() may no longer be true.
38  . Access to undefined constants now always results in an Error exception.
39    Previously, unqualified constant accesses resulted in a warning and were
40    interpreted as strings.
41  . Removed ability to specify an autoloader using an __autoload() function.
42    spl_autoload_register() should be used instead.
43  . Removed the $errcontext argument for custom error handlers.
44  . Removed create_function(). Anonymous functions may be used instead.
45  . Removed each(). foreach or ArrayIterator should be used instead.
46  . Removed ability to unbind $this from closures that were created from a
47    method, using Closure::fromCallable() or ReflectionMethod::getClosure().
48  . Also removed ability to unbind $this from proper closures that contain uses
49    of $this.
50  . Removed ability to use array_key_exists() with objects. Use one of isset()
51    or property_exists() instead.
52  . Made the behavior of array_key_exists() regarding the type of the key
53    parameter consistent with isset() and normal array access. All key types now
54    use the usual coercions and array/object keys throw a TypeError.
55  . Any array that has a number n as its first numeric key will use n+1 for
56    its next implicit key, even if n is negative.
57    RFC: https://wiki.php.net/rfc/negative_array_index
58  . The default error_reporting level is now E_ALL. Previously it excluded
59    E_NOTICE and E_DEPRECATED.
60  . display_startup_errors is now enabled by default.
61  . Using "parent" inside a class that has no parent will now result in a
62    fatal compile-time error.
63  . The @ operator will no longer silence fatal errors (E_ERROR, E_CORE_ERROR,
64    E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_PARSE). Error handlers
65    that expect error_reporting to be 0 when @ is used, should be adjusted to
66    use a mask check instead:
67
68        // Replace
69        function my_error_handler($err_no, $err_msg, $filename, $linenum) {
70            if (error_reporting() == 0) {
71                return; // Silenced
72            }
73            // ...
74        }
75
76        // With
77        function my_error_handler($err_no, $err_msg, $filename, $linenum) {
78            if (!(error_reporting() & $err_no)) {
79                return; // Silenced
80            }
81            // ...
82        }
83
84    Additionally, care should be taken that error messages are not displayed in
85    production environments, which can result in information leaks. Please
86    ensure that display_errors=Off is used in conjunction with error logging.
87  . Following the hash comment operator # immediately with an opening bracket
88    is not supported as a comment anymore since this syntax is now used for
89    attributes.
90    RFC: https://wiki.php.net/rfc/shorter_attribute_syntax_change
91  . Inheritance errors due to incompatible method signatures (LSP violations)
92    will now always generate a fatal error. Previously a warning was generated
93    in some cases.
94    RFC: https://wiki.php.net/rfc/lsp_errors
95  . The precedence of the concatenation operator has changed relative to
96    bitshifts and addition as well as subtraction.
97    RFC: https://wiki.php.net/rfc/concatenation_precedence
98  . Arguments with a default value that resolves to null at runtime will no
99    longer implicitly mark the argument type as nullable. Either use an explicit
100    nullable type, or an explicit null default value instead.
101
102        // Replace
103        function test(int $arg = CONST_RESOLVING_TO_NULL) {}
104        // With
105        function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
106        // Or
107        function test(int $arg = null) {}
108  . A number of warnings have been converted into Error exceptions:
109
110    * Attempting to write to a property of a non-object. Previously this
111      implicitly created an stdClass object for null, false and empty strings.
112    * Attempting to append an element to an array for which the PHP_INT_MAX key
113      is already used.
114    * Attempting to use an invalid type (array or object) as an array key or
115      string offset.
116    * Attempting to write to an array index of a scalar value.
117    * Attempting to unpack a non-array/Traversable.
118
119    A number of notices have been converted into warnings:
120
121    * Attempting to read an undefined variable.
122    * Attempting to read an undefined property.
123    * Attempting to read an undefined array key.
124    * Attempting to read a property of a non-object.
125    * Attempting to access an array index of a non-array.
126    * Attempting to convert an array to string.
127    * Attempting to use a resource as an array key.
128    * Attempting to use null, a boolean, or a float as a string offset.
129    * Attempting to read an out-of-bounds string offset.
130    * Attempting to assign an empty string to a string offset.
131
132    RFC: https://wiki.php.net/rfc/engine_warnings
133  . Attempting to assign multiple bytes to a string offset will now emit a
134    warning.
135  . Unexpected characters in source files (such as null bytes outside of
136    strings) will now result in a ParseError exception instead of a compile
137    warning.
138  . Uncaught exceptions now go through "clean shutdown", which means that
139    destructors will be called after an uncaught exception.
140  . Compile time fatal error "Only variables can be passed by reference" has
141    been delayed until runtime and converted to "Argument cannot be passed by
142    reference" exception.
143  . Some "Only variables should be passed by reference" notices have been
144    converted to "Argument cannot be passed by reference" exception.
145  . The generated name for anonymous classes has changed. It will now include
146    the name of the first parent or interface:
147
148        new class extends ParentClass {};
149        // -> ParentClass@anonymous
150        new class implements FirstInterface, SecondInterface {};
151        // -> FirstInterface@anonymous
152        new class {};
153        // -> class@anonymous
154
155    The name shown above is still followed by a null byte and a unique
156    suffix.
157  . Non-absolute trait method references in trait alias adaptations are now
158    required to be unambiguous:
159
160        class X {
161            use T1, T2 {
162               func as otherFunc;
163            }
164            function func() {}
165        }
166
167    If both T1::func() and T2::func() exist, this code was previously silently
168    accepted, and func was assumed to refer to T1::func. Now it will generate a
169    fatal error instead, and either T1::func or T2::func needs to be written
170    explicitly.
171  . The signature of abstract methods defined in traits is now checked against
172    the implementing class method:
173
174        trait MyTrait {
175            abstract private function neededByTrait(): string;
176        }
177
178        class MyClass {
179            use MyTrait;
180
181            // Error, because of return type mismatch.
182            private function neededByTrait(): int { return 42; }
183        }
184
185    RFC: https://wiki.php.net/rfc/abstract_trait_method_validation
186  . Disabled functions are now treated exactly like non-existent functions.
187    Calling a disabled function will report it as unknown, and redefining a
188    disabled function is now possible.
189  . data: stream wrappers are no longer writable, which matches the documented
190    behavior.
191  . The arithmetic and bitwise operators
192    +, -, *, /, **, %, <<, >>, &, |, ^, ~, ++, --
193    will now consistently throw a TypeError when one of the operands is an
194    array, resource or non-overloaded object. The only exception to this is the
195    array + array merge operation, which remains supported.
196    RFC: https://wiki.php.net/rfc/arithmetic_operator_type_checks
197  . Float to string casting will now always behave locale-independently.
198    RFC: https://wiki.php.net/rfc/locale_independent_float_to_string
199  . Removed support for deprecated curly braces for offset access
200    RFC: https://wiki.php.net/rfc/deprecate_curly_braces_array_access
201  . Applying the final modifier on a private method will now produce a warning
202    unless that method is the constructor.
203    RFC: https://wiki.php.net/rfc/inheritance_private_methods
204  . If an object constructor exit()s, the object destructor will no longer be
205    called. This matches the behavior when the constructor throws.
206  . Non-strict comparisons between numbers and non-numeric strings now work by
207    casting the number to string and comparing the strings. Comparisons between
208    numbers and numeric strings continue to work as before. Notably, this means
209    that `0 == "not-a-number"` is considered false now.
210    RFC: https://wiki.php.net/rfc/string_to_number_comparison
211  . Namespaced names can no longer contain whitespace: While `Foo\Bar` will be
212    recognized as a namespaced name, `Foo \ Bar` will not. Conversely, reserved
213    keywords are now permitted as namespace segments, which may also change the
214    interpretation of code: `new\x` is now the same as `constant('new\x')`, not
215    `new \x()`.
216    RFC: https://wiki.php.net/rfc/namespaced_names_as_token
217  . Nested ternaries now require explicit parentheses.
218    RFC: https://wiki.php.net/rfc/ternary_associativity
219  . debug_backtrace() and Exception::getTrace() will no longer provide
220    references to arguments. It will not be possible to change function
221    arguments through the backtrace.
222  . Numeric string handling has been altered to be more intuitive and less
223    error-prone. Trailing whitespace is now allowed in numeric strings for
224    consistency with how leading whitespace is treated. This mostly affects:
225     - The is_numeric() function
226     - String-to-string comparisons
227     - Type declarations
228     - Increment and decrement operations
229    The concept of a "leading-numeric string" has been mostly dropped; the
230    cases where this remains exist in order to ease migration. Strings which
231    emitted an E_NOTICE "A non well-formed numeric value encountered" will now
232    emit an E_WARNING "A non-numeric value encountered" and all strings which
233    emitted an E_WARNING "A non-numeric value encountered" will now throw a
234    TypeError. This mostly affects:
235     - Arithmetic operations
236     - Bitwise operations
237    This E_WARNING to TypeError change also affects the E_WARNING
238    "Illegal string offset 'string'" for illegal string offsets. The behavior
239    of explicit casts to int/float from strings has not been changed.
240    RFC: https://wiki.php.net/rfc/saner-numeric-strings
241  . Magic Methods will now have their arguments and return types checked if
242    they have them declared. The signatures should match the following list:
243
244      __call(string $name, array $arguments): mixed
245      __callStatic(string $name, array $arguments): mixed
246      __clone(): void
247      __debugInfo(): ?array
248      __get(string $name): mixed
249      __invoke(mixed $arguments): mixed
250      __isset(string $name): bool
251      __serialize(): array
252      __set(string $name, mixed $value): void
253      __set_state(array $properties): object
254      __sleep(): array
255      __unserialize(array $data): void
256      __unset(string $name): void
257      __wakeup(): void
258
259    RFC: https://wiki.php.net/rfc/magic-methods-signature
260  . call_user_func_array() array keys will now be interpreted as parameter names,
261    instead of being silently ignored.
262
263- COM:
264  . Removed the ability to import case-insensitive constants from type
265    libraries. The second argument to com_load_typelib() may no longer be false;
266    com.autoregister_casesensitive may no longer be disabled; case-insensitive
267    markers in com.typelib_file are ignored.
268
269- Curl:
270  . CURLOPT_POSTFIELDS no longer accepts objects as arrays. To interpret an
271    object as an array, perform an explicit (array) cast. The same applies to
272    other options accepting arrays as well.
273
274- Date:
275  . mktime() and gmmktime() now require at least one argument. time() can be
276    used to get the current timestamp.
277
278- dom:
279  . Remove unimplemented classes from ext/dom that had no behavior and contained
280    test data. These classes have also been removed in the latest version of DOM
281    standard:
282
283     * DOMNameList
284     * DomImplementationList
285     * DOMConfiguration
286     * DomError
287     * DomErrorHandler
288     * DOMImplementationSource
289     * DOMLocator
290     * DOMUserDataHandler
291     * DOMTypeInfo
292
293- Enchant:
294  . enchant_broker_list_dicts(), enchant_broker_describe() and
295    enchant_dict_suggest() will now return an empty array instead of null.
296  . enchant_broker_init() will now return an EnchantBroker object rather than
297    a resource. Return value checks using is_resource() should be replaced with
298    checks for `false`.
299  . enchant_broker_request_dict() and enchant_broker_request_pwl_dict() will now
300    return an EnchantDictionary object rather than a resource. Return value
301    checks using is_resource() should be replaced with checks for `false`.
302
303- Exif:
304  . Removed read_exif_data(). exif_read_data() should be used instead.
305
306- Filter:
307  . The FILTER_FLAG_SCHEME_REQUIRED and FILTER_FLAG_HOST_REQUIRED flags for the
308    FILTER_VALIDATE_URL filter have been removed. The scheme and host are (and
309    have been) always required.
310  . The INPUT_REQUEST and INPUT_SESSION source for filter_input() etc have been
311    removed. These were never implemented and their use always generated a
312    warning.
313
314- GD:
315  . The GD extension now uses a GdImage objects as the underlying data structure
316    for images, rather than resources. These objects are completely opaque, i.e.
317    they don't have any methods. Return value checks using is_resource() should
318    be replaced with checks for `false`. The imagedestroy() function no longer
319    has an effect, instead the GdImage instance is automatically destroyed if
320    it is no longer referenced.
321  . The deprecated function image2wbmp() has been removed.
322    RFC: https://wiki.php.net/rfc/image2wbmp
323  . The deprecated functions png2wbmp() and jpeg2wbmp() have been removed.
324    RFC: https://wiki.php.net/rfc/deprecate-png-jpeg-2wbmp
325  . The default $mode parameter of imagecropauto() no longer accepts -1.
326    IMG_CROP_DEFAULT should be used instead.
327
328- GMP:
329  . gmp_random() has been removed. One of gmp_random_range() or
330    gmp_random_bits() should be used instead.
331
332- Iconv:
333  . iconv() implementations which do not properly set errno in case of errors
334    are no longer supported.
335
336- IMAP:
337  . The unused default_host argument of imap_headerinfo() has been removed.
338  . The imap_header() function which is an alias of imap_headerinfo() has been removed.
339
340- Intl:
341  . The deprecated constant INTL_IDNA_VARIANT_2003 has been removed.
342    RFC: https://wiki.php.net/rfc/deprecate-and-remove-intl_idna_variant_2003
343  . The deprecated Normalizer::NONE constant has been removed.
344  . The IntlDateFormatter::RELATIVE_FULL, IntlDateFormatter::RELATIVE_LONG,
345    IntlDateFormatter::RELATIVE_MEDIUM, and IntlDateFormatter::RELATIVE_SHORT
346    constants have been added.
347
348- LDAP:
349  . The deprecated function ldap_sort has been removed.
350  . The deprecated function ldap_control_paged_result has been removed.
351  . The deprecated function ldap_control_paged_result_response has been removed.
352  . The interface of ldap_set_rebind_proc has changed; the $callback parameter
353    does not accept empty string anymore; null value shall be used instead.
354
355- Mbstring:
356  . The mbstring.func_overload directive has been removed. The related
357    MB_OVERLOAD_MAIL, MB_OVERLOAD_STRING, and MB_OVERLOAD_REGEX constants have
358    also been removed. Finally, the "func_overload" and "func_overload_list"
359    entries in mb_get_info() have been removed.
360  . mb_parse_str() can no longer be used without specifying a result array.
361  . A number of deprecated mbregex aliases have been removed. See the following
362    list for which functions should be used instead:
363
364     * mbregex_encoding()      -> mb_regex_encoding()
365     * mbereg()                -> mb_ereg()
366     * mberegi()               -> mb_eregi()
367     * mbereg_replace()        -> mb_ereg_replace()
368     * mberegi_replace()       -> mb_eregi_replace()
369     * mbsplit()               -> mb_split()
370     * mbereg_match()          -> mb_ereg_match()
371     * mbereg_search()         -> mb_ereg_search()
372     * mbereg_search_pos()     -> mb_ereg_search_pos()
373     * mbereg_search_regs()    -> mb_ereg_search_regs()
374     * mbereg_search_init()    -> mb_ereg_search_init()
375     * mbereg_search_getregs() -> mb_ereg_search_getregs()
376     * mbereg_search_getpos()  -> mb_ereg_search_getpos()
377     * mbereg_search_setpos()  -> mb_ereg_search_setpos()
378
379  . The 'e' modifier for mb_ereg_replace() has been removed.
380    mb_ereg_replace_callback() should be used instead.
381  . A non-string pattern argument to mb_ereg_replace() will now be interpreted
382    as a string instead of an ASCII codepoint. The previous behavior may be
383    restored with an explicit call to chr().
384  . The needle argument for mb_strpos(), mb_strrpos(), mb_stripos(),
385    mb_strripos(), mb_strstr(), mb_stristr(), mb_strrchr() and mb_strrichr() can
386    now be empty.
387  . The $is_hex parameter, which was not used internally, has been removed from
388    mb_decode_numericentity().
389  . The legacy behavior of passing the encoding as the third argument instead
390    of an offset for the mb_strrpos() function has been removed; provide an
391    explicit 0 offset with the encoding as the fourth argument instead.
392  . The ISO_8859-* character encoding aliases have been replaced by ISO8859-*
393    aliases for better interoperability with the iconv extension. The mbregex
394    ISO 8859 aliases with underscores (ISO_8859_* and ISO8859_*) have also been
395    removed.
396  . mb_ereg() and mb_eregi() will now return boolean true on a successful
397    match. Previously they returned integer 1 if $matches was not passed, or
398    max(1, strlen($reg[0])) is $matches was passed.
399
400- OCI8:
401  . The OCI-Lob class is now called OCILob, and the OCI-Collection class is now
402    called OCICollection for name compliance enforced by PHP 8 arginfo
403    type annotation tooling.
404  . Several alias functions have been marked as deprecated.
405  . oci_internal_debug() and its alias ociinternaldebug() have been removed.
406
407- ODBC:
408  . odbc_connect() no longer reuses persistent connections.
409  . The unused flags parameter of odbc_exec() has been removed.
410
411- OpenSSL:
412  . openssl_x509_read() and openssl_csr_sign() will now return an
413    OpenSSLCertificate object rather than a resource. Return value checks using
414    is_resource() should be replaced with checks for `false`.
415  . The openssl_x509_free() function is deprecated and no longer has an effect,
416    instead the OpenSSLCertificate instance is automatically destroyed if it is no
417    longer referenced.
418  . openssl_csr_new() will now return an OpenSSLCertificateSigningRequest object
419    rather than a resource. Return value checks using is_resource() should be
420    replaced with checks for `false`.
421  . openssl_pkey_new() will now return an OpenSSLAsymmetricKey object rather than a
422    resource. Return value checks using is_resource() should be replaced with
423    checks for `false`.
424  . The openssl_pkey_free() function is deprecated and no longer has an effect,
425    instead the OpenSSLAsymmetricKey instance is automatically destroyed if it is no
426    longer referenced.
427  . openssl_seal() and openssl_open() now require $method to be passed, as the
428    previous default of "RC4" is considered insecure.
429
430- PCRE:
431  . When passing invalid escape sequences they are no longer interpreted as
432    literals. This behavior previously required the X modifier - which is
433    now ignored.
434
435- PDO:
436  . The default error handling mode has been changed from "silent" to
437    "exceptions". See https://www.php.net/manual/en/pdo.error-handling.php
438    for details of behavior changes and how to explicitly set this attribute.
439    RFC: https://wiki.php.net/rfc/pdo_default_errmode
440  . The signatures of some PDO methods have changed:
441
442        PDO::query(
443            string $statement, ?int $fetch_mode = null, ...$fetch_mode_args)
444        PDOStatement::setFetchMode(int $mode, ...$params)
445
446- PDO MySQL:
447  . PDO::inTransaction() now reports the actual transaction state of the
448    connection, rather than an approximation maintained by PDO. If a query that
449    is subject to "implicit commit" is executed, PDO::inTransaction() will
450    subsequently return false, as a transaction is no longer active.
451
452- PDO_ODBC:
453  . The php.ini directive pdo_odbc.db2_instance_name has been removed
454
455- pgsql:
456  . The deprecated pg_connect() syntax using multiple parameters instead of a
457    connection string is no longer supported.
458  . The deprecated pg_lo_import() and pg_lo_export() signature that passes the
459    connection as the last argument is no longer supported. The connection
460    should be passed as first argument instead.
461  . pg_fetch_all() will now return an empty array instead of false for result
462    sets with zero rows.
463
464- Phar:
465  . Metadata associated with a phar will no longer be automatically unserialized,
466    to fix potential security vulnerabilities due to object instantiation, autoloading, etc.
467    RFC: https://wiki.php.net/rfc/phar_stop_autoloading_metadata
468
469- Reflection:
470  . The method signatures
471
472        ReflectionClass::newInstance($args)
473        ReflectionFunction::invoke($args)
474        ReflectionMethod::invoke($object, $args)
475
476    have been changed to:
477
478        ReflectionClass::newInstance(...$args)
479        ReflectionFunction::invoke(...$args)
480        ReflectionMethod::invoke($object, ...$args)
481
482    Code that must be compatible with both PHP 7 and PHP 8 can use the following
483    signatures to be compatible with both versions:
484
485        ReflectionClass::newInstance($arg = null, ...$args)
486        ReflectionFunction::invoke($arg = null, ...$args)
487        ReflectionMethod::invoke($object, $arg = null, ...$args)
488
489  . The ReflectionType::__toString() method will now return a complete debug
490    representation of the type, and is no longer deprecated. In particular the
491    result will include a nullability indicator for nullable types. The format
492    of the return value is not stable and may change between PHP versions.
493  . Reflection export() methods have been removed.
494  . The following methods can now return information about default values of
495    parameters of internal functions:
496        ReflectionParameter::isDefaultValueAvailable()
497        ReflectionParameter::getDefaultValue()
498        ReflectionParameter::isDefaultValueConstant()
499        ReflectionParameter::getDefaultValueConstantName()
500  . ReflectionMethod::isConstructor() and ReflectionMethod::isDestructor() now
501    also return true for `__construct` and `__destruct` methods of interfaces.
502    Previously, this would only be true for methods of classes and traits.
503  . ReflectionType::isBuiltin() method has been moved to ReflectionNamedType.
504    ReflectionUnionType does not have it.
505
506- Sockets:
507  . The deprecated AI_IDN_ALLOW_UNASSIGNED and AI_IDN_USE_STD3_ASCII_RULES
508    flags for socket_addrinfo_lookup() have been removed.
509  . socket_create(), socket_create_listen(), socket_accept(),
510    socket_import_stream(), socket_addrinfo_connect(), socket_addrinfo_bind(),
511    and socket_wsaprotocol_info_import() will now return a Socket object rather
512    than a resource. Return value checks using is_resource() should be replaced
513    with checks for `false`.
514  . socket_addrinfo_lookup() will now return an array of AddressInfo objects
515    rather than resources.
516
517- SPL:
518  . SplFileObject::fgetss() has been removed.
519  . SplFileObject::seek() now always seeks to the beginning of the line.
520    Previously, positions >=1 sought to the beginning of the next line.
521  . SplHeap::compare($a, $b) now specifies a method signature. Inheriting
522    classes implementing this method will now have to use a compatible
523    method signature.
524  . SplDoublyLinkedList::push() now returns void instead of true
525  . SplDoublyLinkedList::unshift() now returns void instead of true
526  . SplQueue::enqueue() now returns void instead of true
527  . spl_autoload_register() will now always throw a TypeError on invalid
528    arguments, therefore the second argument $do_throw is ignored and a
529    notice will be emitted if it is set to false.
530  . SplFixedArray is now an IteratorAggregate and not an Iterator.
531    SplFixedArray::rewind(), ::current(), ::key(), ::next(), and ::valid()
532    have been removed. In their place, SplFixedArray::getIterator() has been
533    added. Any code which uses explicit iteration over SplFixedArray must now
534    obtain an Iterator through SplFixedArray::getIterator(). This means that
535    SplFixedArray is now safe to use in nested loops.
536
537- Standard:
538  . assert() will no longer evaluate string arguments, instead they will be
539    treated like any other argument. assert($a == $b) should be used instead of
540    assert('$a == $b'). The assert.quiet_eval ini directive and
541    ASSERT_QUIET_EVAL constants have also been removed, as they would no longer
542    have any effect.
543  . parse_str() can no longer be used without specifying a result array.
544  . fgetss() has been removed.
545  . The string.strip_tags filter has been removed.
546  . The needle argument of strpos(), strrpos(), stripos(), strripos(), strstr(),
547    strchr(), strrchr(), and stristr() will now always be interpreted as a
548    string. Previously non-string needles were interpreted as an ASCII code
549    point. An explicit call to chr() can be used to restore the previous
550    behavior.
551  . The needle argument for strpos(), strrpos(), stripos(), strripos(),
552    strstr(), stristr() and strrchr() can now be empty.
553  . The length argument for substr(), substr_count(), substr_compare(), and
554    iconv_substr() can now be null. Null values will behave as if no length
555    argument was provided and will therefore return the remainder of the string
556    instead of an empty string.
557  . The length argument for array_splice() can now be null. Null values will
558    behave identically to omitting the argument, thus removing everything from
559    the 'offset' to the end of the array.
560  . The args argument of vsprintf(), vfprintf(), and vprintf() must now be an
561    array. Previously any type was accepted.
562  . The 'salt' option of password_hash() is no longer supported. If the 'salt'
563    option is used a warning is generated, the provided salt is ignored, and a
564    generated salt is used instead.
565  . The quotemeta() function will now return an empty string if an empty string
566    was passed. Previously false was returned.
567  . hebrevc() has been removed.
568  . convert_cyr_string() has been removed.
569  . money_format() has been removed.
570  . ezmlm_hash() has been removed.
571  . restore_include_path() has been removed.
572  . get_magic_quotes_gpc() and get_magic_quotes_runtime() has been removed.
573  . FILTER_SANITIZE_MAGIC_QUOTES has been removed.
574  . Calling implode() with parameters in a reverse order ($pieces, $glue) is no
575    longer supported.
576  . parse_url() will now distinguish absent and empty queries and fragments:
577
578        http://example.com/foo   => query = null, fragment = null
579        http://example.com/foo?  => query = "",   fragment = null
580        http://example.com/foo#  => query = null, fragment = ""
581        http://example.com/foo?# => query = "",   fragment = ""
582
583    Previously all cases resulted in query and fragment being null.
584  . var_dump() and debug_zval_dump() will now print floating-point numbers
585    using serialize_precision rather than precision. In a default configuration,
586    this means that floating-point numbers are now printed with full accuracy
587    by these debugging functions.
588  . If the array returned by __sleep() contains non-existing properties, these
589    are now silently ignored. Previously, such properties would have been
590    serialized as if they had the value NULL.
591  . The default locale on startup is now always "C". No locales are inherited
592    from the environment by default. Previously, LC_ALL was set to "C", while
593    LC_CTYPE was inherited from the environment. However, some functions did not
594    respect the inherited locale without an explicit setlocale() call. An
595    explicit setlocale() call is now always required if you wish to change any
596    locale component from the default.
597  . Removed deprecated DES fallback in crypt(). If an unknown salt format is
598    passed to crypt(), the function will fail with *0 instead of falling back
599    to a weak DES hash now.
600  . Specifying out of range rounds for sha256/sha512 crypt() will now fail with
601    *0 instead of clamping to the closest limit. This matches glibc behavior.
602  . The result of sorting functions may have changed, if the array contains
603    elements that compare as equal.
604  . Sort comparison functions that return true or false will now throw a
605    deprecation warning, and should be replaced with an implementation
606    that returns an integer less than, equal to, or greater than zero.
607
608        // Replace
609        usort($array, fn($a, $b) => $a > $b);
610        // With
611        usort($array, fn($a, $b) => $a <=> $b);
612
613  . Any functions accepting callbacks that are not explicitly specified to
614    accept parameters by reference will now warn if a callback with reference
615    parameters is used. Examples include array_filter() and array_reduce().
616    This was already the case for most, but not all, functions previously.
617  . The HTTP stream wrapper as used by functions like file_get_contents()
618    now advertises HTTP/1.1 rather than HTTP/1.0 by default. This does not
619    change the behavior of the client, but may cause servers to respond
620    differently. To retain the old behavior, set the 'protocol_version'
621    stream context option, e.g.
622
623        $ctx = stream_context_create(['http' => ['protocol_version' => '1.0']]);
624        echo file_get_contents('http://example.org', false, $ctx);
625  . Calling crypt() without an explicit salt is no longer supported. If you
626    would like to produce a strong hash with an auto-generated salt, use
627    password_hash() instead.
628  . substr(), mb_substr(), iconv_substr() and grapheme_substr() now consistently
629    clamp out-of-bounds offsets to the string boundary. Previously, false was
630    returned instead of the empty string in some cases.
631  . Populating $http_response_header variable by the HTTP stream wrapper
632    doesn't force rebuilding of symbol table anymore.
633
634- Sysvmsg:
635  . msg_get_queue() will now return an SysvMessageQueue object rather than a
636    resource. Return value checks using is_resource() should be replaced with
637    checks for `false`.
638
639- Sysvsem:
640  . sem_get() will now return an SysvSemaphore object rather than a resource.
641    Return value checks using is_resource() should be replaced with checks
642    for `false`.
643  . The $auto_release parameter of sem_get() was changed to accept bool values
644    rather than int.
645
646- Sysvshm:
647  . shm_attach() will now return an SysvSharedMemory object rather than a resource.
648    Return value checks using is_resource() should be replaced with checks
649    for `false`.
650
651- tidy:
652  . The $use_include_path parameter, which was not used internally, has been
653    removed from tidy_repair_string().
654  . tidy::repairString() and tidy::repairFile() became static methods
655
656- Tokenizer:
657  . T_COMMENT tokens will no longer include a trailing newline. The newline will
658    instead be part of a following T_WHITESPACE token. It should be noted that
659    T_COMMENT is not always followed by whitespace, it may also be followed by
660    T_CLOSE_TAG or end-of-file.
661  . Namespaced names are now represented using the T_NAME_QUALIFIED (Foo\Bar),
662    T_NAME_FULLY_QUALIFIED (\Foo\Bar) and T_NAME_RELATIVE (namespace\Foo\Bar)
663    tokens. T_NS_SEPARATOR is only used for standalone namespace separators,
664    and only syntactially valid in conjunction with group use declarations.
665    RFC: https://wiki.php.net/rfc/namespaced_names_as_token
666
667- XML:
668  . xml_parser_create(_ns) will now return an XMLParser object rather than a
669    resource. Return value checks using is_resource() should be replaced with
670    checks for `false`. The xml_parser_free() function no longer has an effect,
671    instead the XMLParser instance is automatically destroyed if it is no longer
672    referenced.
673
674- XMLReader:
675  . XMLReader::open() and XMLReader::xml() are now static methods. They still
676    can be called dynamically, though, but inheriting classes need to declare
677    them as static if they override these methods.
678
679- XMLWriter:
680  . The XMLWriter functions now accept and return, respectively, XMLWriter
681    objects instead of resources.
682
683- Zip:
684  . ZipArchive::OPSYS_Z_CPM has been removed (this name was a typo). Use
685    ZipArchive::OPSYS_CPM instead.
686
687- Zlib:
688  . gzgetss() has been removed.
689  . inflate_init() will now return an InflateContext object rather than a
690    resource. Return value checks using is_resource() should be replaced with
691    checks for `false`.
692  . deflate_init() will now return a DeflateContext object rather than a
693    resource. Return value checks using is_resource() should be replaced with
694    checks for `false`.
695  . zlib.output_compression is no longer automatically disabled for
696    Content-Type: image/*.
697
698========================================
6992. New Features
700========================================
701
702- Core:
703  . Added support for union types.
704    RFC: https://wiki.php.net/rfc/union_types_v2
705  . Added WeakMap.
706    RFC: https://wiki.php.net/rfc/weak_maps
707  . Added ValueError class.
708  . Any number of function parameters may now be replaced by a variadic
709    argument, as long as the types are compatible. For example, the following
710    code is now allowed:
711
712        class A {
713            public function method(int $many, string $parameters, $here) {}
714        }
715        class B extends A {
716            public function method(...$everything) {}
717        }
718  . "static" (as in "late static binding") can now be used as a return type:
719
720        class Test {
721            public function create(): static {
722                return new static();
723            }
724        }
725
726    RFC: https://wiki.php.net/rfc/static_return_type
727  . It is now possible to fetch the class name of an object using
728    `$object::class`. The result is the same as `get_class($object)`.
729    RFC: https://wiki.php.net/rfc/class_name_literal_on_object
730  . New and instanceof can now be used with arbitrary expressions, using
731    `new (expression)(...$args)` and `$obj instanceof (expression)`.
732    RFC: https://wiki.php.net/rfc/variable_syntax_tweaks
733  . Some consistency fixes to variable syntax have been applied, for example
734    writing `Foo::BAR::$baz` is now allowed.
735    RFC: https://wiki.php.net/rfc/variable_syntax_tweaks
736  . Added Stringable interface, which is automatically implemented if a class
737    defines a __toString() method.
738    RFC: https://wiki.php.net/rfc/stringable
739  . Traits can now define abstract private methods.
740    RFC: https://wiki.php.net/rfc/abstract_trait_method_validation
741  . `throw` can now be used as an expression.
742    RFC: https://wiki.php.net/rfc/throw_expression
743  . An optional trailing comma is now allowed in parameter lists.
744    RFC: https://wiki.php.net/rfc/trailing_comma_in_parameter_list
745  . It is now possible to write `catch (Exception)` to catch an exception
746    without storing it in a variable.
747    RFC: https://wiki.php.net/rfc/non-capturing_catches
748  . Added support for mixed type
749    RFC: https://wiki.php.net/rfc/mixed_type_v2
750  . Added support for Attributes
751    RFC: https://wiki.php.net/rfc/attributes_v2
752    RFC: https://wiki.php.net/rfc/attribute_amendments
753    RFC: https://wiki.php.net/rfc/shorter_attribute_syntax
754    RFC: https://wiki.php.net/rfc/shorter_attribute_syntax_change
755  . Added support for constructor property promotion (declaring properties in
756    the constructor signature).
757    RFC: https://wiki.php.net/rfc/constructor_promotion
758  . Added support for `match` expression.
759    RFC: https://wiki.php.net/rfc/match_expression_v2
760  . Private methods declared on a parent class no longer enforce any
761    inheritance rules on the methods of a child class. (with the exception of
762    final private constructors)
763    RFC: https://wiki.php.net/rfc/inheritance_private_methods
764  . Added support for nullsafe operator (`?->`).
765    RFC: https://wiki.php.net/rfc/nullsafe_operator
766  . Added support for named arguments.
767    RFC: https://wiki.php.net/rfc/named_params
768
769- Date:
770  . Added DateTime::createFromInterface() and
771    DateTimeImmutable::createFromInterface().
772  . Added the DateTime format specifier "p" which is the same as "P" but
773    returning "Z" for UTC.
774
775- Dom:
776  . Introduce DOMParentNode and DOMChildNode with new traversal and
777    manipulation APIs.
778    RFC: https://wiki.php.net/rfc/dom_living_standard_api
779
780- Enchant:
781  . enchant_dict_add()
782  . enchant_dict_is_added()
783  . LIBENCHANT_VERSION macro
784
785- FPM:
786  . Added a new option pm.status_listen that allows getting status from
787    different endpoint (e.g. port or UDS file) which is useful for getting
788    status when all children are busy with serving long running requests.
789
790- Hash:
791  . HashContext objects can now be serialized.
792
793- Opcache:
794  . If the opcache.record_warnings ini setting is enabled, opcache will record
795    compile-time warnings and replay them on the next include, even if it is
796    served from cache.
797
798- OpenSSL:
799  . Added Cryptographic Message Syntax (CMS) (RFC 5652) support composed of
800    functions for encryption, decryption, signing, verifying and reading. The
801    API is similar to the API for PKCS #7 functions with an addition of new
802    encoding constants: OPENSSL_ENCODING_DER, OPENSSL_ENCODING_SMIME and
803    OPENSSL_ENCODING_PEM.
804
805- Standard:
806  . printf() and friends now support the %h and %H format specifiers. These
807    are the same as %g and %G, but always use "." as the decimal separator,
808    rather than determining it through the LC_NUMERIC locale.
809  . printf() and friends now support using "*" as width or precision, in which
810    case the width/precision is passed as an argument to printf. This also
811    allows using precision -1 with %g, %G, %h and %H. For example, the following
812    code can be used to reproduce PHP's default floating point formatting:
813
814        printf("%.*H", (int) ini_get("precision"), $float);
815        printf("%.*H", (int) ini_get("serialize_precision"), $float);
816
817  . proc_open() now supports pseudo-terminal (PTY) descriptors. The following
818    attaches stdin, stdout and stderr to the same PTY:
819
820        $proc = proc_open($command, [['pty'], ['pty'], ['pty']], $pipes);
821
822  . proc_open() now supports socket pair descriptors. The following attaches
823    a distinct socket pair to stdin, stdout and stderr:
824
825        $proc = proc_open(
826            $command, [['socket'], ['socket'], ['socket']], $pipes);
827
828    Unlike pipes, sockets do not suffer from blocking I/O issues on Windows.
829    However, not all programs may work correctly with stdio sockets.
830  . Sorting functions are now stable, which means that equal-comparing elements
831    will retain their original order.
832    RFC: https://wiki.php.net/rfc/stable_sorting
833  . array_diff(), array_intersect() and their variations can now be used with
834    a single array as argument. This means that usages like the following are
835    now possible:
836
837        // OK even if $excludes is empty.
838        array_diff($array, ...$excludes);
839        // OK even if $arrays only contains a single array.
840        array_intersect(...$arrays);
841  . The $flag parameter of ob_implicit_flush() was changed to accept bool
842    values rather than int.
843
844- Zip:
845  . Extension updated to version 1.19.1
846  . New ZipArchive::lastId property to get index value of last added entry.
847  . Error can be checked after an archive is closed using ZipArchive::status,
848    ZipArchive::statusSys properties or ZipArchive::getStatusString() method.
849  . The remove_path option of ZipArchive::addGlob() and ::addPattern() is now
850    treated as arbitrary string prefix (for consistency with the add_path
851    option), whereas formerly it was treated as directory name.
852  . Optional compression / encryption features are listed in phpinfo.
853
854========================================
8553. Changes in SAPI modules
856========================================
857
858- Apache:
859  . The PHP module has been renamed from php7_module to php_module.
860
861========================================
8624. Deprecated Functionality
863========================================
864
865- Core:
866  . Declaring a required parameter after an optional one is deprecated. As an
867    exception, declaring a parameter of the form "Type $param = null" before
868    a required one continues to be allowed, because this pattern was sometimes
869    used to achieve nullable types in older PHP versions.
870
871        function test($a = [], $b) {}       // Deprecated
872        function test(Foo $a = null, $b) {} // Allowed
873  . Calling get_defined_functions() with $exclude_disabled explicitly set to
874    false is deprecated. get_defined_functions() will never include disabled
875    functions.
876
877- Enchant:
878  . enchant_broker_set_dict_path and enchant_broker_get_dict_path
879    not available in libenchant < 1.5 nor in libenchant-2
880  . enchant_dict_add_to_personal, use enchant_dict_add instead
881  . enchant_dict_is_in_session, use enchant_dict_is_added instead
882  . enchant_broker_free and enchant_broker_free_dict, unset the object instead
883  . ENCHANT_MYSPELL and ENCHANT_ISPELL constants
884
885- LibXML:
886  . libxml_disable_entity_loader() has been deprecated. As libxml 2.9.0 is now
887    required, external entity loading is guaranteed to be disabled by default,
888    and this function is no longer needed to protect against XXE attacks.
889
890- PGSQL / PDO PGSQL:
891  . The constant PGSQL_LIBPQ_VERSION_STR has now the same value as
892    PGSQL_LIBPQ_VERSION, and thus is deprecated.
893  . Function aliases in the pgsql extension have been deprecated.
894
895- Zip:
896  . Using empty file as ZipArchive is deprecated. Libzip 1.6.0
897    do not accept empty files as valid zip archives any longer.
898    Existing workaround will be removed in next version.
899  . The procedural API of Zip is deprecated. Use ZipArchive instead.
900
901- Reflection:
902  . ReflectionFunction::isDisabled() is deprecated, as it is no longer possible
903    to create a ReflectionFunction for a disabled function. This method now
904    always returns false.
905  . ReflectionParameter::getClass(), ReflectionParameter::isArray(), and
906    ReflectionParameter::isCallable() are deprecated.
907    ReflectionParameter::getType() and the ReflectionType APIs should be used
908    instead.
909
910========================================
9115. Changed Functions
912========================================
913
914- Reflection:
915  . ReflectionClass::getConstants and ReflectionClass::getReflectionConstants results
916    can be now filtered via a new parameter `$filter`. 3 new constants were added to
917    be used with it:
918
919      ReflectionClassConstant::IS_PUBLIC
920      ReflectionClassConstant::IS_PROTECTED
921      ReflectionClassConstant::IS_PRIVATE
922
923- Zip
924 . ZipArchive::addGlob and ZipArchive::addPattern methods accept more
925   values in the "options" array argument:
926   . flags
927   . comp_method
928   . comp_flags
929   . env_method
930   . enc_password
931 . ZipArchive::addEmptyDir, ZipArchive::addFile and aZipArchive::addFromString
932   methods have a new "flags" argument. This allows managing name encoding
933   (ZipArchive::FL_ENC_*) and entry replacement (ZipArchive::FL_OVERWRITE)
934 . ZipArchive::extractTo now restore file modification time.
935
936========================================
9376. New Functions
938========================================
939
940- Core:
941  . Added get_resource_id($resource) function, which returns the same value as
942    (int) $resource. It provides the same functionality under a clearer API.
943
944- LDAP:
945  . Added ldap_count_references(), which returns the number of reference
946    messages in a search result.
947
948- OpenSSL:
949  . Added openssl_cms_encrypt() encrypts the message in the file with the
950    certificates and outputs the result to the supplied file.
951  . Added openssl_cms_decrypt() that decrypts the S/MIME message in the file
952    and outputs the results to the supplied file.
953  . Added openssl_cms_read() that exports the CMS file to an array of PEM
954    certificates.
955  . Added openssl_cms_sign() that signs the MIME message in the file with
956    a cert and key and output the result to the supplied file.
957  . Added openssl_cms_verify() that verifies that the data block is intact,
958    the signer is who they say they are, and returns the certs of the signers.
959
960- PCRE:
961  . Added preg_last_error_msg(), which returns a human-readable message for
962    the last PCRE error. It complements preg_last_error(), which returns an
963    integer enum instead.
964
965- SQLite3:
966  . Add SQLite3::setAuthorizer() and respective class constants to set a
967    userland callback that will be used to authorize or not an action on the
968    database.
969    PR: https://github.com/php/php-src/pull/4797
970
971- Standard:
972  . Added
973
974        str_contains(string $haystack, string $needle): bool
975        str_starts_with(string $haystack, string $needle): bool
976        str_ends_with(string $haystack, string $needle): bool
977
978    functions, which check whether $haystack contains, starts with or ends with
979    $needle.
980    RFC: https://wiki.php.net/rfc/str_contains
981    RFC: https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions
982  . Added fdiv() function, which performs a floating-point division under
983    IEEE 754 semantics. Division by zero is considered well-defined and
984    will return one of Inf, -Inf or NaN.
985  . Added get_debug_type() function, which returns a type useful for error
986    messages. Unlike gettype(), it uses canonical type names, returns class
987    names for objects, and indicates the resource type for resources.
988    RFC: https://wiki.php.net/rfc/get_debug_type
989
990- Zip:
991  . ZipArchive::setMtimeName and ZipArchive::setMtimeIndex to set the
992    modification time of an entry.
993  . ZipArchive::registerProgressCallback to provide updates during archive close.
994  . ZipArchive::registerCancelCallback to allow cancellation during archive close.
995  . ZipArchive::replaceFile to replace an entry content.
996  . ZipArchive::isCompressionMethodSupported to check optional compression
997    features.
998  . ZipArchive::isEncryptionMethodSupported to check optional encryption
999    features.
1000
1001========================================
10027. New Classes and Interfaces
1003========================================
1004
1005- Tokenizer:
1006  . The new PhpToken class adds an object-based interface to the tokenizer.
1007    It provides a more uniform and ergonomic representation, while being more
1008    memory efficient and faster.
1009    RFC: https://wiki.php.net/rfc/token_as_object
1010
1011========================================
10128. Removed Extensions and SAPIs
1013========================================
1014
1015- XML-RPC:
1016  . The xmlrpc extension has been unbundled and moved to PECL.
1017    RFC: https://wiki.php.net/rfc/unbundle_xmlprc
1018
1019========================================
10209. Other Changes to Extensions
1021========================================
1022
1023- CURL:
1024  . The CURL extension now requires at least libcurl 7.29.0.
1025  . curl_init() will now return a CurlHandle object rather than a resource.
1026    Return value checks using is_resource() should be replaced with
1027    checks for `false`. The curl_close() function no longer has an effect,
1028    instead the CurlHandle instance is automatically destroyed if it is no
1029    longer referenced.
1030  . curl_multi_init() will now return a CurlMultiHandle object rather than a
1031    resource. Return value checks using is_resource() should be replaced with
1032    checks for `false`. The curl_multi_close() function no longer has an effect,
1033    instead the CurlMultiHandle instance is automatically destroyed if it is no
1034    longer referenced.
1035  . curl_share_init() will now return a CurlShareHandle object rather than a
1036    resource. Return value checks using is_resource() should be replaced with
1037    checks for `false`. The curl_share_close() function no longer has an effect,
1038    instead the CurlShareHandle instance is automatically destroyed if it is no
1039    longer referenced.
1040  . The deprecated parameter `$version` of curl_version() has been removed.
1041
1042- Date:
1043  . DatePeriod now implements IteratorAggregate (instead of Traversable).
1044
1045- DOM:
1046  . DOMNamedNodeMap now implements IteratorAggregate (instead of Traversable).
1047  . DOMNodeList now implements IteratorAggregate (instead of Traversable).
1048
1049- Intl:
1050  . IntlBreakIterator now implements IteratorAggregate (instead of Traversable).
1051  . ResourceBundle now implements IteratorAggregate (instead of Traversable).
1052
1053- Enchant:
1054  . The enchant extension now uses libenchant-2 by default when available.
1055    libenchant version 1 is still supported but is deprecated and could
1056    be removed in the future.
1057
1058- GD:
1059  . The $num_points parameter of imagepolygon(), imageopenpolygon() and
1060    imagefilledpolygon() is now optional, i.e. these functions may be called
1061    with either 3 or 4 arguments. If the arguments is omitted, it is calculated
1062    as count($points)/2.
1063  . The function imagegetinterpolation() to get the current interpolation method
1064    has been added.
1065
1066- JSON:
1067  . The JSON extension cannot be disabled anymore and is always an integral part
1068    of any PHP build, similar to the date extension.
1069
1070- MBString:
1071  . The Unicode data tables have been updated to version 13.0.0.
1072
1073- PDO:
1074  . PDOStatement now implements IteratorAggregate (instead of Traversable).
1075
1076- LibXML:
1077  . The minimum required libxml version is now 2.9.0. This means that external
1078    entity loading is now guaranteed to be disabled by default, and no extra
1079    steps need to be taken to protect against XXE attacks.
1080
1081- MySQLi / PDO MySQL:
1082  . When mysqlnd is not used (which is the default and recommended option),
1083    the minimum supported libmysqlclient version is now 5.5.
1084  . mysqli_result now implements IteratorAggregate (instead of Traversable).
1085
1086- PGSQL / PDO PGSQL:
1087  . The PGSQL and PDO PGSQL extensions now require at least libpq 9.1.
1088
1089- Readline:
1090  . Calling readline_completion_function() before the interactive prompt starts
1091    (e.g. in auto_prepend_file) will now override the default interactive prompt
1092	completion function. Previously, readline_completion_function() only worked
1093	when called after starting the interactive prompt.
1094
1095- SimpleXML:
1096  . SimpleXMLElement now implements RecursiveIterator and absorbed the
1097    functionality of SimpleXMLIterator. SimpleXMLIterator is an empty extension
1098    of SimpleXMLElement.
1099
1100- Shmop:
1101  . shmop_open() will now return a Shmop object rather than a resource. Return
1102    value checks using is_resource() should be replaced with checks for `false`.
1103    The shmop_close() function no longer has an effect, and is deprecated;
1104    instead the Shmop instance is automatically destroyed if it is no longer
1105    referenced.
1106
1107========================================
110810. New Global Constants
1109========================================
1110
1111- Filter:
1112  . FILTER_VALIDATE_BOOL has been added as an alias for FILTER_VALIDATE_BOOLEAN.
1113    The new name is preferred, as it uses the canonical type name.
1114
1115========================================
111611. Changes to INI File Handling
1117========================================
1118
1119- zend.exception_string_param_max_len
1120  . New INI directive to set the maximum string length in an argument of a
1121    stringified stack strace.
1122
1123- com.dotnet_version
1124  . New INI directive to choose the version of the .NET framework to use for
1125    dotnet objects.
1126
1127========================================
112812. Windows Support
1129========================================
1130
1131- Standard:
1132  . Program execution functions (proc_open(), exec(), popen() etc.) using the
1133    shell now consistently execute `%comspec% /s /c "$commandline"`, which has
1134    the same effect as executing `$commandline` (without additional quotes).
1135
1136- GD:
1137  . php_gd2.dll has been renamed to php_gd.dll.
1138
1139- php-test-pack:
1140  . The test runner has been renamed from run-test.php to run-tests.php, to
1141    match its name in php-src.
1142
1143========================================
114413. Other Changes
1145========================================
1146
1147- EBCDIC targets are no longer supported, though it's unlikely that they were
1148  still working in the first place.
1149
1150========================================
115114. Performance Improvements
1152========================================
1153
1154- A Just-In-Time (JIT) compiler has been added to the opcache extension.
1155- array_slice() on an array without gaps will no longer scan the whole array to
1156  find the start offset. This may significantly reduce the runtime of the
1157  function with large offsets and small lengths.
1158- strtolower() now uses a SIMD implementation when using the "C" LC_CTYPE
1159  locale (which is the default).
1160