Commit a7a49e039d7 for php

commit a7a49e039d756d9d336b770316c282d02db08980
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date:   Thu Oct 29 20:55:30 2026 +0100

    Fix JIT losing the called scope of self::/parent:: calls in included files

    File/eval code take This from the existing frame's scope,
    so This may be a class instead of an object.

    Closes GH-25041.

diff --git a/NEWS b/NEWS
index cb05e526f7f..4b16461b571 100644
--- a/NEWS
+++ b/NEWS
@@ -179,6 +179,8 @@ PHP                                                                        NEWS
     (Pavel Gushcha)
   . Fixed potential infinite recursion/hang (HYBRID/TAILCALL respectively)
     when zend_interrupt_function resets EG(vm_interrupt).  (Levi Morrison)
+  . Fix JIT losing the called scope of self::/parent:: calls in included files.
+    (ndossche)

 - OpenSSL:
   . Fixed bug GH-24784 (openssl_pkcs7_read() and openssl_cms_read() overwrite
diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
index cc3b867b2f2..be3c7ad9bcb 100644
--- a/ext/opcache/jit/zend_jit_ir.c
+++ b/ext/opcache/jit/zend_jit_ir.c
@@ -9389,7 +9389,8 @@ static int zend_jit_init_static_method_call(zend_jit_ctx         *jit,
 		     (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) {
 			if (op_array->fn_flags & ZEND_ACC_STATIC) {
 				scope_ref = ir_LOAD_A(jit_EX(This.value.ref));
-			} else if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
+			} else if ((op_array->fn_flags & ZEND_ACC_CLOSURE) || !op_array->function_name) {
+				/* Closures can be unbound, file/eval inherits This from the existing frame's scope. */
 				ir_ref if_object, values = IR_UNUSED;

 				if_object = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, jit_EX(This)), ir_CONST_U8(IS_OBJECT)));
diff --git a/ext/opcache/tests/jit/init_static_method_call_002.phpt b/ext/opcache/tests/jit/init_static_method_call_002.phpt
new file mode 100644
index 00000000000..897c0377d6c
--- /dev/null
+++ b/ext/opcache/tests/jit/init_static_method_call_002.phpt
@@ -0,0 +1,32 @@
+--TEST--
+JIT INIT_STATIC_METHOD_CALL: self:: in an included file keeps the called scope of a static caller
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit=tracing
+opcache.jit_hot_loop=1
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+
+class A {
+    public static function who() {
+        return static::class;
+    }
+
+    public static function test() {
+        include __DIR__ . '/init_static_method_call_002_include.inc';
+    }
+}
+
+class B extends A {}
+
+B::test();
+
+?>
+--EXPECT--
+B
+B
+B
diff --git a/ext/opcache/tests/jit/init_static_method_call_002_include.inc b/ext/opcache/tests/jit/init_static_method_call_002_include.inc
new file mode 100644
index 00000000000..66ea277d2da
--- /dev/null
+++ b/ext/opcache/tests/jit/init_static_method_call_002_include.inc
@@ -0,0 +1,4 @@
+<?php
+for ($i = 0; $i < 3; $i++) {
+    echo self::who(), "\n";
+}