PHPMD Language Server for Zed Editor
Real-time PHP code quality analysis powered by PHP Mess Detector
Features • Installation • Configuration • Architecture • Contributing
📋 Overview
The PHPMD Language Server brings comprehensive code quality analysis to Zed Editor through the Language Server Protocol (LSP). It provides real-time feedback on potential bugs, suboptimal code, overcomplicated expressions, and unused code elements as you write PHP.
Why PHPMD LSP?
- 🚀 Instant Feedback - See code quality issues as you type, not after you commit
- ⚡ High Performance - Optimized with async processing, LZ4 compression, and smart caching
- 🎯 Zero Configuration - Works out of the box with sensible defaults
- 🔧 Highly Configurable - Customize rules to match your team's standards
- 📦 Self-Contained - Includes bundled PHPMD binary, no external dependencies required
✨ Features
Core Capabilities
🔍 Real-Time Code Analysis
- Detects code quality issues instantly as you type
- Smart diagnostic ranges that skip leading whitespace for cleaner underlines
- Severity-based highlighting (errors, warnings, info)
- Rule-specific documentation links
⚡ Performance Optimizations
- LZ4 Compression - Reduces memory usage by ~85% for large files
- Smart Caching - Avoids re-analyzing unchanged files
- Concurrent Processing - Analyzes up to 4 files simultaneously
- Async Architecture - Non-blocking execution keeps editor responsive
- Timeout Protection - 10-second safeguard prevents hanging on complex files
🎨 Intelligent Diagnostics
- Context-Aware Ranges - Different highlighting for class, method, and property issues
- Whitespace Trimming - Underlines start at first code character, not indentation
- Property Detection - Correctly highlights property violations even when PHPMD reports class-level
- Rule Categorization - Automatic severity mapping based on rule priority
Configuration Features
🔧 Flexible Configuration
- Auto-Discovery - Finds
phpmd.xml,phpmd.xml.dist,.phpmd.xml, or.phpmd.xml.distautomatically - XML Validation - Validates config files before use, skipping invalid XML files
- Smart Fallback - Uses all PHPMD rulesets when no valid config file is found
- Live Reloading - Configuration changes apply instantly without restart
- Multi-Source - Configure via project files, Zed settings, or environment variables
- Auto-Recovery - Gracefully handles deleted or invalid config files
📦 Smart PHPMD Detection
Priority order for finding PHPMD executable:
- Project's
vendor/bin/phpmd(respects composer dependencies) - Custom path from settings
- Bundled PHPMD 2.15+ PHAR (always available fallback)
- System PATH installation
Reliability Features
🛡️ Robust Error Handling
- Process Management - Automatic cleanup of zombie processes
- Memory Monitoring - Tracks and logs memory usage for optimization
- Graceful Degradation - Falls back to defaults when configs fail
- Comprehensive Logging - Detailed debug output for troubleshooting
📦 Installation
Via Zed Extensions Panel (Recommended)
- Open Zed Editor
- Press
Cmd+Shift+X(macOS) orCtrl+Shift+X(Linux/Windows) - Search for "PHPMD"
- Click Install
Manual Installation (Development)
# Clone the repository
git clone https://github.com/GeneaLabs/zed-phpmd-lsp.git
cd zed-phpmd-lsp
# Build the extension
cargo build --release
# Build the LSP server
cd lsp-server
cargo build --release🚀 Quick Start
1. Enable the Language Server
Add to your Zed settings.json (open with Cmd+, or Ctrl+,):
{
"languages": {
"PHP": {
"language_servers": ["phpmd", "intelephense"]
}
}
}2. Start Coding
The extension automatically analyzes PHP files as you open and edit them:
<?php
namespace App\Services;
class UserService
{
private $unused; // 🔍 Unused private field
public function complexMethod($a, $b, $c, $d, $e, $f) // 🔍 Too many parameters
{
if ($a == true) { // 🔍 Use strict comparison
goto end; // 🔍 Avoid goto statements
}
eval($userInput); // 🔍 Security risk: eval usage
end:
return $result;
}
public function m() { // 🔍 Method name too short
// Complex logic here...
}
}⚙️ Configuration
Configuration Priority
The extension uses this priority order (highest to lowest):
- Project Config Files -
phpmd.xml,phpmd.xml.dist,.phpmd.xml - Zed Settings - User or project-specific settings.json
- Environment Variables -
PHPMD_RULESETS,PHPMD_PATH - Defaults - Built-in rulesets: cleancode, codesize, controversial, design, naming, unusedcode
Available Rulesets
| Ruleset | Description | Key Rules |
|---|---|---|
| cleancode | Clean code practices | BooleanArgumentFlag, ElseExpression, StaticAccess |
| codesize | Complexity and size limits | CyclomaticComplexity, NPathComplexity, ExcessiveMethodLength |
| controversial | Debated best practices | Superglobals, CamelCaseParameterName |
| design | Software design principles | ExitExpression, EvalExpression, GotoStatement |
| naming | Naming conventions | ShortVariable, LongVariable, ShortMethodName |
| unusedcode | Dead code detection | UnusedPrivateField, UnusedLocalVariable, UnusedPrivateMethod |
Configuration Examples
Basic Zed Settings
{
"lsp": {
"phpmd": {
"settings": {
"rulesets": "cleancode,codesize,design"
}
}
}
}Advanced Project Configuration
Create phpmd.xml in your project root:
<?xml version="1.0"?>
<ruleset name="MyProject"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>Custom rules for MyProject</description>
<!-- Import specific rules -->
<rule ref="rulesets/cleancode.xml">
<exclude name="ElseExpression"/>
</rule>
<rule ref="rulesets/codesize.xml/CyclomaticComplexity">
<properties>
<property name="reportLevel" value="15"/>
</properties>
</rule>
<rule ref="rulesets/naming.xml/ShortVariable">
<properties>
<property name="minimum" value="2"/>
<property name="exceptions" value="id,db,em,i,j,k"/>
</properties>
</rule>
<!-- Exclude patterns -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/tests/*</exclude-pattern>
<exclude-pattern>*/database/migrations/*</exclude-pattern>
</ruleset>Per-Project Settings
Create .zed/settings.json in your project:
{
"lsp": {
"phpmd": {
"settings": {
"rulesets": "./config/phpmd-strict.xml",
"phpmdPath": "./vendor/bin/phpmd"
}
}
}
}🏗️ Architecture
System Overview
┌─────────────────┐ LSP Protocol ┌──────────────────┐
│ │ ◄──────────────────► │ │
│ Zed Editor │ │ PHPMD LSP │
│ │ │ Server │
└─────────────────┘ └──────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ PHP Files │ │ PHPMD Binary │
│ in Workspace │ │ (Analysis) │
└─────────────────┘ └──────────────────┘Key Components
LSP Server (lsp-server/src/main.rs)
- Tower-LSP Framework - Async LSP implementation in Rust
- Tokio Runtime - High-performance async execution
- LZ4 Compression - Memory-efficient document storage
- Semaphore Control - Limits concurrent PHPMD processes
Memory Management
// Document compression reduces memory by ~85%
CompressedDocument {
compressed_data: Vec<u8>, // LZ4 compressed content
original_size: usize, // Original file size
checksum: u64, // Content hash for cache validation
compression_ratio: f32, // Monitoring compression efficiency
}Diagnostic Processing Pipeline
- File Change Detection - Debounced to avoid excessive processing
- Content Compression - LZ4 compression for memory efficiency
- PHPMD Execution - Isolated process with timeout protection
- JSON Parsing - Robust extraction from mixed PHPMD output
- Range Calculation - Smart positioning with whitespace trimming
- Cache Storage - Results cached with content checksums
Performance Characteristics
- Memory Usage: ~15-20MB base + ~0.2MB per open file (compressed)
- Analysis Speed: 50-200ms for typical files (1000 lines)
- Concurrent Files: Up to 4 simultaneous analyses
- Cache Hit Rate: ~70-80% in typical editing sessions
- Compression Ratio: 85-90% size reduction for source files
🐛 Troubleshooting
Common Issues
Diagnostics Not Appearing
Verify language server is enabled:
{ "languages": { "PHP": { "language_servers": ["phpmd"] } } }Check debug output:
- View → Toggle Log Panel
- Look for
PHPMD LSP:prefixed messages
Test PHPMD manually:
phpmd path/to/file.php text cleancode
Performance Issues
Reduce concurrent analyses:
{ "lsp": { "phpmd": { "settings": { "maxConcurrent": 2 } } } }Simplify rulesets:
- Start with single ruleset:
"rulesets": "cleancode" - Add more gradually to identify performance impact
- Start with single ruleset:
Custom Rules Not Working
Validate XML syntax:
xmllint --noout phpmd.xmlCheck file paths:
- Use absolute paths for testing
- Ensure relative paths are from project root
Test configuration:
phpmd . text phpmd.xml --verbose
Debug Mode
Enable verbose logging in Zed:
{
"lsp": {
"phpmd": {
"settings": {
"logLevel": "debug"
}
}
}
}🤝 Contributing
We welcome contributions! See our Contributing Guide for details.
Development Setup
# Clone and setup
git clone https://github.com/GeneaLabs/zed-phpmd-lsp.git
cd zed-phpmd-lsp
# Install Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build everything
cargo build --release
cd lsp-server && cargo build --release
# Run tests
cargo testAreas for Contribution
- 🪟 Windows testing and compatibility
- 🐧 Linux distribution testing
- 📝 Additional ruleset templates
- 🌍 Internationalization support
- 🧪 Test coverage improvements
- 📚 Documentation translations
📚 Resources
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Third-Party Licenses
- PHPMD - BSD-3-Clause License (bundled as PHAR)
- Rust Dependencies - Various permissive licenses
See THIRD_PARTY_LICENSES.md for complete attribution.
🙏 Acknowledgments
- Manuel Pichler - Creator of PHPMD
- PHPMD Contributors - For the excellent code quality tool
- Zed Industries - For the blazing-fast editor and extension API
- Tower-LSP Contributors - For the robust LSP framework
- PHP Community - For continuous feedback and support
Made with ❤️ for the PHP community