Skip to content

Commit 704fb13

Browse files
claudeondrejmirtes
authored andcommitted
Add comprehensive developer documentation for turbo-ext
Created CLAUDE.md with detailed documentation covering: - Overview and purpose of the PHPStan Turbo Extension - Architecture and integration strategy using class aliasing - Directory structure and Zephir configuration - Current CombinationsHelper implementation details - Development workflow (building, enabling, testing) - Integration points across the codebase - Performance considerations and limitations - Future expansion guidelines - Debugging and troubleshooting tips This documentation will help with future development tasks on the turbo-ext.
1 parent 0e43eef commit 704fb13

File tree

1 file changed

+285
-0
lines changed

1 file changed

+285
-0
lines changed

turbo-ext/CLAUDE.md

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
# PHPStan Turbo Extension - Developer Guide
2+
3+
## Overview
4+
5+
The **PHPStan Turbo Extension** is an experimental project aimed at improving PHPStan's performance by rewriting performance-critical parts of PHPStan as a native PHP extension using the [Zephir language](https://zephir-lang.com/).
6+
7+
**Status:** Highly experimental work-in-progress (Proof of Concept)
8+
9+
## Purpose & Goals
10+
11+
### Primary Goal
12+
Accelerate PHPStan's analysis by moving computationally expensive operations from userland PHP into compiled C code via a PHP extension.
13+
14+
### Current Focus
15+
The initial implementation targets the `CombinationsHelper::combinations()` method, which is used extensively in type inference for:
16+
- Constant array type operations (`src/Type/Constant/ConstantArrayType.php:1829`)
17+
- sprintf() function return type analysis (`src/Type/Php/SprintfFunctionDynamicReturnTypeExtension.php`)
18+
- implode() function return type analysis (`src/Type/Php/ImplodeFunctionReturnTypeExtension.php`)
19+
20+
### Why This Matters
21+
The `combinations()` method generates Cartesian products of arrays, which can be computationally expensive during type inference. Moving this to native code can provide significant performance improvements.
22+
23+
## Architecture
24+
25+
### Integration Strategy
26+
27+
PHPStan uses a **transparent fallback mechanism** that automatically switches to the native implementation when the extension is available:
28+
29+
1. **Default Implementation**: Pure PHP implementation in `src/Internal/CombinationsHelper.php`
30+
2. **Turbo Implementation**: Native code in `turbo-ext/phpstanturbo/CombinationsHelper.zep`
31+
3. **Auto-Detection**: `src/Turbo/TurboExtensionEnabler.php` checks if the extension is loaded
32+
4. **Class Aliasing**: When loaded, the Zephir class `PHPStanTurbo\CombinationsHelper` replaces `PHPStan\Internal\CombinationsHelper`
33+
34+
### Initialization Flow
35+
36+
```
37+
bin/phpstan (line 21)
38+
39+
TurboExtensionEnabler::enableIfLoaded()
40+
41+
extension_loaded('phpstanturbo') → true?
42+
↓ YES
43+
class_alias('PHPStanTurbo\CombinationsHelper', 'PHPStan\Internal\CombinationsHelper')
44+
45+
All subsequent calls to CombinationsHelper::combinations() use native code
46+
```
47+
48+
This also applies to the test suite via `tests/bootstrap.php:8`.
49+
50+
## Directory Structure
51+
52+
```
53+
turbo-ext/
54+
├── README.md # User-facing documentation
55+
├── CLAUDE.md # This file - developer guide
56+
├── .gitignore # Excludes /vendor, /ext, /.zephir
57+
├── composer.json # Requires phalcon/zephir ^0.19.0
58+
├── composer.lock # Locked dependencies
59+
├── config.json # Zephir compiler configuration
60+
└── phpstanturbo/ # Zephir source code directory
61+
└── CombinationsHelper.zep # Native implementation of combinations()
62+
63+
Generated during build (git-ignored):
64+
├── vendor/ # Composer dependencies (Zephir)
65+
├── ext/ # Generated C code and compiled extension
66+
│ └── modules/phpstanturbo.so # The final compiled extension
67+
└── .zephir/ # Zephir build cache
68+
```
69+
70+
## Zephir Configuration (`config.json`)
71+
72+
Key configuration points:
73+
74+
- **Namespace**: `phpstanturbo` (maps to PHP namespace `PHPStanTurbo`)
75+
- **Extension Name**: `phpstan_turbo`
76+
- **Version**: `0.0.1`
77+
- **Optimizations**: Enabled static type inference, constant folding, call gatherer pass
78+
- **Warnings**: Comprehensive warning set enabled for code quality
79+
80+
## Development Workflow
81+
82+
### Prerequisites
83+
84+
1. **Zephir Installation**: Follow [Zephir Installation Guide](https://docs.zephir-lang.com/latest/installation/#prerequisites)
85+
2. **Zephir Parser Extension**: Install [php-zephir-parser](https://github.com/zephir-lang/php-zephir-parser)
86+
3. **Build Tools**: C compiler (gcc/clang), PHP development headers
87+
4. **Dependencies**: Run `composer install` in `turbo-ext/` directory
88+
89+
### Building the Extension
90+
91+
```bash
92+
cd turbo-ext
93+
vendor/bin/zephir generate && vendor/bin/zephir compile
94+
```
95+
96+
This generates:
97+
- C source code in `ext/`
98+
- Compiled `phpstanturbo.so` in `ext/modules/`
99+
100+
### Enabling the Extension
101+
102+
Add to your `php.ini`:
103+
```ini
104+
extension=/absolute/path/to/phpstan-src/turbo-ext/ext/modules/phpstanturbo.so
105+
```
106+
107+
Verify loading:
108+
```bash
109+
php -m | grep phpstanturbo
110+
```
111+
112+
### Testing Integration
113+
114+
1. With extension enabled, run PHPStan:
115+
```bash
116+
bin/phpstan analyse ...
117+
```
118+
119+
2. Verify extension is being used by checking that `TurboExtensionEnabler::isLoaded()` returns true
120+
121+
3. Run PHPStan's test suite:
122+
```bash
123+
vendor/bin/phpunit
124+
```
125+
126+
## Performance Considerations
127+
128+
### Expected Benefits
129+
- Reduced CPU time for combination generation
130+
- Lower overhead from PHP VM interpretation
131+
- Potential for better memory locality in native code
132+
133+
### Current Limitations
134+
- No generator support in Zephir version (memory trade-off)
135+
- Only one function optimized so far
136+
- Extension build/deployment complexity
137+
138+
### Benchmarking
139+
TODO: Add benchmark suite to measure actual performance gains
140+
141+
## Future Expansion Areas
142+
143+
### High-Priority Candidates
144+
Functions that are:
145+
- Called frequently during analysis
146+
- Computationally intensive
147+
- Work with primitive data structures
148+
- Don't require complex PHP ecosystem features
149+
150+
### Potential Targets
151+
152+
1. **Array/String Operations**
153+
- Array intersection/union operations
154+
- String manipulation utilities
155+
- Hash computations
156+
157+
2. **Type System Operations**
158+
- Type comparison/equality checks
159+
- Simple type transformations
160+
- Type acceptability checks
161+
162+
3. **Scope/Variable Tracking**
163+
- Scope merging operations
164+
- Variable state tracking
165+
166+
### Investigation Workflow
167+
168+
To identify new optimization targets:
169+
170+
1. **Profile PHPStan**: Find hotspots using Xdebug or Blackfire
171+
2. **Identify Pure Functions**: Focus on methods without side effects
172+
3. **Assess Complexity**: Ensure Zephir can express the logic
173+
4. **Prototype**: Implement in Zephir
174+
5. **Benchmark**: Measure actual performance impact
175+
6. **Integrate**: Add to TurboExtensionEnabler aliasing
176+
177+
## Development Best Practices
178+
179+
### Adding New Zephir Classes
180+
181+
1. Create `.zep` file in `turbo-ext/phpstanturbo/`
182+
2. Use namespace `PHPStanTurbo`
183+
3. Match the interface of the PHP class being replaced
184+
4. Update `TurboExtensionEnabler.php` with new class_alias
185+
5. Keep fallback PHP implementation in sync
186+
187+
### Testing Strategy
188+
189+
1. Ensure PHP implementation has comprehensive tests
190+
2. Extension should pass same test suite
191+
3. Add specific tests for edge cases in Zephir
192+
4. Test both with and without extension loaded
193+
194+
### Compatibility
195+
196+
- Maintain API compatibility with PHP version
197+
- Document any behavioral differences (e.g., generators vs arrays)
198+
- Ensure graceful fallback when extension not available
199+
200+
## Debugging
201+
202+
### Extension Not Loading
203+
204+
```bash
205+
# Check if extension file exists
206+
ls -l turbo-ext/ext/modules/phpstanturbo.so
207+
208+
# Check PHP configuration
209+
php --ini
210+
211+
# Check for loading errors
212+
php -d extension=/path/to/phpstanturbo.so -m
213+
214+
# Verify extension info
215+
php --re phpstanturbo
216+
```
217+
218+
### Rebuild from Scratch
219+
220+
```bash
221+
cd turbo-ext
222+
rm -rf ext/ .zephir/
223+
vendor/bin/zephir generate && vendor/bin/zephir compile
224+
```
225+
226+
### Zephir Compilation Errors
227+
228+
- Check Zephir syntax against [Zephir Language Reference](https://docs.zephir-lang.com/)
229+
- Ensure C compiler and PHP dev headers are available
230+
- Review generated C code in `ext/` directory
231+
232+
## Resources
233+
234+
### Documentation
235+
- [Zephir Official Documentation](https://docs.zephir-lang.com/)
236+
- [Zephir Language Tutorial](https://docs.zephir-lang.com/latest/tutorial/)
237+
- [PHP Extension Development](https://www.phpinternalsbook.com/)
238+
239+
### Tools
240+
- [Zephir Parser](https://github.com/zephir-lang/php-zephir-parser)
241+
- [Zephir Compiler](https://github.com/zephir-lang/zephir)
242+
243+
## Contributing to Turbo Extension
244+
245+
When adding new optimizations:
246+
247+
1. **Measure First**: Profile to confirm bottleneck
248+
2. **Start Simple**: Pick pure functions with simple data types
249+
3. **Maintain Compatibility**: Keep same interface as PHP version
250+
4. **Test Thoroughly**: Run full test suite with/without extension
251+
5. **Document Trade-offs**: Note any behavioral differences
252+
6. **Benchmark Results**: Provide performance measurements
253+
254+
## Known Issues & Limitations
255+
256+
1. **Generator Support**: Zephir version uses arrays instead of generators
257+
- Impact: Higher memory usage for large combination sets
258+
- Mitigation: Monitor memory usage in production
259+
260+
2. **Build Complexity**: Requires Zephir toolchain and C compiler
261+
- Impact: Development setup more complex
262+
- Mitigation: Clear documentation and prerequisites
263+
264+
3. **Distribution**: Extension must be compiled per environment
265+
- Impact: Cannot distribute as pure PHP package
266+
- Mitigation: Keep extension optional with fallback
267+
268+
4. **Debugging**: Native code harder to debug than PHP
269+
- Impact: Longer development cycles
270+
- Mitigation: Comprehensive PHP tests before porting
271+
272+
## Version History
273+
274+
- **0.0.1** (Current): Initial PoC with CombinationsHelper only
275+
276+
## Contact & Support
277+
278+
For issues or questions:
279+
- Main PHPStan repo: https://github.com/phpstan/phpstan
280+
- Zephir issues: https://github.com/zephir-lang/zephir/issues
281+
282+
---
283+
284+
**Last Updated**: 2025-12-30
285+
**Maintainers**: PHPStan Team

0 commit comments

Comments
 (0)