Skip to content

Compiler: lib/Compiler.php is one 62,407-line class with 1,268 methods and 923 fields — trait-based decomposition behind an opcode-md5 corpus gate (lib/Compiler.php, lib/Lint/LintCompiler.php) #36230

Description

@PurHur

Category

Foundation: · maintainability (87 PRs/day land in this file) · child of #36188

Problem

lib/Compiler.php: 62,407 lines, one class, 1,268 methods (902 private / 344 protected / 21 public), 923 property declarations, 3,599 instanceof (3,185 on Op\…), 10 switch. Dispatch is compileOp (:13352) → compileExpr (:14299, a switch (get_class($expr)) with 43 arms) / compileStmt (:13423) / compileTerminal (:44722). 102 PHP builtin names are hardcoded inside lowering (array_merge 39x, array_replace_recursive 32x, var_export 23x, preg_replace_callback_array 13x …). compileCallArgSends alone is 6,431 lines (the super-quadratic compile child of #36188 covers its algorithm). The ~40 mutable fields shared by the 902 private methods (coalesceResultSlots, ternaryMergeVarSlots, activeCatchVarSlotsByName, …) are why nobody can move code safely, and why merge conflicts in this file are constant at fleet velocity. The one subclass, Lint\LintCompiler, overrides five protected methods (lib/Lint/LintCompiler.php:29,39,53,79,90) — a constraint any split must keep.

PHP implementation target

Traits, not collaborator objects: trait methods keep $this, visibility and overridability, so LintCompiler keeps working. One PR per step, each gated by Printer::print md5 equality over a fixed ≥ 100-file corpus (zero opcode diff), in this order:

  1. Compiler\Concern\CompileTimeFold — the ~15 tryFold* methods (all private).
  2. Compiler\Concern\ParameterAsserts — the 9 assertNo*/assertVariadic* methods (:999-1130).
  3. Compiler\Concern\CoalesceAndNullsafecompileCoalesce (:15949) + nullsafe prelude machinery.
  4. Compiler\Concern\InlineCallArgProducers — the ~60 inline*/sibling*/hoisted*/rewire*/slotFor* methods (~18,000 lines) — the staging ground for the def-use rewrite (super-quadratic compile child of Compiler audit (Sep 2026): fast generated code, Zend-shaped runtime, incremental builds, truthful gates — automation tracker #36188).
  5. Compiler\Concern\ClassLoweringcompileClassBody (:9308), compileInterface, compileTrait, compileClassLike; keep the five LintCompiler-overridden methods on the class.
  6. Only below ~15k lines: convert the 43 compileExpr arms into per-op classes behind a LoweringRegistry (the switch is already an exact dispatch table).
    Do not start with per-op classes — moving state before moving code is where behaviour changes leak in. Add script/opcode-corpus-md5.sh (the gate) first; it doubles as the safety net for the Simplifier-default and operand-index children of Compiler audit (Sep 2026): fast generated code, Zend-shaped runtime, incremental builds, truthful gates — automation tracker #36188.

Done when

  • script/opcode-corpus-md5.sh committed and run in check-generated-docs.sh's fast tier
  • Steps 1–5 merged with zero opcode diff; lib/Compiler.php < 20,000 lines; LintCompiler tests unchanged
  • CONTRIBUTING: new lowering code goes into a Concern, never into Compiler.php directly

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:compilerCompiler / CFG / JITenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-0:FoundationPhase 0 – foundation & DevEx

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions