laravel/surveyor
Beta Laravel tool for mostly static analysis of PHP/Laravel apps. Parses files/classes to extract rich metadata (classes, methods, properties, types) and can inspect models and container bindings for extra detail. Returns structured results for other tools.
Installation:
composer require laravel/surveyor
No additional configuration is required for basic usage.
First Use Case:
Run Surveyor on a directory (e.g., app/) to extract metadata:
use Laravel\Surveyor\Surveyor;
$surveyor = new Surveyor();
$results = $surveyor->survey(app_path('Http/Controllers'));
This returns an array of Surveyor\Result objects, each representing a parsed PHP file.
Key Improvements in v0.2.4:
int, string).Where to Look First:
Surveyor class: Core entry point for analysis (now handles interfaces and complex type resolution).Result class: Contains parsed metadata (e.g., classes, interfaces, methods, properties).Surveyor::survey(): Primary method to trigger analysis (now more accurate for Eloquent builders).Surveyor::getResults(): Retrieve raw results (useful for debugging).Surveying a Directory (Including Interfaces):
$results = Surveyor::survey(base_path('app'));
foreach ($results as $result) {
// Access parsed data: $result->classes, $result->interfaces, $result->methods, etc.
if (isset($result->interfaces)) {
// Handle interface-specific logic.
}
}
Tip: The improved handling of interfaces and Eloquent builders ensures accurate parsing of abstract contracts and query methods.
Filtering Results by Type:
Use Surveyor::filter() to narrow results (e.g., by namespace, class name, or interface):
$filtered = $results->filter(fn ($result) =>
str_contains($result->namespace, 'App\\Contracts') ||
(isset($result->interfaces) && !empty($result->interfaces))
);
Extracting Eloquent Builder Metadata: Access structured data for Eloquent builders (now with generics and integer range support):
foreach ($results as $result) {
$builderMethods = $result->methods
->where('name', 'like', 'where%')
->where('returnType', 'contains', 'Builder');
$rangeMethods = $result->methods
->where('parameters', 'contains', ['type' => 'int[]']);
}
Integration with Laravel Ranger:
For high-level DTOs, pair with laravel/ranger:
use Laravel\Ranger\Ranger;
$ranger = new Ranger();
$ranger->analyze($results); // Convert Surveyor results to Ranger DTOs (now includes interfaces).
Artisan Command: Create a custom command to run Surveyor periodically (e.g., during CI):
use Laravel\Surveyor\Surveyor;
use Symfony\Component\Console\Command\Command;
class SurveyCommand extends Command {
protected function handle() {
$results = Surveyor::survey(app_path());
// Log or process results, including interfaces and Eloquent builders.
}
}
Event Listeners:
Trigger Surveyor on file changes (e.g., via file:updated events) to keep metadata fresh, especially for interfaces and builders.
Caching:
Cache results for performance (e.g., in bootstrap/cache):
$cacheKey = 'surveyor_results';
$results = Cache::remember($cacheKey, now()->addHours(1), fn () => Surveyor::survey(app_path()));
Note: Corrupted cache files are treated as cache misses (v0.2.3), ensuring stale data is not returned.
Beta API Instability:
v1.0.0. Check the changelog for breaking changes.composer.json (e.g., ^0.2.0) to avoid unexpected updates.Performance with Large Codebases:
vendor/ or storage/ to speed up analysis:
$surveyor = new Surveyor(['exclude' => ['vendor', 'storage']]);
False Positives in Parsing:
eval(), create_function) or complex inline assignments.Namespace Resolution:
composer dump-autoload is up to date.int, string).Eloquent Builder Method Resolution:
whereBetween, orWhere) to ensure accurate type resolution.Enable Verbose Output:
Pass ['verbose' => true] to the Surveyor constructor to log parsing details:
$surveyor = new Surveyor(['verbose' => true]);
Inspect Raw Results:
Use Surveyor::getRawResults() to debug parsing issues:
$rawResults = Surveyor::getRawResults();
dd($rawResults); // Inspect the underlying data structure, including interfaces and builders.
Custom Analyzers for Interfaces: Extend Surveyor to analyze interfaces (e.g., detect unimplemented methods):
use Laravel\Surveyor\Contracts\Analyzer;
class InterfaceAnalyzer implements Analyzer {
public function analyze($result) {
if (isset($result->interfaces)) {
foreach ($result->interfaces as $interface) {
// Check for unimplemented methods or deprecated interfaces.
}
}
}
}
Register the analyzer via the Surveyor constructor:
$surveyor = new Surveyor(['analyzers' => [new InterfaceAnalyzer()]]);
Post-Processing for Eloquent Builders: Use Laravel collections to transform builder-related results:
$builderMethods = $results->flatMap->methods
->where('returnType', 'contains', 'Builder')
->where('parameters', '!=', []);
Integration with Static Analysis Tools: Export Surveyor results to JSON for use with other tools (e.g., SonarQube):
file_put_contents(
storage_path('app/surveyor_results.json'),
json_encode($results->toArray())
);
Note: Results now include interfaces and refined Eloquent builder metadata.
Exclusion Patterns: Use glob patterns to exclude files/directories:
$surveyor = new Surveyor(['exclude' => ['tests/*', 'app/Console/*']]);
File Extensions:
Surveyor defaults to .php files. To include other extensions (e.g., .inc), pass:
$surveyor = new Surveyor(['extensions' => ['php', 'inc']]);
Handling PHP Type Keywords:
New in v0.2.4: Surveyor now correctly resolves method names that conflict with PHP type keywords (e.g., int, string). No additional configuration is required.
Eloquent Builder Generics: New in v0.2.4: Surveyor propagates generics through Eloquent builder method chains. Ensure your codebase uses modern Laravel syntax for optimal parsing.
Cache Handling: New in v0.2.3: Corrupted disk cache files are automatically treated as cache misses, preventing stale data from being returned. No additional configuration is required.
How can I help you explore Laravel packages today?