From e5667a0bccaf0adbe0ce98bbe9b317b011e0d901 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 6 Feb 2022 20:34:42 +0100 Subject: [PATCH 1/2] extracted PdoStatementReflection->getStatementResultType() for later re-use --- ...tatementExecuteTypeSpecifyingExtension.php | 2 +- ...atementFetchDynamicReturnTypeExtension.php | 32 +++----------- src/PdoReflection/PdoStatementReflection.php | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php b/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php index 3a62ccb1b..0a982a8b6 100644 --- a/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php +++ b/src/Extensions/PdoStatementExecuteTypeSpecifyingExtension.php @@ -30,7 +30,7 @@ public function getClass(): string public function isMethodSupported(MethodReflection $methodReflection, MethodCall $node, TypeSpecifierContext $context): bool { - return 'execute' === $methodReflection->getName(); + return 'execute' === strtolower($methodReflection->getName()); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php b/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php index 4dfaf8d18..611f63ee4 100644 --- a/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php +++ b/src/Extensions/PdoStatementFetchDynamicReturnTypeExtension.php @@ -24,6 +24,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\UnionType; +use staabm\PHPStanDba\PdoReflection\PdoStatementReflection; use staabm\PHPStanDba\QueryReflection\QueryReflection; final class PdoStatementFetchDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension @@ -69,16 +70,6 @@ private function inferType(MethodReflection $methodReflection, MethodCall $metho $args = $methodCall->getArgs(); $statementType = $scope->getType($methodCall->var); - if (!$statementType instanceof GenericObjectType) { - return null; - } - - $genericTypes = $statementType->getTypes(); - - if (1 !== \count($genericTypes)) { - return null; - } - $fetchType = PDO::FETCH_BOTH; if (\count($args) > 0) { $fetchModeType = $scope->getType($args[0]->value); @@ -92,23 +83,10 @@ private function inferType(MethodReflection $methodReflection, MethodCall $metho } } - $resultType = $genericTypes[0]; - - if ((PDO::FETCH_NUM === $fetchType || PDO::FETCH_ASSOC === $fetchType) && $resultType instanceof ConstantArrayType) { - $builder = ConstantArrayTypeBuilder::createEmpty(); - - $keyTypes = $resultType->getKeyTypes(); - $valueTypes = $resultType->getValueTypes(); - - foreach ($keyTypes as $i => $keyType) { - if (PDO::FETCH_NUM === $fetchType && $keyType instanceof ConstantIntegerType) { - $builder->setOffsetValueType($keyType, $valueTypes[$i]); - } elseif (PDO::FETCH_ASSOC === $fetchType && $keyType instanceof ConstantStringType) { - $builder->setOffsetValueType($keyType, $valueTypes[$i]); - } - } - - $resultType = $builder->getArray(); + $pdoStatementReflection = new PdoStatementReflection(); + $resultType = $pdoStatementReflection->getStatementResultType($statementType, $fetchType); + if ($resultType === null) { + return null; } if ('fetchAll' === $methodReflection->getName()) { diff --git a/src/PdoReflection/PdoStatementReflection.php b/src/PdoReflection/PdoStatementReflection.php index 34d1ef545..30ea9d43b 100644 --- a/src/PdoReflection/PdoStatementReflection.php +++ b/src/PdoReflection/PdoStatementReflection.php @@ -4,10 +4,19 @@ namespace staabm\PHPStanDba\PdoReflection; +use PDO; use PhpParser\Node\Expr; use PhpParser\Node\Expr\MethodCall; use PHPStan\Reflection\MethodReflection; +use PHPStan\Type\Constant\ConstantArrayType; +use PHPStan\Type\Constant\ConstantArrayTypeBuilder; +use PHPStan\Type\Constant\ConstantIntegerType; +use PHPStan\Type\Constant\ConstantStringType; +use PHPStan\Type\Generic\GenericObjectType; +use PHPStan\Type\Type; use staabm\PHPStanDba\QueryReflection\ExpressionFinder; +use staabm\PHPStanDba\QueryReflection\QueryReflection; +use staabm\PHPStanDba\QueryReflection\QueryReflector; final class PdoStatementReflection { @@ -25,4 +34,39 @@ public function findPrepareQueryStringExpression(MethodReflection $methodReflect return null; } + + /** + * @param PDO::FETCH* $fetchType + * @return Type|null + */ + public function getStatementResultType(Type $statementType, int $fetchType) { + if (!$statementType instanceof GenericObjectType) { + return null; + } + + $genericTypes = $statementType->getTypes(); + if (1 !== \count($genericTypes)) { + return null; + } + + $resultType = $genericTypes[0]; + if ((PDO::FETCH_NUM === $fetchType || PDO::FETCH_ASSOC === $fetchType) && $resultType instanceof ConstantArrayType) { + $builder = ConstantArrayTypeBuilder::createEmpty(); + + $keyTypes = $resultType->getKeyTypes(); + $valueTypes = $resultType->getValueTypes(); + + foreach ($keyTypes as $i => $keyType) { + if (PDO::FETCH_NUM === $fetchType && $keyType instanceof ConstantIntegerType) { + $builder->setOffsetValueType($keyType, $valueTypes[$i]); + } elseif (PDO::FETCH_ASSOC === $fetchType && $keyType instanceof ConstantStringType) { + $builder->setOffsetValueType($keyType, $valueTypes[$i]); + } + } + + return $builder->getArray(); + } + + return $resultType; + } } From 4dd7fa9aafb83244698f7396e8545e6974a1c9fd Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 6 Feb 2022 20:43:52 +0100 Subject: [PATCH 2/2] fix --- src/PdoReflection/PdoStatementReflection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PdoReflection/PdoStatementReflection.php b/src/PdoReflection/PdoStatementReflection.php index 30ea9d43b..93e940780 100644 --- a/src/PdoReflection/PdoStatementReflection.php +++ b/src/PdoReflection/PdoStatementReflection.php @@ -36,7 +36,8 @@ public function findPrepareQueryStringExpression(MethodReflection $methodReflect } /** - * @param PDO::FETCH* $fetchType + * // the following param doesnt work, see phpstan bug https://github.com/phpstan/phpstan/issues/6577 + * @xx-param PDO::FETCH* $fetchType * @return Type|null */ public function getStatementResultType(Type $statementType, int $fetchType) {