Installation
composer require greenlion/php-sql-parser
Add to composer.json if not using autoloader:
"autoload": {
"psr-4": {
"App\\": "app/",
"GreenLion\\SQLParser\\": "vendor/greenlion/php-sql-parser/src/"
}
}
Run composer dump-autoload.
First Use Case Parse a simple query in a Laravel controller or service:
use GreenLion\SQLParser\Parser;
$parser = new Parser();
$sql = 'SELECT id, name FROM users WHERE id > 10 LIMIT 10';
$ast = $parser->parse($sql);
// Output the Abstract Syntax Tree (AST)
print_r($ast);
Key Entry Points
Parser::parse(): Core method to generate AST.Parser::getAST(): Retrieve the parsed AST object.Parser::getTokens(): Get raw token stream (for debugging).Query Analysis Extract metadata from SQL (e.g., table names, columns, conditions):
$ast = $parser->parse('SELECT * FROM users WHERE active = 1');
$tables = collect($ast->getTables())->pluck('name'); // ['users']
$columns = collect($ast->getColumns())->pluck('name'); // ['*']
Dynamic Query Building Modify parsed SQL programmatically (e.g., add conditions):
$ast = $parser->parse('SELECT id FROM users');
$ast->where->addCondition('active', '=', true);
$modifiedSql = $ast->getSQL(); // "SELECT id FROM users WHERE active = 1"
Validation & Sanitization
Check for unsafe patterns (e.g., UNION, DROP TABLE):
$ast = $parser->parse($userInputSql);
if ($ast->hasUnsafeOperations()) {
throw new \Exception('SQL contains unsafe operations.');
}
ORM Integration Translate parsed SQL to Eloquent queries:
$ast = $parser->parse('SELECT name, email FROM users WHERE status = ?');
$query = User::query();
foreach ($ast->getColumns() as $column) {
$query->addSelect($column->name);
}
$query->where('status', $ast->where->conditions[0]->value);
Token Stream Processing Inspect raw tokens for custom logic:
$tokens = $parser->getTokens();
foreach ($tokens as $token) {
if ($token->type === 'KEYWORD' && $token->value === 'JOIN') {
// Handle JOIN logic
}
}
Laravel Service Provider Bind the parser as a singleton for global access:
$this->app->singleton(Parser::class, function () {
return new Parser();
});
Middleware for SQL Inspection Parse incoming SQL in middleware (e.g., for API queries):
public function handle($request, Closure $next) {
$sql = $request->input('sql');
$ast = app(Parser::class)->parse($sql);
// Log or validate $ast
return $next($request);
}
Event Listeners Trigger events when specific SQL patterns are detected:
$parser->on('table-access', function ($table) {
\Log::info("Table accessed: {$table->name}");
});
$parser->parse($sql);
Caching Parsed Queries Cache AST objects for repeated queries:
$cacheKey = md5($sql);
$ast = Cache::remember($cacheKey, now()->addHours(1), function () use ($parser, $sql) {
return $parser->parse($sql);
});
Non-Standard SQL Dialects
ILIKE, RETURNING) may fail or produce incomplete ASTs.Complex SQL Features
OVER(PARTITION BY ...) may not be fully analyzed).try-catch and fall back to raw SQL execution if parsing fails.Whitespace Sensitivity
SELECT * FROM) may cause tokenization issues.trim() or regex to normalize whitespace:
$sql = preg_replace('/\s+/', ' ', $sql);
Parameterized Queries
:param) are not supported. Only ? placeholders work.? before parsing:
$sql = str_replace([':id', ':name'], ['?', '?'], $sql);
Case Sensitivity
SELECT, FROM) are case-insensitive in parsing but may affect AST structure.$sql = strtoupper($sql); // or strtolower()
Inspect Tokens Dump raw tokens to diagnose parsing issues:
$tokens = $parser->getTokens();
foreach ($tokens as $token) {
var_dump($token->type, $token->value);
}
AST Visualization
Use print_r or json_encode to explore the AST structure:
echo json_encode($ast, JSON_PRETTY_PRINT);
Partial Parsing Handle parsing errors gracefully:
try {
$ast = $parser->parse($sql);
} catch (\GreenLion\SQLParser\Exception\ParseException $e) {
\Log::error("SQL parse error: {$e->getMessage()}");
// Fallback: execute raw SQL or return empty result
}
Test Edge Cases Common failure points:
SELECT /* comment */ * FROM users).WHERE, FROM, or SELECT.FROM users AS "user_1").Custom Token Handlers Extend tokenization for domain-specific SQL:
$parser->addTokenHandler('CUSTOM_KEYWORD', function ($lexer, $value) {
return new \GreenLion\SQLParser\Token('CUSTOM_KEYWORD', $value);
});
AST Modifiers Override AST nodes post-parsing:
$ast = $parser->parse($sql);
$ast->visit(function ($node) {
if ($node instanceof \GreenLion\SQLParser\AST\Where) {
$node->addCondition('custom_field', '>', 'value');
}
});
Plugin System Create reusable parsers for specific use cases:
class UserQueryParser {
public function parse($sql) {
$parser = new Parser();
$ast = $parser->parse($sql);
// Add user-specific logic
return $ast;
}
}
Performance Optimization
$ast = $parser->parse($sql);
$columns = $ast->getColumns(); // Only parse columns if needed
Integration with Query Builders Sync parsed SQL with Laravel’s query builder:
$ast = $parser->parse($sql);
$query = DB::query();
foreach ($ast->getTables() as $table) {
$query->from($table->name);
}
// Map conditions, joins, etc.
How can I help you explore Laravel packages today?