Skip to content

πŸ—ΊοΈ ROADMAP: Compile a small PHP web application (living document)Β #78

@PurHur

Description

@PurHur

Living roadmap β€” edit this issue as phases complete. Link PRs here. Check boxes when milestones land on master.

Repository: PurHur/php-compiler
Target: Compile and run a small normal PHP web app (multi-file, forms, headers, optional AOT CGI/FastCGI deploy)β€”not just echo "Hello".

Issue index: #46–#881. Latest audit: 2026-05-23 batch 59 (#878–#881; expanded #48/#113; de-dupe #98/#174).


Phase model (north star)

Delivery order for the compile-a-small-web-app goal:

Phase Name GitHub labels (typical) Milestone
0 Foundation phase-0:Foundation Local/Docker CI (#436 βœ…, #501 βœ…), phpc CLI + phpc init (#312 βœ…, #632 βœ…), Docker 22.04 (#73 βœ…), docs (#245 βœ…, #48, #727 phpc-json, #808 gate matrix), JIT compliance (#98, #717 βœ…, #728 βœ…), inventory gate (#765), self-host probe CI (#829, #830, #868)
1 Language phase-2:language OOP VM/JIT βœ… / native AOT link (#568 βœ…, #752 βœ…), typed props (#767, #169), includes (#54 βœ… VM, #475 JIT), ::class (#740), return types (#205)
2 Stdlib phase-4:stdlib Web builtins: headers, JSON, sessions (#64), htmlspecialchars (#124 βœ…), path guards (#117, #704 βœ…), regex (#93 βœ…, #787 preg_quote βœ…), redirects (#634 βœ…), templates (#275 βœ… extract), rmdir (#759 βœ…), unlink (#748 βœ…), rename (#772 βœ…), touch (#843 βœ…), addslashes (#874)
3 Web AOT phase-3:aot, phase-1:web-runtime phpc build --project link βœ… (#752), execute (#764, bisect #878–#880, #867, #866, #846–#849, #831–#834, #784, #807), deploy (#609 βœ…, #718 βœ…), runtime includes (#623 βœ…), VM/AOT CGI (#50 βœ…, #665 βœ…), FastCGI (#173), debug CLI (#774, #792, #847, #75)
4 Polish phase-5:reference-app MiniWebApp VM βœ… (#539) β†’ gates default-on (#641 βœ…, #664 βœ…, #674 βœ…) β†’ AOT execute+HTTP (#676, #747, #478, #833, #881) β†’ docs (#655 βœ…, #445, #696, #753, #801) + stale-copy gates (#766, #802, #809) + smoke accuracy

Label prefixes (phase-2:language, etc.) are historical GitHub labels β€” they do not always match the phase number in this table.


Current phase

Active β€” Phase 4 Polish (AOT execute + HTTP): phpc build --project examples/003-MiniWebApp links on harness (#752 βœ…, #812 βœ…). Native .phpc/bin/app runs but returns empty stdout for home/hello routes β€” #764 (not a link failure).

Bisect ladder (smallest β†’ largest; updated batch 59):

Step Issue Fixture / probe Status
1 #848 isset_object_property_array.phpt βœ… closed
2 #806 / #783 require_return_config.phpt βœ… closed
3 #878 nested_include_two_tier.phpt πŸ“‹ open
4 #867 miniwebapp_render_home.phpt (add tree) πŸ“‹ open
5 #866 $_SERVER in included layout.php πŸ“‹ open
6 #846 + #832 private method β†’ layout partial chain πŸ“‹ open
7 #831 global fn from class method (contact) πŸ“‹ open
8 #849 JSON api/status in class method πŸ“‹ open
9 #834 reject early-return path πŸ“‹ open
10 #764 full 003 integration ❌ blocker

DevEx (batch 59): #879 script/miniwebapp-aot-bisect.sh, #880 @group miniwebapp-bisect, #881 retarget examples-aot-smoke.sh 003 slice.

Track Issues
AOT execute (blocker) #764, #878, #867, #866, #846, #831, #832, #834, #849, #784, #807
AOT execute tests #785, #773, #775 / #791 βœ…, #747 (canonical), #485 (umbrella)
Smoke / messaging #881, #809, #833, #766, #802, #801, #753
Test infra #790, #454, #880
DevEx / debug #879, #847 --list-units, #774, #746, #792, #808
Self-host (stretch) #829, #830, #868, #816 βœ…
HTTP / CGI AOT #610 (canonical), #478 (umbrella), #682
CI hygiene #765, #754, #737, #98

In parallel β€” Phase 1 Language: #205, #475, #145, #740, #169, #767, #195.

In parallel β€” Phase 0 Foundation: #98 JIT compliance; #113 host php-parser. Canonical CI: ./script/ci-local.sh / make test-docker β€” #394 GHA disabled.

Stretch (orthogonal): Self-host #540 βœ… β€” docs/bootstrap-selfhost.md.


Next 3 priorities

# Issue Why now
1 #867 + #878 + #866 Middle bisect after closed #848/#806 β€” before layout branches
2 #879 + #880 + #747 + #790 Ordered local bisect + shared CGI env for CLI smoke
3 #881 + #766 + #753 + #801 Retire #568 copy in scripts/docs; accurate examples README

Current state (2026-05-23, batch 59)

Area Status Notes
VM execution βœ… Strong Compliance + RealWorld PHPT + mini_web_app_*.phpt
phpc CLI βœ… serve, run, build, deploy, test, lint, init --profile miniwebapp, doctor --gates (#657 βœ…)
001–004 examples βœ… VM/AOT (000–002, 004) make examples-aot-smoke β€” 003 execute pending #764
003-MiniWebApp VM βœ… #539, PATH_INFO (#489), assets (#594)
003-MiniWebApp AOT link βœ… #752 βœ…, #812 βœ…
003-MiniWebApp AOT execute ❌ #764 β€” exit 0, 0 stdout bytes
AOT bisect fixtures ⚠️ #848/#806 βœ…; #878/#867 open
JSON api/status AOT πŸ“‹ #849 class-method json_encode
Bisect DevEx πŸ“‹ #879 script, #880 PHPUnit group
Self-host probe CI πŸ“‹ #829 wire probe; #830 inventory; #868 cast/isset link
phpc build --list-units πŸ“‹ #847 debug graph
JIT compliance root fix ⚠️ #98 (not #174)
examples/README AOT row ⚠️ stale #753 cites #568
examples-aot-smoke 003 ⚠️ stale skip #881 β€” script still skips #568
Bootstrap inventory CI ⚠️ #765, #830
Deploy shell smoke βœ… #718 βœ… (001/002)

Verify on harness (no GHA):

make docker-build-22
./script/docker-ci-local.sh
php script/bootstrap-inventory.php --check   # #765 / #830
./script/ci-fast.sh
make web-smoke && make examples-web-smoke
# AOT bisect (#764):
./script/ci-local.sh --filter 'isset_object_property_array|nested_include_two_tier'
cd examples/003-MiniWebApp && QUERY_STRING=route=home REQUEST_METHOD=GET ./.phpc/bin/app | wc -c
phpc doctor --gates
# When #879 lands:
MINIWEBAPP_AOT_BISECT_GATE=1 ./script/miniwebapp-aot-bisect.sh

New issues (batch 59, #878–#881)

# Title
#878 Testing: nested_include_two_tier.phpt AOT execute (layout scope, #764)
#879 DevEx: script/miniwebapp-aot-bisect.sh β€” ordered #764 fixture runner
#880 Testing: PHPUnit @group miniwebapp-bisect for ordered #764 AOT fixtures
#881 CI: examples-aot-smoke.sh 003 β€” link probe + execute bytes (#809, #764)

Expanded (batch 59): #48 (README north-star table), #113 (php-parser patch workflow).

De-dupe comments (batch 59): #98 ↔ #174; #881 supersedes stale #568 skip in examples-aot-smoke.sh (with #809 policy).

Prior batch (58, #866–#868)

# Title
#866 AOT: $_SERVER reads in runtime-included templates (layout.php SCRIPT_NAME, #764)
#867 Testing: aot phpt miniwebapp_render_home β€” resolveAppName + layout include (#764)
#868 Self-host: native link bootstrap-aot cast_int.php + isset_array_offset.php (Phase C)

Expanded (batch 58): #72 (closures), #75 (AOT debug symbols).


CI de-duplication (canonical)

Topic Canonical issue Notes
Full local gate ./script/ci-local.sh, make test-docker, ./script/docker-ci-local.sh #245 βœ… docs
Fast iteration ./script/ci-fast.sh, make test-fast #436 βœ…
JIT skipped with LLVM 9 #98, #250 βœ…, #717 βœ…, #728 βœ… Not #174
LLVM 14+ upgrade #174 After #98 green on LLVM 9
GHA workflows #394 βœ… closed Do not add .github/workflows/* for CI
MiniWebApp AOT execute #764, #878–#880, #867–#866 Bisect then integrate
MiniWebApp AOT execute tests #747 #485 umbrella only
ServeAotTest MiniWebApp #610 #478 umbrella only
examples-aot-smoke 003 #881 (impl), #809 (policy) Link βœ…; execute #764
Self-host compile probe #816 βœ… script, #829 CI wire, #830 doc commit, #868 cast/isset link Stretch Phase 0
AOT debug graph #847 --list-units #746 doctor probe
Stale #568 messaging #766, #792, #802, #801, #881, #753 Scripts + docs

How to update

  1. Check phase boxes when child issues close.
  2. Update Current state after each audit.
  3. Comment release notes when a phase completes.
  4. Close duplicates; link blockers in Reference app: MiniWebApp runtime green (lint 0, VM serve, routes)Β #539, Testing: MiniWebApp AOT unskip matrix after #568 (orchestrate #454 #485 #478 #610)Β #676, AOT: MiniWebApp native binary CLI execute emits empty stdout (post-link)Β #764.

Child issues: #46–#881.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions