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(), andbcround(). - Introduced
RoundingModeenum forround(), including four new rounding modes:TowardsZero,AwayFromZero,NegativeInfinity, andPositiveInfinity. - New methods for
DateTimeandDateTimeImmutable:createFromTimestamp(),getMicrosecond(),setMicrosecond(). - Added
mb_trim(),mb_ltrim(),mb_rtrim(),mb_ucfirst(), andmb_lcfirst()functions. - New functions:
pcntl_getcpu(),pcntl_getcpuaffinity(),pcntl_getqos_class(),pcntl_setns(), andpcntl_waitid(). - New methods:
ReflectionClassConstant::isDeprecated(),ReflectionGenerator::isClosed(), andReflectionProperty::isDynamic(). - New functions:
http_get_last_response_headers(),http_clear_last_response_headers(), andfpow(). - New methods for XML handling:
XMLReader::fromStream(),XMLReader::fromUri(),XMLReader::fromString(),XMLWriter::toStream(),XMLWriter::toUri(), andXMLWriter::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 aValueError. - 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, andMYSQLI_TYPE_INTERVAL. - The functions
mysqli_ping(),mysqli_kill(),mysqli_refresh(), and their corresponding methodsmysqli::ping(),mysqli::kill(),mysqli::refresh(), along withMYSQLI_REFRESH_*constants are deprecated. stream_bucket_make_writeable()andstream_bucket_new()now returnStreamBucketinstances instead ofstdClass.- Changes to
exit()behavior. - The
E_STRICTconstant 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!