Skip to content

Commit 756c419

Browse files
staabmclxmstaab
andauthored
support PDOStatement::fetch() (#41)
Co-authored-by: Markus Staab <[email protected]>
1 parent d4df070 commit 756c419

File tree

3 files changed

+38
-4
lines changed

3 files changed

+38
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This extension provides following features:
44

55
* the array shape of results can be inferred for `PDOStatement` and `mysqli_result`
66
* .. when the query string can be resolved at analysis time. This is even possible for queries containing php-variables, as long as their typ is known in most cases.
7-
* builtin we support `mysqli_query`, `mysqli->query`, `PDOStatement->fetchAll`, `PDO->query` and `PDO->prepare`
7+
* builtin we support `mysqli_query`, `mysqli->query`, `PDOStatement->fetch`, `PDOStatement->fetchAll`, `PDO->query` and `PDO->prepare`
88
* `PDO->prepare` knows the array shape of the returned results and therefore can return a generic `PDOStatement`
99
* `mysqli->query` knows the array shape of the returned results and therefore can return a generic `mysqli_result`
1010
* `SyntaxErrorInQueryMethodRule` can inspect sql queries and detect syntax errors - `SyntaxErrorInQueryFunctionRule` can do the same for functions

src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
use PHPStan\Type\ArrayType;
1414
use PHPStan\Type\Constant\ConstantArrayType;
1515
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
16+
use PHPStan\Type\Constant\ConstantBooleanType;
1617
use PHPStan\Type\Constant\ConstantIntegerType;
1718
use PHPStan\Type\Constant\ConstantStringType;
1819
use PHPStan\Type\DynamicMethodReturnTypeExtension;
1920
use PHPStan\Type\Generic\GenericObjectType;
2021
use PHPStan\Type\IntegerType;
2122
use PHPStan\Type\Type;
23+
use PHPStan\Type\UnionType;
2224

2325
final class PdoStatementFetchDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
2426
{
@@ -29,7 +31,7 @@ public function getClass(): string
2931

3032
public function isMethodSupported(MethodReflection $methodReflection): bool
3133
{
32-
return 'fetchAll' === $methodReflection->getName();
34+
return \in_array($methodReflection->getName(), ['fetchAll', 'fetch'], true);
3335
}
3436

3537
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
@@ -75,10 +77,18 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method
7577
}
7678
}
7779

78-
return new ArrayType(new IntegerType(), $builder->getArray());
80+
if ('fetchAll' === $methodReflection->getName()) {
81+
return new ArrayType(new IntegerType(), $builder->getArray());
82+
}
83+
84+
return new UnionType([$builder->getArray(), new ConstantBooleanType(false)]);
85+
}
86+
87+
if ('fetchAll' === $methodReflection->getName()) {
88+
return new ArrayType(new IntegerType(), $resultType);
7989
}
8090

81-
return new ArrayType(new IntegerType(), $resultType);
91+
return new UnionType([$resultType, new ConstantBooleanType(false)]);
8292
}
8393

8494
return $defaultReturn;

tests/data/pdo-stmt-fetch.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,28 @@ public function fetchAll(PDO $pdo)
3030
$all = $stmt->fetchAll(PDO::FETCH_OBJ);
3131
assertType('array|false', $all); // XXX since php8 this cannot return false
3232
}
33+
34+
public function fetch(PDO $pdo)
35+
{
36+
$stmt = $pdo->prepare('SELECT email, adaid FROM ada');
37+
$stmt->execute();
38+
assertType('PDOStatement<array{email: string, 0: string, adaid: int<0, 4294967295>, 1: int<0, 4294967295>}>', $stmt);
39+
40+
// default fetch-mode is BOTH
41+
$all = $stmt->fetch();
42+
assertType('array{email: string, 0: string, adaid: int<0, 4294967295>, 1: int<0, 4294967295>}|false', $all);
43+
44+
$all = $stmt->fetch(PDO::FETCH_BOTH);
45+
assertType('array{email: string, 0: string, adaid: int<0, 4294967295>, 1: int<0, 4294967295>}|false', $all);
46+
47+
$all = $stmt->fetch(PDO::FETCH_NUM);
48+
assertType('array{string, int<0, 4294967295>}|false', $all);
49+
50+
$all = $stmt->fetch(PDO::FETCH_ASSOC);
51+
assertType('array{email: string, adaid: int<0, 4294967295>}|false', $all);
52+
53+
// not yet supported fetch types
54+
$all = $stmt->fetch(PDO::FETCH_OBJ);
55+
assertType('mixed', $all);
56+
}
3357
}

0 commit comments

Comments
 (0)