PHP 8.5 Released!

PHP 8.5 is a major update of the PHP language. It contains many new features, such as the new URI extension, support for modifying properties while cloning, the Pipe operator, performance improvements, bug fixes, and general cleanup.

Upgrade to PHP 8.5 now!

Logo PHP 8.5

New URI Extension

As an always-available part of PHP's standard library the new URI extension provides APIs to parse and modify URIs and URLs according to the RFC 3986 and the WHATWG URL standards.

The secure and standards-compliant URI parsing is powered by the uriparser (RFC 3986) and Lexbor (WHATWG URL) libraries.

use Uri\Rfc3986\Uri;
$components = parse_url("https://php.net/releases/8.5/en.php");
$uri = new Uri("https://php.net/releases/8.5/en.php");
var_dump($components['host']);
var_dump($uri->getHost());
// string(7) "php.net"

Related RFC: Add RFC 3986 and WHATWG URL compliant API

Clone with

It is now possible to update properties during object cloning by passing an associative array with the updated to the clone() function. This enables straight-forward support of the "with-er" pattern for readonly classes.

final readonly class PhpVersion
{
public function __construct(
public string $version = 'PHP 8.4',
) {}
public functionwithVersion(string $version): self
{
$newObject = clone $this;
$newObject->version = $version;
return $newObject;
return clone($this, [
'version' => $version,
]);
}
}
$version = new PhpVersion();
var_dump($version->version);
// string(7) "PHP 8.4"
var_dump($version->withVersion('PHP 8.5')->version);
// Fatal error: Uncaught Error: Cannot modify readonly property PhpVersion::$version
// string(7) "PHP 8.5"
var_dump($version->version);
// string(7) "PHP 8.4"

Related RFC: Clone with v2

Pipe operator

The pipe operator allows chaining function calls together without dealing with intermediary variables. That can be especially helpful when replacing many "nested calls" with a chain that can be read forwards, rather than inside-out.

Learn more about the backstory of this feature in The PHP Foundation’s blog.

$input = ' Some kind of string. ';
$output = strtolower(
str_replace(['.', '/', '…'], '',
str_replace(' ', '-',
trim($input)
)
)
);
$output = $input
|> trim(...)
|> (fn($string) => str_replace(' ', '-', $string))
|> (fn($string) => str_replace(['.', '/', '…'], '', $string))
|> strtolower(...);
var_dump($output);
// string(19) "some-kind-of-string"

Related RFC: Pipe operator v3

#[\NoDiscard] Attribute

By adding the #[\NoDiscard] attribute to a function, PHP will check whether the returned value is consumed and emit a warning if it is not. This allows to improve the safety of APIs where the returned value is important, but where it is easy to forget using the return value by accident.

The associated (void) cast can be used to indicate that a value is intentionally unused.

#[\NoDiscard]
function getPhpVersion(): string
{
'PHP 8.5';
}
getPhpVersion();
// No Errors
// Warning: The return value of function getPhpVersion() should either be used or intentionally ignored by casting it as (void)

Related RFC: Marking return values as important (#[\NoDiscard])

Closures and First Class Callables in Constant Expressions

final class CalculatorTest extends \PHPUnit\Framework\TestCase
{
#[DataProvider('subtractionProvider')]
public function testSubtraction(
int $minuend,
int $subtrahend,
int $result
): void
{
$this->assertSame(
$result,
Calculator::subtract($minuend, $subtrahend)
);
}
public static function subtractionProvider(): iterable
{
for ($i = -10; $i <= 10; $i++) {
yield [$i, $i, 0];
yield [$i, 0, $i];
yield [0, $i, -$i
}
}
}
final class CalculatorTest
{
#[Test\CaseGenerator(static function (): iterable
{
for ($i = -10; $i <= 10; $i++) {
yield [$i, $i, 0];
yield [$i, 0, $i];
yield [0, $i, -$i];
}
})]
public function testSubtraction(
int $minuend,
int $subtrahend,
int $result
)
{
\assert(
Calculator::subtract($minuend, $subtrahend) === $result
);
}
}

Related RFC: First Class Callables in constant expressions, Support Closures in constant expressions

Persistent cURL Share Handles

New CurlSharePersistentHandle class, curl_multi_get_handles(), curl_share_init_persistent() functions are available.

$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
$sh = curl_share_init_persistent([
CURL_LOCK_DATA_DNS,
CURL_LOCK_DATA_CONNECT
]);
$ch1 = curl_init('https://php.net/');
curl_setopt($ch1, CURLOPT_SHARE, $sh);
curl_exec($ch1);
$ch2 = curl_init('https://thephp.foundation/');
curl_setopt($ch2, CURLOPT_SHARE, $sh);
curl_exec($ch2);

Related RFC: Add persistent curl share handles, Persistent curl share handle improvement

New array_first() and array_last() functions

New CurlSharePersistentHandle class, curl_multi_get_handles(), curl_share_init_persistent() functions are available.

$php = [
'php-82' => ['state' => 'security', 'branch' => 'PHP-8.2'],
'php-83' => ['state' => 'active', 'branch' => 'PHP-8.3'],
'php-84' => ['state' => 'active', 'branch' => 'PHP-8.4'],
'php-85' => ['state' => 'upcoming', 'branch' => 'PHP-8.5'],
];
$upcomingRelease = null;
foreach ($php as $key => $version) {
if ($version['state'] === 'upcoming') {
$upcomingRelease = $version;
break;
}
}
$upcomingRelease = array_first(
array_filter(
$php,
static fn($version) => $version['state'] === 'upcoming'
)
);
var_dump($upcomingRelease);

Related RFC: array_first() and array_last()

New Classes, Interfaces, and Functions

  • Property Promotion is now available for final
  • Attributes are now available for constants
  • Attribute #[\Override] now works on properties
  • Attribute #[\Deprecated] available for traits
  • Asymmetric Visibility for Static Properties
  • New #[\DelayedTargetValidation] attribute is available
  • New get_error_handler(), get_exception_handler() functions are available.
  • New Closure::getCurrent method is available.
  • New Dom\Element::getElementsByClassName() and Dom\Element::insertAdjacentHTML() methods are available.
  • New enchant_dict_remove_from_session() and enchant_dict_remove() functions are available.
  • New grapheme_levenshtein() function is available.
  • New opcache_is_script_cached_in_file_cache() function is available.
  • New ReflectionConstant::getFileName(), ReflectionConstant::getExtension(), ReflectionConstant::getExtensionName(), ReflectionConstant::getAttributes(), and ReflectionProperty::getMangledName() methods are available.

Deprecations and backward compatibility breaks

There are no deprecations or compatibility breaks.

Better performance, better syntax, improved type safety.

For source downloads of PHP 8.5 please visit the downloads page. Windows binaries can be found on the PHP for Windows site. The list of changes is recorded in the ChangeLog.

The migration guide is available in the PHP Manual. Please consult it for a detailed list of new features and backward-incompatible changes.

Upgrade to PHP 8.5 now!

Logo PHP 8.5