Skip to content

Commit 50c6288

Browse files
committed
Create P1-PHP-PARSER.md
1 parent 4a4f35d commit 50c6288

1 file changed

Lines changed: 162 additions & 0 deletions

File tree

PROJECT/1-INBOX/P1-PHP-PARSER.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# P1 – PHP Parser / Static Analysis Integration Plan
2+
**Status:** Not Started · **Created:** 2026-02-03
3+
4+
## Table of Contents
5+
- [Background](#background)
6+
- [High-Level Phased Checklist](#high-level-phased-checklist)
7+
- [Background & Goals](#background--goals)
8+
- [Tooling Options Overview](#tooling-options-overview)
9+
- [Recommended Tooling Choice](#recommended-tooling-choice)
10+
- [Phase 0 – Spike & Decision](#phase-0--spike--decision)
11+
- [Phase 1 – Local PHPStan Integration](#phase-1--local-phpstan-integration)
12+
- [Phase 2 – PHP-Parser AST Experiments for WPCC](#phase-2--php-parser-ast-experiments-for-wpcc)
13+
- [Phase 3 – Hardening & Developer Experience](#phase-3--hardening--developer-experience)
14+
- [Risk / Quagmire Avoidance](#risk--quagmire-avoidance)
15+
- [LLM Notes](#llm-notes)
16+
17+
## Background
18+
WPCC today is a shell-based scanner that leans on grep-style rules, cached file lists, and small Python helpers to produce deterministic JSON logs and HTML reports.
19+
It is intentionally distributed without a Composer/vendor footprint, and its checks are primarily syntactic (e.g., unbounded queries, superglobals, magic strings) rather than type- or contract-aware.
20+
This plan explores how to layer PHP-Parser and dedicated static analysis tools (PHPStan/Psalm) on top of that foundation without breaking the lightweight distribution model.
21+
22+
## High-Level Phased Checklist
23+
> **Note for LLMs:** Whenever you progress an item below, update its checkbox state in-place so humans can see progress without scrolling.
24+
- [ ] Phase 0 – Clarify goals, choose pilot use cases, decide tooling mix
25+
- [ ] Phase 1 – Run PHPStan/Psalm on a target plugin repo with simple IRL checks
26+
- [ ] Phase 2 – Implement first PHP-Parser-based AST rule inside WPCC
27+
- [ ] Phase 3 – Stabilize, document, and integrate into CI / WPCC flows
28+
29+
## Background & Goals
30+
We want type- and shape-aware analysis that can catch:
31+
- Contract mismatches between producers (`search_customers()`) and consumers (filters/Ajax).
32+
- Misused settings from `get_option()` and similar APIs.
33+
- Nullability mistakes around `get_user_by()`, `get_post()`, `wc_get_order()`, etc.
34+
35+
Constraints:
36+
- WPCC today is shell + grep + small Python helpers, with no Composer footprint.
37+
- We must avoid a quagmire where bundling a full static analyser into WPCC explodes complexity.
38+
- First wins must be small, IRL, and obviously useful to developers.
39+
- We already have in-house PHP-Parser plumbing:
40+
- `kissplugins/WP-PHP-Parser-loader` for loading/configuring PHP-Parser in WP.
41+
- A working harness in `KISS-woo-shipping-settings-debugger` for using AST analysis on real plugins.
42+
43+
## Tooling Options Overview
44+
**PHPStan**
45+
- Mature static analyser with strong ecosystem.
46+
- Good WordPress support via `phpstan/wordpress` and community configs.
47+
- Excellent at cross-function type contracts and array shapes.
48+
- Assumes a Composer-managed project; heavy to embed directly into WPCC.
49+
50+
**Psalm**
51+
- Very capable analyser with rich type system and taint analysis.
52+
- Similar Composer + bootstrap expectations as PHPStan.
53+
- Slightly smaller WP-specific ecosystem for our current needs.
54+
55+
**nikic/PHP-Parser**
56+
- Low-level AST library; we get syntax trees and must build our own analysis.
57+
- Great for narrow, custom rules where grep is too blunt.
58+
- No built-in type inference, data flow, or WordPress awareness.
59+
- Fits WPCC’s distribution model better, especially given our existing loader + harness, but only if we keep scope tight.
60+
61+
## Recommended Tooling Choice
62+
**Short answer**
63+
- For plugin development repos (e.g., Woo Fast Search), start with **PHPStan** as the primary static analysis tool.
64+
- For WPCC itself and its “no Composer” distribution, use **PHP-Parser** for a small set of targeted AST-based checks, not as a general type system.
65+
66+
Rationale:
67+
- PHPStan/Psalm already solved the hard problems (types, inheritance, generics, data flow); recreating that on top of PHP-Parser would be a multi-month project.
68+
- WPCC can still benefit from lightweight AST rules where grep is too blunt, while keeping install friction low.
69+
- PHPStan has a slight edge over Psalm here due to WordPress extensions, docs, and recipes that match our IRL patterns.
70+
71+
## Phase 0 – Spike & Decision
72+
**Goals**
73+
- Confirm the “easier” IRL use cases (options shape, nullability, list vs single) are lower effort and lower risk than the wholesale filter contract.
74+
- Decide on: (a) initial PHPStan configuration for a target plugin repo; (b) first AST rule worth building with PHP-Parser in WPCC, reusing our existing loader and harness patterns where possible.
75+
76+
**Tasks**
77+
- [ ] Pick 1–2 IRL scenarios as pilots:
78+
- [ ] Settings/options shape via `get_option()`.
79+
- [ ] Nullability guards for `get_user_by()` / `get_post()` / `wc_get_order()`.
80+
- [ ] Run a manual PHPStan spike (level 1–3) on the plugin repo using Composer dev-dependency.
81+
- [ ] Document major friction points (WordPress stubs, bootstrap, performance).
82+
- [ ] Review `WP-PHP-Parser-loader` and KISS-woo-shipping-settings-debugger harness to understand existing AST patterns and APIs.
83+
- [ ] Sketch one candidate PHP-Parser rule where grep is not enough (e.g., verifying a specific Ajax response array shape) that can be implemented by reusing the loader/harness concepts.
84+
- [ ] Roughly sketch a JSON config schema for AST rules (e.g., for `ajax-response-shape`: function selectors, expected keys, severity/impact) before implementation.
85+
- [ ] Time-box Phase 0 spikes (e.g., 4–6 engineering hours) and add a “stop and reassess” checkpoint; if PHPStan WP stubs/bootstrap friction is too high, pivot or descope rather than pushing through.
86+
87+
## Phase 1 – Local PHPStan Integration
88+
**Intent:** Keep this out of WPCC’s distribution; treat it as a per-repo dev tool.
89+
90+
**Tasks**
91+
- [ ] Add PHPStan as a dev dependency to the target plugin repo.
92+
- [ ] Create a minimal `phpstan.neon` with:
93+
- [ ] WordPress extension / stubs if needed.
94+
- [ ] Baseline file to mute existing noise.
95+
- [ ] Encode 1–2 simple IRL checks:
96+
- [ ] `get_option()` wrapper returning a documented array shape.
97+
- [ ] One nullability wrapper (e.g., `find_customer_by_email(): ?WP_User`).
98+
- [ ] Run PHPStan in CI and locally; confirm it stays fast and stable.
99+
- [ ] Record a canonical IRL failure fixture for later regression tests: the Woo Fast Search "wholesale filter contract mismatch" bug at commit `9dec5a4cd713b6528673cc8a0561e6c4db925667` (https://github.com/kissplugins/KISS-woo-fast-search/commit/9dec5a4cd713b6528673cc8a0561e6c4db925667).
100+
101+
## Phase 2 – PHP-Parser AST Experiments for WPCC
102+
**Intent:** Add one small AST-based rule to WPCC to prove value over grep, without changing WPCC’s installation story, and **leverage our existing loader + harness** so this remains a low-risk, low-effort experiment.
103+
104+
### Proposed First AST Rule: Ajax Response Shape Checker
105+
**Scenario (example: Woo Fast Search, or similar search feature)**
106+
- Target a specific Ajax endpoint function (e.g. `ajax_search_customers()`).
107+
- Enforce that any returned array literal for the JSON response has a **fixed, documented shape**, for example:
108+
- `['customers' => list, 'total' => int, 'has_more' => bool]`.
109+
110+
**What the rule does (AST-level)**
111+
- Parse target PHP files and locate:
112+
- Functions matching a configured name/pattern (e.g. `kiss_woo_ajax_search_customers`).
113+
- `return` statements that return an array literal.
114+
- Validate that those array literals:
115+
- Contain required keys (`customers`, `total`, `has_more`).
116+
- Do **not** contain obviously conflicting duplicate shapes for the same function.
117+
- Optionally: flag if the same function sometimes returns a bare list vs a keyed array literal.
118+
119+
**Limitations (v1)**
120+
- Only inspects direct array literals in `return` statements.
121+
- Patterns like `$result = [...]; return $result;` or arrays built via helper functions are out of scope for the initial rule.
122+
- This is acceptable for v1; broader data-flow or variable-tracking can be revisited in later phases if this rule proves useful.
123+
124+
**CLI contract (sketch)**
125+
- New helper, invoked from WPCC (names TBD), for example:
126+
- `php dist/bin/wpcc-ast-check.php --rule ajax-response-shape --config dist/config/ajax-response-shape.json --paths "${PATHS}"`.
127+
- Output: JSON object with a `findings` array compatible with WPCC’s log schema, e.g. each finding contains at minimum:
128+
- `id` (e.g. `ast-001-ajax-response-shape`)
129+
- `severity` (e.g. `warning` or `error`)
130+
- `impact` (e.g. `MEDIUM`)
131+
- `file`, `line`, `message`, `code`, and optional `context` lines (mirroring existing entries in `dist/logs/*.json`).
132+
133+
**Tasks**
134+
- [ ] Decide and document how PHP-Parser will be distributed for WPCC (e.g., bundle loader/helper into `dist/` and rely on `WP-PHP-Parser-loader` to manage `nikic/php-parser`, keeping WPCC itself Composer-free).
135+
- [ ] Reuse or adapt `WP-PHP-Parser-loader` so WPCC can reliably load PHP-Parser in its own context.
136+
- [ ] Mirror or borrow minimal harness patterns from KISS-woo-shipping-settings-debugger for walking ASTs and emitting JSON findings.
137+
- [ ] Define a small JSON config format for this rule (e.g. function names and expected keys).
138+
- [ ] Implement the `ajax-response-shape` rule end-to-end:
139+
- [ ] CLI entry point callable from WPCC.
140+
- [ ] JSON output format consistent with existing `findings` entries (id/severity/impact/file/line/message/code/context).
141+
- [ ] Wiring into the scan pipeline behind a feature flag.
142+
- [ ] Measure performance impact and confirm it’s acceptable on medium-sized plugins.
143+
- [ ] Create small synthetic fixtures for this rule (e.g., one "good" and one "bad" Ajax endpoint file plus expected `findings` JSON) so we can exercise AST feedback without depending on live IRL plugins.
144+
145+
## Phase 3 – Hardening & Developer Experience
146+
**Tasks**
147+
- [ ] Decide which AST-based rules graduate from “experiment” to “default on”.
148+
- [ ] Document how WPCC interacts with PHPStan in plugin repos (if at all).
149+
- [ ] Add docs / recipes in `~/bin/ai-ddtk/recipes/` for:
150+
- [ ] Running PHPStan on a plugin with WPCC.
151+
- [ ] Enabling/disabling AST-based checks.
152+
- [ ] Capture lessons learned to avoid future quagmires (what worked, what hurt).
153+
154+
## Risk / Quagmire Avoidance
155+
- Keep PHPStan usage local to plugin repos, not bundled into WPCC.
156+
- Keep PHP-Parser usage narrowly scoped (one or a few high-value rules).
157+
- Regularly reassess: if a path starts requiring custom type inference or complex data flow, stop and reconsider before committing.
158+
159+
## LLM Notes
160+
- When you complete or materially progress any task in this file, update the checklist(s) above rather than creating new documents.
161+
- Do not expand this document into a full design spec; keep it as a high-level plan plus checklists and link out to more detailed docs in other files if needed.
162+

0 commit comments

Comments
 (0)