Skip to content

Commit c9c166e

Browse files
staabmclxmstaab
andauthored
mysqli: implement type inference for union-types in sql queries (#294)
Co-authored-by: Markus Staab <[email protected]>
1 parent 84a28c4 commit c9c166e

File tree

8 files changed

+295
-10
lines changed

8 files changed

+295
-10
lines changed

src/Extensions/MysqliQueryDynamicReturnTypeExtension.php

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,23 +100,32 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
100100
private function inferResultType(Expr $queryExpr, Scope $scope): ?Type
101101
{
102102
$queryReflection = new QueryReflection();
103-
$queryString = $queryReflection->resolveQueryString($queryExpr, $scope);
104-
if (null === $queryString) {
103+
$queryStrings = $queryReflection->resolveQueryStrings($queryExpr, $scope);
104+
105+
$genericObjects = [];
106+
foreach ($queryStrings as $queryString) {
107+
$resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_ASSOC);
108+
109+
if (null === $resultType) {
110+
return null;
111+
}
112+
113+
$genericObjects[] = new GenericObjectType(mysqli_result::class, [$resultType]);
114+
}
115+
116+
if (0 === \count($genericObjects)) {
105117
return null;
106118
}
107119

108-
$resultType = $queryReflection->getResultType($queryString, QueryReflector::FETCH_TYPE_ASSOC);
109-
if ($resultType) {
110-
if (QueryReflection::getRuntimeConfiguration()->throwsMysqliExceptions($this->phpVersion)) {
111-
return new GenericObjectType(mysqli_result::class, [$resultType]);
112-
}
120+
$resultType = TypeCombinator::union(...$genericObjects);
113121

122+
if (!QueryReflection::getRuntimeConfiguration()->throwsMysqliExceptions($this->phpVersion)) {
114123
return TypeCombinator::union(
115-
new GenericObjectType(mysqli_result::class, [$resultType]),
124+
$resultType,
116125
new ConstantBooleanType(false),
117126
);
118127
}
119128

120-
return null;
129+
return $resultType;
121130
}
122131
}

tests/default/DbaInferenceTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function dataFileAsserts(): iterable
4747

4848
yield from $this->gatherAssertTypes(__DIR__.'/data/bug254.php');
4949
yield from $this->gatherAssertTypes(__DIR__.'/data/pdo-union-result.php');
50+
yield from $this->gatherAssertTypes(__DIR__.'/data/mysqli-union-result.php');
5051
}
5152

5253
/**

tests/default/config/.phpstan-dba-mysqli.cache

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/default/config/.phpstan-dba-pdo.cache

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/default/config/.phpunit-phpstan-dba-mysqli.cache

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/default/config/.phpunit-phpstan-dba-pdo.cache

Lines changed: 64 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace PdoUnionResult;
4+
5+
use mysqli;
6+
use function PHPStan\Testing\assertType;
7+
8+
class Foo
9+
{
10+
public function doBar(mysqli $mysqli)
11+
{
12+
$queries = ['SELECT adaid FROM ada', 'SELECT email FROM ada'];
13+
14+
foreach ($queries as $query) {
15+
$result = $mysqli->query($query);
16+
assertType('mysqli_result<array{adaid: int<0, 4294967295>}>|mysqli_result<array{email: string}>', $result);
17+
}
18+
}
19+
}

tests/rules/config/.phpstan-dba-pdo.cache

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)