PHP 8.3 New Features Explained
By Pawan Singh · Jun 2026
PHP 8.3 is an incremental release rather than a rewrite, but a few additions are genuinely useful in day-to-day code — here's what actually matters, not the full changelog.
Typed Class Constants
Class constants can now declare a type, closing a long-standing gap where constants were the one place in a class without type enforcement:
class Status
{
const string ACTIVE = 'active';
const string ARCHIVED = 'archived';
}
Attempting to declare a constant with a value that doesn't match its type is now a fatal error at compile time, not something that surfaces later as a subtle bug.
Dynamic Class Constant Fetch
Previously, reading a class constant by a variable name required the awkward constant() function. PHP 8.3 lets you use the same {$var} syntax already familiar from dynamic property/method access:
$name = 'ACTIVE';
echo Status::{$name}; // 'active'
The #[\Override] Attribute
A common refactoring bug: renaming a parent class's method and forgetting to update every child override, which silently stops overriding anything. The new #[\Override] attribute makes intent explicit and turns that mistake into a compile error:
class Base
{
public function handle(): void {}
}
class Child extends Base
{
#[\Override]
public function handle(): void {} // fine
#[\Override]
public function handel(): void {} // fatal error: typo, not actually overriding anything
}
json_validate()
Before 8.3, checking whether a string was valid JSON meant calling json_decode() and checking json_last_error() — wasteful if you only care about validity, not the decoded value, since it fully parses and allocates the result either way:
if (json_validate($rawInput)) {
// valid JSON, decode it now if you actually need the data
}
json_validate() checks syntax without building the PHP value, which is meaningfully cheaper for large payloads you're just gatekeeping.
Readonly Properties Can Now Be Modified During Cloning
Readonly properties were, until 8.3, permanently locked after construction — including inside __clone(), which made "clone with one field changed" patterns require reconstructing the whole object. Now a readonly property can be reassigned from within the scope of the class doing the cloning:
final class Point
{
public function __construct(
public readonly int $x,
public readonly int $y,
) {}
public function withX(int $x): static
{
$clone = clone $this;
$clone->x = $x; // allowed in 8.3, was a fatal error before
return $clone;
}
}
This is the one change here most likely to actually simplify code you've already written — immutable value objects with "with-style" modifiers no longer need manual reconstruction.
New Randomizer Methods
The Random\Randomizer class (introduced in 8.2) picked up getFloat(), nextFloat(), and getBytesFromString() — giving cryptographically-aware random floats and constrained-alphabet random strings without hand-rolling them from random_int().
Should You Upgrade?
None of this is a breaking-change minefield the way some major PHP versions have been — 8.3 is a safe upgrade for most codebases. The typed constants and #[\Override] attribute are worth adopting immediately in new code even if you don't touch anything else, since both catch real bugs at compile time that would otherwise surface at runtime, often in production.
Need help planning or executing a PHP version upgrade? Get in touch — I work as a freelance PHP developer.