PHP 8.3: Major Features
A refinement release for teams on PHP 8.2.x: stronger invariants (#[Override], typed constants), better JSON and string ergonomics (json_validate, str_increment/str_decrement), and a long tail of small runtime changes that show up under load or in edge-case code paths.
Table of Contents
#[\Override]â catch missing overrides at compile time- Typed class constants
- Readonly: anonymous classes & cloning
- Language quality-of-life
- New functions worth adopting (
json_validate,str_*, DOM, Random) - Backward incompatible changes (migration notes)
- Deprecations (increment/decrement strings,
get_class(), assert INI) - Other changes & operations (gc_status, streams, highlights)
PHP 8.3 is less about one headline feature and more about tightening contracts: you can express typed constants, verify overrides with #[\Override], and validate JSON without decodingâwhile the engine and standard library get stricter in places (range(), proc_get_status(), Date/ DOM exceptions). Plan for extra QA around string increment/decrement (deprecated operators, new helpers), reflection (ReflectionProperty::setValue), and assert configuration (INI settings and assert_options() deprecated).
#[\Override] â catch missing overrides at compile time
Mark methods that are intended to override a parent or interface. If the name is wrong or the parent removes the method, PHP fails early instead of silently introducing a new method.
interface Logger
{
public function log(string $message): void;
}
final class FileLogger implements Logger
{
#[\Override]
public function log(string $message): void
{
// ...
}
}
Use this especially in large codebases where refactors rename interface methods.
Typed class constants
Constants on classes, interfaces, traits, and enums can declare types, aligning constants with the rest of the type system.
interface Config
{
public const string APP_NAME = 'MyApp';
}
This reduces âwrong constant typeâ bugs that previously surfaced only at use sites.
Readonly: anonymous classes & cloning
- Anonymous classes may be declared
readonly. - Readonly properties can be reinitialized during
clone(when the object graph allows), which makes immutable clones less painful than in 8.2-only patterns.
Language quality-of-life
- Dynamic class constant access:
SomeClass::{$name}for runtime constant names. - Static variable initializers may use arbitrary expressions (not only constants).
finalon trait methods when importing a trait method.- Closures from magic methods can receive named arguments when invoked.
php.ini: fallback/default value syntax for cleaner configuration.
New functions worth adopting (json_validate, str_*, DOM, Random)
json_validate()
Validate JSON without decoding into PHP valuesâideal for APIs, queues, and quick guards before expensive json_decode().
if (!json_validate($payload)) {
throw new InvalidArgumentException('Invalid JSON');
}
$data = json_decode($payload, true, flags: JSON_THROW_ON_ERROR);
str_increment() / str_decrement()
Preferred replacements for legacy ++/-- on strings (see deprecations). Use for alphanumeric counters where you previously relied on increment operators.
$next = str_increment('a9'); // predictable stepping without string ++
$prev = str_decrement($next);
DOM, Intl, Random, POSIX, etc.
PHP 8.3 adds many DOM methods (e.g. insertAdjacentElement, getRootNode, replaceChildren), Intl calendar helpers, Random helpers on Randomizer (getFloat, nextFloat, âŚ), and POSIX sysconf/pathconf/eaccessâuseful for system-level scripts and tooling.
Backward incompatible changes (migration notes)
Stack / timers / fibers
- Deep recursion near stack limits may now throw
Errorwhen exceedingzend.max_allowed_stack_size(minus reserved); fibers usefiber.stack_sizesimilarly. - Zend Max Execution Timers default on for ZTS builds on Linuxâwatch long-running CLI workers.
Processes
proc_get_status()on POSIX returns correct values on repeated calls; results may be cached (check the"cached"key).proc_close()afterproc_get_status()now yields correct exit codes (not-1).
Arrays & traits
- Class constant visibility: variance is now enforced when constants are inherited from interfacesâcode that relied on looser visibility may need fixes.
- Empty array + negative first index: next implicit key follows
n+1(not0). - Traits with static properties: inherited statics from the parent are redeclared per trait user (separate storage)âcan affect subtle static state.
Standard library (high impact)
range(): stricter validation (TypeError/ValueErrorfor bad inputs), more warnings for odd boundaries, different behavior for character ranges when boundaries look numericâre-test any code generating ranges from user input.number_format(): negative$decimalsnow rounds before the decimal point (previously ignored).file(): invalid flag combinations are rejected (e.g.FILE_APPENDwas silently accepted before).
Date / DOM / FFI / Opcache
- Date: richer
DateError/DateExceptionhierarchies instead of generic warnings/exceptionsâupdatecatchblocks. - DOM: spec-aligned behavior for nodes without parents;
createAttributeNS()fixes; new members may conflict with userland subclassesâensure compatible signatures. - FFI:
voidC functions returnnull, not a dummyFFI\CData:voidobject. - Opcache:
opcache.consistency_checksremoved (was broken with tracing JIT / inheritance cache).
WeakMap
- Self-referential keys in
WeakMapmay be collected in cycles where reachability is only through iterationâaudit exotic caching patterns.
Deprecations (increment/decrement strings, get_class(), assert INI)
String ++ / --
Increment/decrement on empty or non-numeric strings is deprecated; non-numeric increment is âsoft deprecatedâ. Prefer str_increment() / str_decrement() for new code.
get_class() / get_parent_class() without arguments
Calling them with no args is deprecatedâpass an object or class name explicitly.
Assert
assert_options()and related constants deprecated.assert.*INI settings deprecatedâmigrate to ini settings documented in PHP 8.3 migration âINI handlingâ notes.
Misc
- Reflection:
ReflectionProperty::setValue($value)(one arg) deprecated for static propsâpassnullas object for static. - SQLite3: prefer exceptions;
enableExceptions(false)emits deprecation. - Random:
MT_RAND_PHPvariant deprecated.
Other changes & operations (gc_status, streams, highlights)
gc_status()reports richer timing fields (collector/destructor/free time)âuseful when tuning memory-heavy workloads.- Streams:
fread()on sockets may return sooner when buffered data exists; memory streams behave more like files for seeks past end. open_basedir: runtimeini_setrejects paths with..even when prefixed with./.- highlight_string/file HTML output structure changedâif you snapshot tests of highlighted PHP, update baselines.
Closing thoughts
PHP 8.3 rewards teams that treat constants and overrides as part of the type surface: typed constants and #[\Override] reduce âsilent driftâ during refactors. Pair that with json_validate for cheap validation and a deliberate plan for string increment and assert deprecationsâthose are the changes most likely to surprise legacy codebases.