@@ -4956,6 +4956,45 @@ static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args)
49564956
49574957static zend_result zend_compile_func_printf (znode * result , zend_ast_list * args ) /* {{{ */
49584958{
4959+ /* Special case: printf with a single constant string argument and no format specifiers.
4960+ * In this case, just emit ECHO and return the string length if needed. */
4961+ if (args -> children == 1 ) {
4962+ zend_eval_const_expr (& args -> child [0 ]);
4963+ if (args -> child [0 ]-> kind == ZEND_AST_ZVAL ) {
4964+ zval * format_string = zend_ast_get_zval (args -> child [0 ]);
4965+ if (Z_TYPE_P (format_string ) == IS_STRING ) {
4966+ /* Check if there are any format specifiers */
4967+ char * p = Z_STRVAL_P (format_string );
4968+ char * end = p + Z_STRLEN_P (format_string );
4969+ bool has_format_specs = false;
4970+
4971+ while (p < end ) {
4972+ if (* p == '%' ) {
4973+ p ++ ;
4974+ if (p < end && * p != '%' ) {
4975+ has_format_specs = true;
4976+ break ;
4977+ }
4978+ }
4979+ p ++ ;
4980+ }
4981+
4982+ if (!has_format_specs ) {
4983+ /* No format specifiers - just emit ECHO and return string length */
4984+ znode format_node ;
4985+ zend_compile_expr (& format_node , args -> child [0 ]);
4986+ zend_emit_op (NULL , ZEND_ECHO , & format_node , NULL );
4987+
4988+ /* Return the string length as a constant if the result is used */
4989+ result -> op_type = IS_CONST ;
4990+ ZVAL_LONG (& result -> u .constant , Z_STRLEN_P (format_string ));
4991+ return SUCCESS ;
4992+ }
4993+ }
4994+ }
4995+ }
4996+
4997+ /* Fall back to sprintf optimization for format strings with specifiers */
49594998 znode rope_result ;
49604999 if (zend_compile_func_sprintf (& rope_result , args ) != SUCCESS ) {
49615000 return FAILURE ;
@@ -4964,7 +5003,7 @@ static zend_result zend_compile_func_printf(znode *result, zend_ast_list *args)
49645003 /* printf() returns the amount of bytes written, so just an ECHO of the resulting sprintf()
49655004 * optimisation might not be enough. At this early stage we can't detect if the result is
49665005 * actually used, so we just emit the opcodes and cleanup if they are not used in the
4967- * optimizer later. */
5006+ * optimizers block pass later. */
49685007 znode copy ;
49695008 zend_emit_op_tmp (& copy , ZEND_COPY_TMP , & rope_result , NULL );
49705009 zend_emit_op (NULL , ZEND_ECHO , & rope_result , NULL );
0 commit comments