Skip to content

Commit 1e28adc

Browse files
staabmclxmstaab
andauthored
PDO: added PDO::FETCH_KEY_PAIR support (#303)
Co-authored-by: Markus Staab <[email protected]>
1 parent 865ad5d commit 1e28adc

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

src/DoctrineReflection/DoctrineReflection.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use staabm\PHPStanDba\QueryReflection\QueryReflector;
2424
use Traversable;
2525

26+
// XXX move into a "Reflection" package on next major version
2627
final class DoctrineReflection
2728
{
2829
public function reduceResultType(MethodReflection $methodReflection, Type $resultType): ?Type

src/PdoReflection/PdoStatementReflection.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PDOStatement;
99
use PhpParser\Node\Expr;
1010
use PhpParser\Node\Expr\MethodCall;
11+
use PHPStan\Type\ArrayType;
1112
use PHPStan\Type\Constant\ConstantArrayType;
1213
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
1314
use PHPStan\Type\Constant\ConstantIntegerType;
@@ -20,8 +21,10 @@
2021
use staabm\PHPStanDba\QueryReflection\QueryReflection;
2122
use staabm\PHPStanDba\QueryReflection\QueryReflector;
2223

24+
// XXX move into a "Reflection" package on next major version
2325
final class PdoStatementReflection
2426
{
27+
// XXX move into separate class on next major version
2528
public function findPrepareQueryStringExpression(MethodCall $methodCall): ?Expr
2629
{
2730
$exprFinder = new ExpressionFinder();
@@ -37,6 +40,7 @@ public function findPrepareQueryStringExpression(MethodCall $methodCall): ?Expr
3740
return null;
3841
}
3942

43+
// XXX move into separate class on next major version
4044
/**
4145
* @return MethodCall[]
4246
*/
@@ -58,7 +62,9 @@ public function getFetchType(Type $fetchModeType): ?int
5862
return null;
5963
}
6064

61-
if (PDO::FETCH_ASSOC === $fetchModeType->getValue()) {
65+
if (PDO::FETCH_KEY_PAIR === $fetchModeType->getValue()) {
66+
return QueryReflector::FETCH_TYPE_KEY_VALUE;
67+
} elseif (PDO::FETCH_ASSOC === $fetchModeType->getValue()) {
6268
return QueryReflector::FETCH_TYPE_ASSOC;
6369
} elseif (PDO::FETCH_NUM === $fetchModeType->getValue()) {
6470
return QueryReflector::FETCH_TYPE_NUMERIC;
@@ -153,10 +159,17 @@ public function getColumnRowType(Type $statementType, int $columnIndex): ?Type
153159
*/
154160
private function reduceStatementResultType(Type $bothType, int $fetchType): Type
155161
{
162+
if (!$bothType instanceof ConstantArrayType) {
163+
return $bothType;
164+
}
165+
166+
if (\count($bothType->getValueTypes()) <= 0) {
167+
return $bothType;
168+
}
169+
156170
// turn a BOTH typed statement into either NUMERIC or ASSOC
157171
if (
158-
(QueryReflector::FETCH_TYPE_NUMERIC === $fetchType || QueryReflector::FETCH_TYPE_ASSOC === $fetchType) &&
159-
$bothType instanceof ConstantArrayType && \count($bothType->getValueTypes()) > 0
172+
QueryReflector::FETCH_TYPE_NUMERIC === $fetchType || QueryReflector::FETCH_TYPE_ASSOC === $fetchType
160173
) {
161174
$builder = ConstantArrayTypeBuilder::createEmpty();
162175

@@ -174,6 +187,13 @@ private function reduceStatementResultType(Type $bothType, int $fetchType): Type
174187
return $builder->getArray();
175188
}
176189

190+
// both types contains numeric and string keys, therefore the count is doubled
191+
if (QueryReflector::FETCH_TYPE_KEY_VALUE === $fetchType && \count($bothType->getValueTypes()) >= 4) {
192+
$valueTypes = $bothType->getValueTypes();
193+
194+
return new ArrayType($valueTypes[0], $valueTypes[2]);
195+
}
196+
177197
// not yet supported fetch type - or $fetchType == BOTH
178198
return $bothType;
179199
}

tests/default/data/pdo-stmt-fetch.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public function fetchAll(PDO $pdo)
3737
$all = $stmt->fetchAll(PDO::FETCH_COLUMN, 1);
3838
assertType('array<int, int<0, 4294967295>>', $all);
3939

40+
$all = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
41+
assertType('array<int, array<string, int<0, 4294967295>>>', $all);
42+
4043
// not yet supported fetch types
4144
$all = $stmt->fetchAll(PDO::FETCH_OBJ);
4245
assertType('array', $all); // XXX since php8 this cannot return false
@@ -72,6 +75,9 @@ public function fetch(PDO $pdo)
7275
$all = $stmt->fetch(PDO::FETCH_COLUMN, 1);
7376
assertType('int<0, 4294967295>|false', $all);
7477

78+
$all = $stmt->fetch(PDO::FETCH_KEY_PAIR);
79+
assertType('array<string, int<0, 4294967295>>|false', $all);
80+
7581
// not yet supported fetch types
7682
$all = $stmt->fetch(PDO::FETCH_OBJ);
7783
assertType('mixed', $all);

tests/rules/config/.phpstan-dba-mysqli.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)