Actually, it's 8.4.1; between tagging 8.4 and the announcement, security fixes were applied which meant bumping the version number.

The highlights are here:
https://www.php.net/releases/8.4/en.php

The highlights of the highlights:

  • Property hooks. Previous PHP had (and it still has) magic __get and __set methods for getting your object to pretend to have properties it doesn't actually have. These were awkward for several reasons, not the least of which being that such properties were invisible to IDEs and static analysis (since they didn't actually exist). With property hooks you can declare an ordinary object property, while attaching your own getter/setter code to them to be invoked when they're accessed. The magic methods are still there, suitable for situations where you want your object to be able to respond to arbitrary property names being thrown at it, but if you know what those names are in advance (like, your __get is just a big switch listing them), then property hooks may well be the way to go.

  • Asymmetric Visibility. Now you can make a property that is public for reading, but writeable only privately. Previously, if you wanted that sort of control you had to make the property private and write getters and setters with the visibility you wanted.

  • #[\Deprecated] Attribute
    You know how PHP deprecates things well in advance of their removal, to give you notice and time to upgrade: when a deprecated feature is used a message is logged notifying you. Now PHP library and application authors can use that mechanism in their own products.

  • New ext-dom features and HTML5 support. Because PHP's HTML parsing and DOM manipulation facilities really needed it. The new DOM (the old one remains for legacy support) has its own namespace.

  • Object API for BCMath. Up until now, big-number arithmetic using the BCMath extension involved passing strings of digits back and forth between various bc*() functions. Now the bignums have their own class (\BcMath\Number) and can be used with arithmetic and comparison operators directly (e.g. for Numbers $num1 and $num2 you can write $result = $num1 + $num2; to get their sum, and $result will also be a Number). They also implement __toString, so you can get that string of digits back at the end when you expect to. (Oh, and did I mention it's now quite a bit faster, precisely because it's not constantly converting back and forth between those strings of digits?)

  • New array_*() functions. I use array functions probably way too much. Without looking at the new array_find() function, how would you find an element of an array that returns true for some test?

  • PDO driver specific subclasses. For a long time, even PDO assumed everyone was using MySQL: it had to in order to accommodate MySQL/MariaDB's syntax quirks. This was especially problematic when it came to how identifiers and strings were quoted in SQL. It also meant that when you created a PDO connection object, it came with a whole bunch of methods that had nothing to do with the database you were connecting to. Now, each DBMS has its own subclass of PDO.

  • new MyClass()->method() without parentheses. Instead of (new MyClass())->method().

And a bunch more things. Lazy objects, a new JIT compiler, round() gets additional rounding modes (and an Enum that lists the modes), the ICU library has been bumped to version 75 and PCRE to 10.44...

Being a minor release, there are some BC breaks and deprecations: if a function parameter can be nullable then you're warned if you don't explicitly say so, a few extensions that have basically been dead for however long have been packed off to PECL, E_STRICT is a deprecated error reporting level, some mysqli features have been deprecated, ...

The release announcement is linked above. The migration guide is where you expect it:
https://www.php.net/manual/en/migration84.php

12 days later

Good write-up.

Of course, I wouldn't expect anything less from the learned Father of the Board.....

A tweak tosprintf.
Just fiddling around and stumbled on this change.

Consider the statement $m =sprintf("Message (%s): %s\n", date('Y-m-d h:i:s'), $message_slug);. This could have been written more performantly as $m = "Message (" . date('Y-m-d h:i:s') . "): $message_slug\n";, but that's harder to read and more fraught if the format changes.

In PHP 8.3, the bytecode for that sprintf call would look something like:

INIT_FCALL 3 128 string("sprintf")
SEND_VAL string("Message (%s): %s\n") 1
INIT_FCALL 1 96 string("date")
SEND_VAL string("Y-m-d h:i:s") 1
V1 = DO_ICALL
SEND_VAR V1 2
SEND_VAR CV0($message_slug) 3
V2 = DO_ICALL

In 8.4, it becomes

INIT_FCALL 1 96 string("date")
SEND_VAL string("Y-m-d h:i:s") 1
V1 = DO_ICALL
T3 = ROPE_INIT 5 string("Message (")
T3 = ROPE_ADD 1 T3 V1
T3 = ROPE_ADD 2 T3 string("): ")
T3 = ROPE_ADD 3 T3 CV0($message_slug)
T2 = ROPE_END 4 T3 string("\n")

Yes, that's exactly what it looks like: what you'd have if you'd written $temp = date('Y-m-d h:i:s'); $m ="Message ($temp): $message_slug\n";

Basically, what happens is that a v?[sf]?printf() call in which the format pattern contains only plain %s (and %d) specifiers is converted into concatenations before being compiled to bytecode. PHP is very efficient at concatenating strings, and this also saves the costs of a function call and parsing the format string. Win-win-win.

There are limitations. As soon as any format specifier gets fancier (like %14s) then it's back to a sprintf call. Also, the format string has to be provided literally, so it won't work if said format came from, say, an i18n multilingual collection.

    Write a Reply...