PHP 8.4 Major Update Features Are Here!

5 min read Original article ↗

Frederick Taylor

PHP 8.4 marks a significant update to the PHP language. It introduces a variety of new features, such as property hooks, asymmetric visibility, an updated DOM API, performance enhancements, bug fixes, and general cleanups.

Preparation

First, set up the PHP development environment. Open ServBay, select the PHP 8.4 package, and in just about 3 minutes, your PHP 8.4 development environment will be ready.

Press enter or click to view image in full size

Next, let’s take a look at the updates in PHP 8.4 compared to previous versions.

Property Hooks

Property hooks provide support for computed properties that can be directly understood by IDEs and static analysis tools, eliminating the need to write potentially invalid docblock comments. They also allow for reliable preprocessing or postprocessing of values without checking for matching getters or setters in the class.

Not PHP 8.4

class Locale
{
private string $languageCode;
private string $countryCode;

public function __construct(string $languageCode, string $countryCode)
{
$this->setLanguageCode($languageCode);
$this->setCountryCode($countryCode);
}

public function getLanguageCode(): string
{
return $this->languageCode;
}

public function setLanguageCode(string $languageCode): void
{
$this->languageCode = $languageCode;
}

public function getCountryCode(): string
{
return $this->countryCode;
}

public function setCountryCode(string $countryCode): void
{
$this->countryCode = strtoupper($countryCode);
}

public function setCombinedCode(string $combinedCode): void
{
[$languageCode, $countryCode] = explode('_', $combinedCode, 2);

$this->setLanguageCode($languageCode);
$this->setCountryCode($countryCode);
}

public function getCombinedCode(): string
{
return \sprintf("%s_%s", $this->languageCode, $this->countryCode);
}
}

$brazilianPortuguese = new Locale('pt', 'br');
var_dump($brazilianPortuguese->getCountryCode()); // BR
var_dump($brazilianPortuguese->getCombinedCode()); // pt_BR

PHP 8.4

class Locale
{
public string $languageCode;

public string $countryCode
{
set (string $countryCode) {
$this->countryCode = strtoupper($countryCode);
}
}

public string $combinedCode
{
get => \sprintf("%s_%s", $this->languageCode, $this->countryCode);
set (string $value) {
[$this->countryCode, $this->languageCode] = explode('_', $value, 2);
}
}

public function __construct(string $languageCode, string $countryCode)
{
$this->languageCode = $languageCode;
$this->countryCode = $countryCode;
}
}

$brazilianPortuguese = new Locale('pt', 'br');
var_dump($brazilianPortuguese->countryCode); // BR
var_dump($brazilianPortuguese->combinedCode); // pt_BR

Asymmetric Visibility

You can now independently control the write and read scopes of properties, reducing the need to write cumbersome getter methods to expose property values while preventing modifications from outside the class.

Not PHP 8.4

class PhpVersion
{
public string $version = '8.3';
}

$phpVersion = new PhpVersion();
var_dump($phpVersion->version); // string(3) "8.3"
$phpVersion->version = 'PHP 8.4'; // No error

PHP 8.4

class PhpVersion
{
public private(set) string $version = '8.4';
}

$phpVersion = new PhpVersion();
var_dump($phpVersion->version); // string(3) "8.4"
$phpVersion->version = 'PHP 8.3'; // Visibility error

#[\Deprecated] Attribute

The new #[\Deprecated] attribute allows PHP’s existing deprecation mechanism to be applied to user-defined functions, methods, and class constants.

Not PHP 8.4

class PhpVersion
{
/**
* @deprecated 8.3 use PhpVersion::getVersion() instead
*/
public function getPhpVersion(): string
{
return $this->getVersion();
}

public function getVersion(): string
{
return '8.3';
}
}

$phpVersion = new PhpVersion();
// No indication that the method is deprecated.
echo $phpVersion->getPhpVersion();

PHP 8.4

class PhpVersion
{
#[\Deprecated(
message: "use PhpVersion::getVersion() instead",
since: "8.4",
)]
public function getPhpVersion(): string
{
return $this->getVersion();
}

public function getVersion(): string
{
return '8.4';
}
}

$phpVersion = new PhpVersion();
// Deprecated: Method PhpVersion::getPhpVersion() is deprecated since 8.4, use PhpVersion::getVersion() instead
echo $phpVersion->getPhpVersion();

New ext-dom Features and HTML5 Support

The new DOM API includes standard-compliant support for parsing HTML5 documents, fixing several long-standing normative bugs in DOM functionality, and adding several functions to facilitate document handling. The new DOM API can be used within the Dom namespace. You can create documents using the Dom\HTMLDocument and Dom\XMLDocument classes.

Not PHP 8.4

$dom = new DOMDocument();
$dom->loadHTML(
<<<'HTML'
<main>
<article>PHP 8.4 is a feature-rich release!</article>
<article class="featured">PHP 8.4 adds new DOM classes that are spec-compliant, keeping the old ones for compatibility.</article>
</main>
HTML,
LIBXML_NOERROR,
);

$xpath = new DOMXPath($dom);
$node = $xpath->query(".//main/article[not(following-sibling::*)]")[0];
$classes = explode(" ", $node->className); // Simplified
var_dump(in_array("featured", $classes)); // bool(true)

PHP 8.4

$dom = Dom\HTMLDocument::createFromString(
<<<HTML
<main>
<article>PHP 8.4 is a feature-rich release!</article>
<article class="featured">PHP 8.4 adds new DOM classes that are spec-compliant, keeping the old ones for compatibility.</article>
</main>
HTML,
LIBXML_NOERROR,
);

$node = $dom->querySelector('main > article:last-child');
var_dump($node->classList->contains("featured")); // bool(true)

New array_*() Functions

New functions array_find(), array_find_key(), array_any(), and array_all() have been added.

Not PHP 8.4

$animal = null;
foreach (['dog', 'cat', 'cow', 'duck', 'goose'] as $value) {
if (str_starts_with($value, 'c')) {
$animal = $value;
break;
}
}

var_dump($animal); // string(3) "cat"

PHP 8.4

$animal = array_find(
['dog', 'cat', 'cow', 'duck', 'goose'],
static fn(string $value): bool => str_starts_with($value, 'c'),
);

var_dump($animal); // string(3) "cat"

Driver-Specific SQL Parsers for PDO

New subclasses like Pdo\Dblib, Pdo\Firebird, Pdo\MySql, Pdo\Odbc, and Pdo\Sqlite are now available.

Not PHP 8.4

$connection = new PDO(
'sqlite:foo.db',
$username,
$password,
); // object(PDO)

$connection->sqliteCreateFunction(
'prepend_php',
static fn ($string) => "PHP {$string}",
);
$connection->query('SELECT prepend_php(version) FROM php');

PHP 8.4

$connection = PDO::connect(
'sqlite:foo.db',
$username,
$password,
); // object(Pdo\Sqlite)

$connection->createFunction(
'prepend_php',
static fn ($string) => "PHP {$string}",
); // Does not exist on a mismatching driver.
$connection->query('SELECT prepend_php(version) FROM php');

Accessing Methods Without Parentheses

You can now access properties and methods of newly instantiated objects without wrapping the new expression in parentheses.

Not PHP 8.4

class PhpVersion
{
public function getVersion(): string
{
return 'PHP 8.3';
}
}

var_dump((new PhpVersion())->getVersion());

PHP 8.4

class PhpVersion
{
public function getVersion(): string
{
return 'PHP 8.4';
}
}

var_dump(new PhpVersion()->getVersion());

New Classes, Interfaces, and Functions

  • A new JIT implementation based on the IR framework.
  • Added request_parse_body() function.
  • New functions: bcceil(), bcdivmod(), bcfloor(), and bcround().
  • Introduced RoundingMode enum for round(), including four new rounding modes: TowardsZero, AwayFromZero, NegativeInfinity, and PositiveInfinity.
  • New methods for DateTime and DateTimeImmutable: createFromTimestamp(), getMicrosecond(), setMicrosecond().
  • Added mb_trim(), mb_ltrim(), mb_rtrim(), mb_ucfirst(), and mb_lcfirst() functions.
  • New functions: pcntl_getcpu(), pcntl_getcpuaffinity(), pcntl_getqos_class(), pcntl_setns(), and pcntl_waitid().
  • New methods: ReflectionClassConstant::isDeprecated(), ReflectionGenerator::isClosed(), and ReflectionProperty::isDynamic().
  • New functions: http_get_last_response_headers(), http_clear_last_response_headers(), and fpow().
  • New methods for XML handling: XMLReader::fromStream(), XMLReader::fromUri(), XMLReader::fromString(), XMLWriter::toStream(), XMLWriter::toUri(), and XMLWriter::toMemory().
  • New function: grapheme_str_split().

Deprecations and Backward Incompatibilities

  • The IMAP, OCI8, PDO_OCI, and pspell extensions have been removed from PHP and moved to PECL.
  • Implicit nullable parameter types are now deprecated.
  • Using _ as a class name is deprecated.
  • Negative powers of zero are deprecated.
  • Passing invalid modes to round() will throw a ValueError.
  • Class constants from the date, intl, pdo, reflection, spl, sqlite, and xmlreader extensions are now strongly typed.
  • The GMP class is now final.
  • Removed constants: MYSQLI_SET_CHARSET_DIR, MYSQLI_STMT_ATTR_PREFETCH_ROWS, MYSQLI_CURSOR_TYPE_FOR_UPDATE, MYSQLI_CURSOR_TYPE_SCROLLABLE, and MYSQLI_TYPE_INTERVAL.
  • The functions mysqli_ping(), mysqli_kill(), mysqli_refresh(), and their corresponding methods mysqli::ping(), mysqli::kill(), mysqli::refresh(), along with MYSQLI_REFRESH_* constants are deprecated.
  • stream_bucket_make_writeable() and stream_bucket_new() now return StreamBucket instances instead of stdClass.
  • Changes to exit() behavior.
  • The E_STRICT constant is deprecated.

Conclusion

PHP 8.4 brings a wealth of new features and improvements that enhance the language’s usability and performance. Developers can now leverage property hooks, asymmetric visibility, and a more robust DOM API, among other enhancements. However, it’s important to be aware of deprecated features and backward incompatible changes when upgrading to ensure a smooth transition. ServBay helps you embrace the new features and enjoy coding with PHP 8.4!