Download the PHP package pierresh/phpstan-pdo-mysql without Composer
On this page you can find all versions of the php package pierresh/phpstan-pdo-mysql. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download pierresh/phpstan-pdo-mysql
More information about pierresh/phpstan-pdo-mysql
Files in pierresh/phpstan-pdo-mysql
Package phpstan-pdo-mysql
Short Description PHPStan rules for validating PDO/MySQL code: SQL syntax, parameter bindings, and SELECT columns matching PHPDoc types
License MIT
Informations about the package phpstan-pdo-mysql
PHPStan PDO MySQL Rules
Static analysis rules for PHPStan that validate PDO/MySQL code for common errors that would otherwise only be caught at runtime.
Features
This extension provides seven powerful rules that work without requiring a database connection:
- SQL Syntax Validation - Detects MySQL syntax errors in
prepare()andquery()calls - Parameter Binding Validation - Ensures PDO parameters match SQL placeholders
- SELECT Column Validation - Verifies SELECT columns match PHPDoc type annotations
- Self-Reference Detection - Catches self-reference conditions in JOIN and WHERE clauses
- Invalid Table Reference Detection - Catches typos in table/alias names (e.g.,
user.namewhen table isusers) - Tautological Condition Detection - Catches always-true/false conditions like
WHERE 1 = 1 - MySQL-Specific Syntax Detection - Flags MySQL-specific functions that have portable ANSI alternatives
All validation is performed statically by analyzing your code, so no database setup is needed.
Developer Tools:
ddt()Helper Function - Generates PHPStan type definitions from runtime values for easy copy-paste into your codeddc()Helper Function - Generates PHP class definitions from objects for use withPDO::fetchObject()
Installation
The extension will be automatically registered if you use phpstan/extension-installer.
Manual registration in phpstan.neon:
Examples
1. SQL Syntax Validation
Catches syntax errors in SQL queries:
[!CAUTION] SQL syntax error in query(): Expected token NAME ~RESERVED, but end of query found instead.
Works with both direct strings and variables:
[!CAUTION] SQL syntax error in query(): Expected token NAME ~RESERVED, but end of query found instead.
2. Parameter Binding Validation
Ensures all SQL placeholders have corresponding bindings:
[!CAUTION] Missing parameter :name in execute()
[!CAUTION] Parameter :extra in execute() is not used
[!CAUTION] Missing parameter :user_id in execute()
Parameter :id in execute() is not used
Important: When execute() receives an array, it ignores previous bindValue() calls:
[!CAUTION] Missing parameter :id in execute()
Parameter :name in execute() is not used
3. SELECT Column Validation
Validates that SELECT columns match the PHPDoc type annotation.
[!NOTE] This rule supports
fetch(),fetchObject(), andfetchAll()methods, assuming the fetch mode of the database connection isPDO::FETCH_OBJ(returning objects). Other fetch modes likePDO::FETCH_ASSOC(arrays) orPDO::FETCH_CLASSare not currently validated.[!CAUTION] SELECT column mismatch: PHPDoc expects property "name" but SELECT (line X) has "nam" - possible typo?
[!CAUTION] SELECT column missing: PHPDoc expects property "email" but it is not in the SELECT query (line X)
Supports @phpstan-type aliases:
[!CAUTION] SELECT column mismatch: PHPDoc expects property "name" but SELECT (line X) has "nam" - possible typo?
SELECT column missing: PHPDoc expects property "email" but it is not in the SELECT query (line X)
Fetch Method Type Validation
The extension also validates that your PHPDoc type structure matches the fetch method being used:
[!CAUTION] Type mismatch: fetchAll() returns array<object{...}> but PHPDoc specifies object{...} (line X)
[!CAUTION] Type mismatch: fetch() returns object{...} but PHPDoc specifies array<object{...}> (line X)
[!NOTE] Both PHPStan array syntaxes are supported:
- Generic syntax:
array<object{...}>- Suffix syntax:
object{...}[]
False Return Type Validation
The extension validates that fetch() and fetchObject() calls properly handle the false return value that occurs when no rows are found.
[!CAUTION] Missing |false in @var type: fetch() can return false when no results found. Either add |false to the type or check for false/rowCount() before using the result (line X)
[!CAUTION] Missing |false in @var type: fetch() can return false when no results found. Either add |false to the type or check for false/rowCount() before using the result (line X)
[!NOTE] This validation applies only to
fetch()andfetchObject(). ThefetchAll()method returns an empty array instead of false, so it doesn't require|falsein the type annotation.
4. Self-Reference Detection
Detects self-reference conditions where the same column is compared to itself. This is likely a bug where the developer meant to reference a different table or column.
[!CAUTION] Self-referencing JOIN condition: 'users.id = users.id'
[!CAUTION] Self-referencing WHERE condition: 'products.category_id = products.category_id'
[!CAUTION] Self-referencing JOIN condition: 'products.id = products.id'
Self-referencing WHERE condition: 'products.active = products.active'
[!NOTE] This rule works with:
INNER JOIN,LEFT JOIN,RIGHT JOINconditionsWHEREclause conditions (includingAND/ORcombinations)- Both
SELECTandINSERT...SELECTqueries- Queries with PDO placeholders (
:parameter)
The rule reports errors on the exact line where the self-reference occurs, making it easy to locate and fix the issue.
5. Invalid Table Reference Detection
Detects typos in table and alias names used in qualified column references. Catches errors like using user.name when the table is users, or referencing a table that doesn't appear in FROM/JOIN clauses.
[!CAUTION] Invalid table reference 'user' - available tables/aliases: users
[!CAUTION] Invalid table reference 'usr' - available tables/aliases: u, users
[!CAUTION] Invalid table reference 'orders' - available tables/aliases: users
The rule validates:
- Column references in SELECT clause
- Column references in WHERE conditions
- Column references in JOIN conditions
- Column references in ORDER BY and GROUP BY clauses
- Column references in HAVING clause
This catches common typos that would only be discovered at runtime, like:
- Singular/plural mistakes (
uservsusers) - Typos in alias names (
usrvsusrs) - Wrong table references in complex JOINs
6. Tautological Condition Detection
Detects tautological conditions that are always true or always false. These are often left over from development (e.g., WHERE 1 = 1 used to easily toggle conditions) and should be removed before committing.
[!CAUTION] Tautological condition in WHERE clause: '1 = 1' (always true)
[!CAUTION] Tautological condition in WHERE clause: '1 = 0' (always false)
[!CAUTION] Tautological condition in WHERE clause: ''yes' = 'yes'' (always true)
[!CAUTION] Tautological condition in WHERE clause: 'TRUE = FALSE' (always false)
[!CAUTION] Tautological condition in JOIN clause: '1 = 1' (always true)
[!NOTE] This rule detects:
- Numeric comparisons:
1 = 1,0 = 0,42 = 42,1 = 0- String comparisons:
'yes' = 'yes','a' = 'b'- Boolean comparisons:
TRUE = TRUE,FALSE = FALSE,TRUE = FALSE- In WHERE, JOIN ON, and HAVING clauses
7. MySQL-Specific Syntax Detection
Detects MySQL-specific SQL syntax that has portable ANSI alternatives. This helps maintain database-agnostic code for future migrations to PostgreSQL, SQL Server, or other databases.
[!CAUTION] Use COALESCE() instead of IFNULL() for database portability
[!CAUTION] Use CASE WHEN instead of IF() for database portability
[!CAUTION] Bind current datetime to a PHP variable instead of NOW() for database portability
[!CAUTION] Bind current date to a PHP variable instead of CURDATE() for database portability
[!CAUTION] Use LIMIT count OFFSET offset instead of LIMIT offset, count for database portability
Currently detects:
IFNULL()→ UseCOALESCE()IF()→ UseCASE WHENNOW()→ Bind PHP datetime variableCURDATE()→ Bind PHP date variableLIMIT offset, count→ UseLIMIT count OFFSET offset
Requirements
- PHP 8.1+
- PHPStan 1.10+
- SQLFTW 0.1+ (SQL syntax validation)
How It Works
All four rules use a two-pass analysis approach:
- First pass: Scan the method for SQL query strings (both direct literals and variables)
- Second pass: Find all
prepare()/query()calls and validate them
This allows the rules to work with both patterns:
The rules also handle SQL queries prepared in constructors and used in other methods.
Known Limitations
- SQL queries with variable interpolation (e.g.,
"SELECT $column FROM table") cannot be validated SELECT *andSELECT table.*queries cannot be validated for column matching (no way to know columns statically)- Very long queries (>10,000 characters) are skipped for performance
- Cross-file SQL tracking is limited to class properties
Performance
These rules are designed to be fast:
- Early bailouts for non-SQL code
- Efficient SQL detection heuristics
- Skips very long queries (>10,000 characters)
- Gracefully handles missing dependencies
Available Error Identifiers
| Identifier | Rule | Description |
|---|---|---|
pdoSql.sqlSyntax |
SQL Syntax Validation | SQL syntax error detected |
pdoSql.missingParameter |
Parameter Bindings | Parameter expected in SQL but missing from execute() array |
pdoSql.extraParameter |
Parameter Bindings | Parameter in execute() array but not used in SQL |
pdoSql.missingBinding |
Parameter Bindings | Parameter expected but no bindValue()/bindParam() found |
pdoSql.extraBinding |
Parameter Bindings | Parameter bound but not used in SQL |
pdoSql.columnMismatch |
SELECT Column Validation | Column name typo detected (case-sensitive) |
pdoSql.columnMissing |
SELECT Column Validation | PHPDoc property missing from SELECT |
pdoSql.fetchTypeMismatch |
SELECT Column Validation | Fetch method doesn't match PHPDoc type structure |
pdoSql.missingFalseType |
SELECT Column Validation | Missing \|false union type for fetch()/fetchObject() |
pdoSql.selfReferenceCondition |
Self-Reference Detection | Self-referencing condition in JOIN or WHERE clause |
pdoSql.invalidTableReference |
Invalid Table Reference Detection | Invalid table or alias name in qualified column reference |
pdoSql.mySqlSpecific |
MySQL-Specific Syntax | MySQL-specific function with portable alternative |
pdoSql.tautologicalCondition |
Tautological Condition Detection | Always-true or always-false condition detected |
Ignoring Specific Errors
All errors from this extension have custom identifiers that allow you to selectively ignore them in your phpstan.neon:
You can also ignore errors by path or message pattern:
Playground
Want to try the extension quickly? Open playground/example.php in your IDE with a PHPStan plugin installed. You'll see errors highlighted in real-time as you edit the code.
Developer Tools
ddt() - Dump Debug Type
The ddt() helper function inspects PHP values at runtime and generates PHPStan type definitions. This is useful for quickly creating @phpstan-type annotations from real data in tests.
Usage in PHPUnit tests:
Terminal output:
Simply copy the output and paste it into your code as a type annotation!
Supported types:
- Objects (stdClass and class instances): Shows public properties as
object{...}shape - Associative arrays: Formatted as
array{key: type, ...} - Sequential arrays: Formatted as
array<int, type> - Nested structures: Handles nesting up to 5 levels deep
- All scalar types: int, float, string, bool, null
Type mapping:
| PHP Runtime Type | PHPStan Output |
|---|---|
integer |
int |
double |
float |
string |
string |
boolean |
bool |
NULL |
null |
array (associative) |
array{key: type, ...} |
array (sequential) |
array<int, type> |
object |
object{prop: type, ...} |
Examples:
Note: The function calls exit(0) after dumping (like dd()), so execution stops. This is intentional for use in debugging/testing workflows.
ddc() - Dump Debug Class
The ddc() helper function inspects PHP objects at runtime and generates PHP class definitions. This is useful for creating view model classes compatible with PDO::fetchObject().
Usage in PHPUnit tests:
Terminal output:
Simply copy the output, rename the class, and use it as your view model!
Example workflow:
Supported types:
| PHP Runtime Value | Generated Type |
|---|---|
integer |
int |
double |
float |
string |
string |
boolean |
bool |
NULL |
mixed |
array |
array |
object |
object |
Note: Like ddt(), this function calls exit(0) after dumping.
Development
To contribute to this project:
-
Clone the repository:
-
Install dependencies:
- Run tests:
This will start PHPUnit watcher that automatically runs tests when files change.
To run tests once without watching:
- Analyze source code with PHPStan:
This analyzes only the ./src directory (excludes playground and test fixtures) at maximum level.
- Refactor code with Rector:
Rector is configured to modernize code to PHP 8.1+ standards with code quality improvements.
- Format code with Mago:
Mago provides consistent, opinionated code formatting for PHP 8.1+.
-
Lint code with Mago:
- Analyze code with Mago:
Mago's analyzer provides fast, type-level analysis to find logical errors and type mismatches.
License
MIT
Contributing
Contributions welcome! Please open an issue or submit a pull request.