Skip to content

Support PHP 8.2 in the Turbo extension - #6825

Merged
ondrejmirtes merged 1 commit into
2.3.xfrom
turbo-php82
Oct 25, 2026
Merged

ondrejmirtes merged 1 commit into
2.3.xfrom
turbo-php82

Conversation

@ondrejmirtes

Copy link
Copy Markdown
Member

Adds PHP 8.2 to the Turbo extension's supported versions without changing the shared-core split. The shared core is still compiled once against PHP 8.5 headers; on 8.2 it loads next to a thin 8.2 extension (main.cpp, Abi.cpp, Shadow.cpp, TrustedTypes.cpp). The shared-core gate reports identical shared code for 8.2, 8.3, 8.4 and 8.6 against the 8.5 reference.

What 8.2 lacks or spells differently

Each difference is either routed through pt_abi or pinned in abi.h:

Difference Handling
No engine C stack limit (EG(stack_base/limit), zend_call_stack.h are new in 8.3) On 8.2, Abi.cpp computes the stack bounds the way 8.3 does (Linux, macOS, Windows) and keeps them correct across fresh-stack coroutines; the shared code reads them through pt_abi.eg_stack_*
zend_fcall_info_cache.closure (8.3 grew the struct from 32 to 40 bytes) Against 8.2 headers, the shared sources see 8.3's layout declared on top of 8.2's struct. The engine only uses the first four fields, and the shared code never reads closure
_ZEND_TYPE_LITERAL_NAME_BIT in internal arginfo Pinned; on 8.2, Abi.cpp converts it to the plain name bit at registration
zend_zval_value_name() is not exported in 8.2 Routed to zend_zval_type_name(), so native TypeErrors use 8.2's wording ("bool given" rather than "true given")
8.2.35's fallible zend_string_* helpers, smart_str_extract, ZEND_HASH_FILL_* bookkeeping, ZEND_ASSUME Codegen pins to 8.5's definitions
Z_EXPECTED_NUMBER_OR_STRING, non-const zend_parse_arg_*_slow, bool-returning zend_fiber_init_context #ifs in the version-specific Abi.cpp

CI and packaging

  • 8.2 is added to every turbo matrix in phar.yml, plus the shared-core gate (8.2 and 8.2-zts) and the turbo-build-image.yml tags. Windows builds 8.2 with VS16, like 8.3.
  • Alpine 3.24 doesn't package PHP 8.2, so install-alpine-php.sh builds it from the tarball.
  • The Windows "below the minimum" control job moves from 8.2 to 8.1.
  • TurboExtensionSelector::MINIMUM_PHP_VERSION_ID is now 80200; turbo-ext/composer.json and the README are updated.
  • Test harness: on PHP before 8.3, type-family.php reads its 8.3-only fixtures through static analysis. walk-trace.php skips the endless-recursion fixture there, because 8.2 has no stack limit and plain PHP segfaults on it; with turbo, the native side throws the "Maximum call stack size" error.

Verified locally (Linux arm64 in Docker, plus macOS)

  • Shared-core gate (clang): 8.2, 8.3, 8.4 and 8.6 identical to the 8.5 reference.
  • Strict GCC split build (8.5 core + 8.2 extension): 0 warnings. make lint-turbo is clean.
  • On 8.2: smoke, arena, signature parity, trusted types, parser corpus and exit-immediately all pass; walk-trace is identical (675,770 lines).
  • Full test suite with turbo: 22,409 tests and 0 failures on 8.2; 0 failures on 8.5.
  • PHPStan self-analysis on 8.2 gives identical output with and without turbo; user CPU 146 s → 84 s.
  • Not run locally, left to this PR's CI: Windows, 8.2 ZTS, the x86_64 gate, musl and macOS 8.2.

The gnu-php8.2 and gnu-php8.2-zts images were published by running turbo-build-image.yml (workflow_dispatch) on this branch before opening the PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_0156KuUPxcWUY7jap6uxnA5h

@ondrejmirtes
ondrejmirtes force-pushed the turbo-php82 branch 2 times, most recently from 70ca7bb to 85d45c4 Compare October 24, 2026 20:52
The shared core built against PHP 8.5 headers loads on PHP 8.2 next to a
thin 8.2 extension; the shared-core gate reports identical shared code for
8.2 through 8.6. What 8.2 lacks or spells differently is routed through
pt_abi or pinned in abi.h:

- no engine C stack limit: Abi.cpp computes the bounds like 8.3 does and
  keeps them across fresh-stack coroutines
- zend_fcall_info_cache.closure: 8.3's layout is declared on top of 8.2's
- the literal-name arginfo bit is translated to the plain name bit
- zend_zval_value_name() routes to zend_zval_type_name() on 8.2
- codegen pins for zend_string_*, smart_str_extract, ZEND_HASH_FILL_*
  and ZEND_ASSUME

CI builds and tests 8.2 everywhere 8.3 is built; Alpine 3.24 has no php82
package, so the musl legs build it from the tarball.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0156KuUPxcWUY7jap6uxnA5h
@ondrejmirtes
ondrejmirtes merged commit e84798f into 2.3.x Oct 25, 2026
1065 of 1069 checks passed
@ondrejmirtes
ondrejmirtes deleted the turbo-php82 branch October 25, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant