-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
This simple example showcases basic features of maria-stan via the built-in MySQLi PHPStan extension. See the example file [run.php](run.php) and PHPStan's output in [phpstan.out](phpstan.out). You can also try it out yourself: | ||
|
||
First, clone the repository and run `composer install` in the root directory. Then set up a MariaDB instance. You can use the following docker command to run a new one (from root directory of the project): | ||
|
||
```bash | ||
docker run --detach --name maria-stan-example-mysqli \ | ||
--volume ./examples/MySQLi/data.sql:/docker-entrypoint-initdb.d/init.sql --env MARIADB_ROOT_PASSWORD=root --env MARIADB_DATABASE=maria-stan-example-mysqli \ | ||
--publish 13306:3306 --rm mariadb:10.11.5-jammy | ||
``` | ||
|
||
Or you can use whatever MariaDB instance you already have running. However, you'll probably have to modify the `phpstan.neon`, because I'm using a non-standard MariaDB port to avoid conflict with other MariaDB instances already running on your system. | ||
|
||
Finally, you can run phpstan and see the result for yourself (from root directory of the project): | ||
|
||
`php vendor/bin/phpstan analyse -c examples/MySQLi/phpstan.neon --debug examples/MySQLi/run.php` | ||
|
||
If you are curious about what else maria-stan can do, you can edit the `run.php` script and see what happens when you | ||
try other queries (keep in mind that the MySQLi PHPStan extension is incomplete, so some use-cases may not be covered). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
CREATE TABLE schools ( | ||
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, | ||
name VARCHAR (255) NOT NULL, | ||
type ENUM ('elementary', 'secondary', 'university') NOT NULL | ||
); | ||
|
||
INSERT INTO schools (id, name, type) | ||
VALUES (1, 'Foo elementary school', 'elementary'), (2, 'Bar secondary school', 'secondary'), (3, 'Baz university', 'university'); | ||
|
||
CREATE TABLE people ( | ||
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, | ||
name VARCHAR (255) NOT NULL | ||
); | ||
|
||
INSERT INTO people (id, name) | ||
VALUES (1, 'John Doe'), ('2', 'Jane Doe'), (3, 'John Doe jr.'), (4, 'Jane Doe jr.'); | ||
|
||
CREATE TABLE classes ( | ||
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, | ||
name VARCHAR(255) NOT NULL, | ||
school_id INT NOT NULL REFERENCES schools (id), | ||
teacher_id INT NULL REFERENCES people (id) | ||
); | ||
|
||
INSERT INTO classes (id, name, school_id, teacher_id) | ||
VALUES (1, 'History', 1, 1), (2, 'Math', 1, 1), (3, 'PHP Programming', 2, 2), (4, 'Algorithms and Data Structures', 3, 2); | ||
|
||
CREATE TABLE class_students ( | ||
class_id INT NOT NULL REFERENCES people (id), | ||
student_id INT NOT NULL REFERENCES people (id) | ||
); | ||
|
||
INSERT INTO class_students (class_id, student_id) | ||
VALUES (1, 1), (2, 1), (3, 2); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
includes: | ||
- ../../extension.mysqli.neon | ||
|
||
parameters: | ||
level: 9 | ||
maria-stan: | ||
db: | ||
host: 127.0.0.1 | ||
port: 13306 | ||
user: 'root' | ||
password: 'root' | ||
database: 'maria-stan-example-mysqli' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
------ ---------------------------------------------------------------------------------- | ||
Line run.php | ||
------ ---------------------------------------------------------------------------------- | ||
28 Dumped type: array<int, array{id: int, name: string, type: | ||
'elementary'|'secondary'|'university'}> | ||
42 Dumped type: array<int, array{name: string, average_no_classes: numeric-string}> | ||
55 Dumped type: array<int, array{id: int, name?: string, type?: | ||
'elementary'|'secondary'|'university'}> | ||
59 Table 'non_existent_table' doesn't exist | ||
67 The used SELECT statements have a different number of columns: 3 vs 2. | ||
------ ---------------------------------------------------------------------------------- | ||
|
||
|
||
[ERROR] Found 5 errors | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
// @phpstan-ignore-next-line phpstanApi.phpstanNamespace | ||
namespace PHPStan { | ||
|
||
use function function_exists; | ||
use function var_dump; | ||
|
||
if (! function_exists('dumpType')) { | ||
function dumpType(mixed $value): void | ||
{ | ||
var_dump($value); | ||
} | ||
} | ||
} | ||
|
||
namespace { | ||
|
||
use function rand; | ||
|
||
// These credentials are not used for analysis. They are here just so you can try to run the script. | ||
$db = new mysqli('127.0.0.1', 'root', 'root', 'maria-stan-example-mysqli', 13306); | ||
|
||
// Trivial query - maria-stan should report the correct result type based on the table schema. | ||
$result = $db->query('SELECT * FROM schools')->fetch_all(\MYSQLI_ASSOC); | ||
\PHPStan\dumpType($result); | ||
|
||
// A slightly more complicated query. Notice that maria-stan recognizes that average_no_classes cannot be null! | ||
$result = $db->query(' | ||
SELECT s.name, AVG(number_of_classes) average_no_classes | ||
FROM schools s | ||
JOIN ( | ||
SELECT c.school_id, cs.student_id, COUNT(*) number_of_classes | ||
FROM classes c | ||
JOIN class_students cs ON c.id = cs.class_id | ||
GROUP BY c.school_id, cs.student_id | ||
) cs ON cs.school_id = s.id | ||
GROUP BY s.id | ||
')->fetch_all(\MYSQLI_ASSOC); | ||
\PHPStan\dumpType($result); | ||
|
||
// Sometimes the query can be partially dynamic. But as long as PHPStan is able to provide us with a union of | ||
// constant strings, such queries can still be analysed. Keep in mind that PHPStan has a limit of how many constant | ||
// values can be in a union, before it gets generalized. Each possible query is analysed individually, | ||
// and the results (i.e. return types and errors) are then combined. | ||
$table = rand() | ||
? 'schools' | ||
: 'people'; | ||
$col = rand() | ||
? 'id' | ||
: '*'; | ||
$result = $db->query("SELECT {$col} FROM {$table}" . ' WHERE 1')->fetch_all(\MYSQLI_ASSOC); | ||
\PHPStan\dumpType($result); | ||
|
||
// Here we have a trivially wrong query - it references a table which doesn't exist. Maria-stan should report it. | ||
try { | ||
$db->query('SELECT * FROM non_existent_table'); | ||
die('This was expected to fail!'); | ||
} catch (mysqli_sql_exception) { | ||
} | ||
|
||
// Here is a slightly more sneaky error. You can probably imagine that you have a query like this, which worked | ||
// when it was first written, but then someone adds a column into one of the tables which breaks the query. | ||
try { | ||
$db->query(' | ||
SELECT * FROM schools | ||
UNION ALL | ||
SELECT * FROM people | ||
'); | ||
die('This was expected to fail!'); | ||
} catch (mysqli_sql_exception) { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters