Repository navigation
PHP 8.6: Optimized printf changes compile-time acceptance of discarded expressions #24794
Description
Description
Summary
PHP 8.6.0RC4 changes whether certain expressions containing an unsupported (unset) cast are accepted during compilation, depending on whether a function call follows an optimized or ordinary compilation path.
This produces different results for direct printf() calls and dynamic calls. Some expressions accepted by PHP 8.5 are rejected by PHP 8.6, while other expressions previously rejected are now accepted.
Minimal reproducer
<?php
printf(true || (unset)$x);Actual behavior:
- PHP 8.5.10: Compilation succeeds.
- PHP 8.6.0RC4: Compilation fails with:
Fatal error: The (unset) cast is no longer supported
Dynamic-call control
<?php
$f = "printf";
$f(true || (unset)$x);Both PHP 8.5.10 and PHP 8.6.0RC4 accept this during compilation.
Opposite acceptance difference
<?php
printf(false ? (unset)$x : "ok");- PHP 8.5.10: Compilation fails with the unsupported
(unset)cast diagnostic. - PHP 8.6.0RC4: Compilation succeeds.
These results occur during compilation, without executing the examples.
Expected behavior / clarification requested
Is optimization-specific traversal intended to change compile-time PHP source validity, or should optimized and ordinary calls enforce the same validity rules?
In particular, which behavior is intended for the logical short-circuit and conditional-expression examples above?
Related observations involve sprintf(), qualified and imported calls, named arguments, unpacking, partial function application, and constant initializers. These appear to follow different compilation paths, but the examples above demonstrate the central inconsistency.
Affected versions
- PHP 8.5.10 — Windows x64
- PHP 8.6.0RC4 — Windows x64, NTS, VC2022
- PHP 8.6 source commit:
f23b4c222cebe33be93ee8ecaaa14390c5507a08
The PHP 8.6 executable was built from the specified source commit.
Reproduce with:
php -n -l example.phpCLI OPcache and JIT were disabled. This behaviour is related to compiler lowering and constant-expression traversal, not runtime optimization.
Relevant implementation
- [zend_compile_func_printf]()
Line 5264 in f23b4c2
static zend_result zend_compile_func_printf(znode *result, zend_ast_list *args) /* {{{ */ - [zend_compile_func_sprintf]()
Line 5096 in f23b4c2
static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args) /* {{{ */ - [zend_eval_const_expr]()
Line 12920 in f23b4c2
static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */ - [Related PR #19658](re-use
sprintf()optimisation forprintf()#19658)
The optimized call compilation path appears to traverse constant expressions differently from ordinary call compilation.
I would appreciate clarification on whether these differences are intentional language behaviour or an unintended consequence of compilation optimization.
PHP Version
PHP 8.6.0RC4 (cli) (built: Oct 25 2026 12:45:36) (NTS Visual C++ 2022 x64)
Copyright © The PHP Group and Contributors
Zend Engine v4.6.0RC4, Copyright © Zend by Perforce
with Zend OPcache v8.6.0RC4, Copyright ©, by Zend by Perforce
Operating System
Windows x64 (64-bit), MSVC 2022 build
Activity
iluuu1994 commentedon Oct 27, 2026
Hi @alwyn1024. Thanks for the report. As with GH-24795, this has the same root cause. This is unrelated to
printf(),true || (unset)$xalone reproduces the issue. So I'm closing this as a wontfix with the same argumentation. Thanks anyway. 🙂alwyn1024 commentedon Oct 28, 2026
Thank you for clarifying @iluuu1994 , much appreciated.