Installation
composer require goaop/dissect
Add to composer.json if not auto-loaded:
"autoload": {
"psr-4": {
"App\\": "app/",
"Dissect\\": "vendor/goaop/dissect/src/"
}
}
Run composer dump-autoload.
First Use Case: Parsing PHP Code
use Dissect\Parser;
$code = '<?php echo "Hello, World!";';
$parser = new Parser();
$ast = $parser->parse($code);
// Inspect the AST (Abstract Syntax Tree)
print_r($ast);
Where to Look First
src/ directory for classes like Parser, Lexer, and Node types.tests/ (if present) for practical usage patterns.Dissect\Parser: Main entry point for parsing PHP code.Dissect\Lexer: Tokenizes input code.Dissect\Node: Represents nodes in the AST (e.g., FunctionNode, ExpressionNode).Lexical Analysis (Tokenization) Extract tokens from raw PHP code for custom processing (e.g., linting, rewriting):
use Dissect\Lexer;
$lexer = new Lexer();
$tokens = $lexer->tokenize($code);
foreach ($tokens as $token) {
echo "Token: {$token->type}, Value: {$token->value}\n";
}
Syntactic Analysis (AST Traversal) Traverse the AST to analyze or modify code structure:
$ast = $parser->parse($code);
$visitor = new class($ast) implements Dissect\Visitor {
public function visitFunctionNode($node) {
// Custom logic for function nodes
echo "Found function: {$node->name}\n";
}
// Implement other visit methods as needed
};
$visitor->visit($ast);
Code Transformation Rewrite or refactor code by modifying the AST:
$ast = $parser->parse($code);
// Example: Replace all `echo` statements with `return`
$ast->accept(new class implements Dissect\Visitor {
public function visitEchoNode($node) {
$node->type = 'ReturnNode';
$node->expr = $node->expr; // Reuse the expression
}
});
$rewrittenCode = $parser->generate($ast);
Integration with Laravel
$this->app->singleton(Dissect\Parser::class, function ($app) {
return new Dissect\Parser();
});
use Illuminate\Console\Command;
use Dissect\Parser;
class AnalyzeCode extends Command
{
protected $parser;
public function __construct(Parser $parser)
{
parent::__construct();
$this->parser = $parser;
}
public function handle()
{
$code = file_get_contents('app/Http/Controllers/TestController.php');
$ast = $this->parser->parse($code);
// Analyze and output results
}
}
Event Listeners Hook into Laravel events to analyze code dynamically (e.g., on file save):
use Illuminate\Filesystem\Events\FileWritten;
Event::listen(FileWritten::class, function ($event) {
if ($event->path->endsWith('.php')) {
$parser = app(Dissect\Parser::class);
$ast = $parser->parse(file_get_contents($event->path));
// Trigger custom logic (e.g., validate AST)
}
});
PHP Version Compatibility
AST Node Mutability
Visitor pattern or Dissect’s built-in methods (e.g., generate()) to reconstruct valid code.// ❌ Avoid this (may corrupt AST)
$ast->nodes[0]->type = 'InvalidNodeType';
// ✅ Do this (use visitors or Dissect methods)
$ast->accept(new CustomVisitor());
Performance
app/ directory) can be slow. Cache results or use lazy loading:
$cache = new Illuminate\Cache\FileStore();
$astCacheKey = 'ast:'.md5($code);
$ast = $cache->remember($astCacheKey, 3600, function () use ($parser, $code) {
return $parser->parse($code);
});
Error Handling
try {
$ast = $parser->parse($code);
} catch (Dissect\ParseError $e) {
Log::error("Parse error in {$file}: " . $e->getMessage());
$ast = null;
}
Namespace Collisions
Node) may conflict with your project’s namespaces. Use fully qualified names or aliases:
use Dissect\Node as DissectNode;
Extend the Lexer
Customize tokenization by extending Dissect\Lexer:
class CustomLexer extends Dissect\Lexer {
protected function getTokenPatterns() {
$patterns = parent::getTokenPatterns();
$patterns[] = '/\@customDirective(\w+)/'; // Add custom directives
return $patterns;
}
}
Visitor Pattern for Complex Logic Break down complex transformations into smaller visitor classes:
class RenameVariablesVisitor implements Dissect\Visitor {
private $mapping = ['oldVar' => 'newVar'];
public function visitVariableNode($node) {
if (isset($this->mapping[$node->name])) {
$node->name = $this->mapping[$node->name];
}
}
}
Generate Code from AST
Use Parser::generate() to convert modified ASTs back to PHP:
$rewrittenCode = $parser->generate($ast);
file_put_contents('modified.php', $rewrittenCode);
Debugging ASTs Pretty-print ASTs for debugging:
echo $parser->generate($ast); // View raw PHP
// Or use a library like `symfony/var-dumper`:
dump($ast);
Combine with Other Tools
Testing Write unit tests for custom visitors/transformations:
public function testVisitorTransformsEchoToReturn() {
$code = '<?php echo "test";';
$ast = $parser->parse($code);
$ast->accept(new EchoToReturnVisitor());
$rewritten = $parser->generate($ast);
$this->assertStringContainsString('return', $rewritten);
}
Configuration
$parser = new Dissect\Parser([
'strict' => true, // Enable strict parsing
]);
How can I help you explore Laravel packages today?