Skip to content

Commit

Permalink
Handle return-type of HeaderCollection->get()
Browse files Browse the repository at this point in the history
  • Loading branch information
EtienneBruines committed Sep 10, 2019
1 parent ab51e6b commit 76aa3bb
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
3 changes: 3 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ services:
-
class: Proget\PHPStan\Yii2\Type\ActiveRecordDynamicMethodReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
-
class: Proget\PHPStan\Yii2\Type\HeaderCollectionDynamicMethodReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
-
class: Proget\PHPStan\Yii2\Type\ActiveRecordDynamicStaticMethodReturnTypeExtension
tags: [phpstan.broker.dynamicStaticMethodReturnTypeExtension]
Expand Down
55 changes: 55 additions & 0 deletions src/Type/HeaderCollectionDynamicMethodReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Proget\PHPStan\Yii2\Type;

use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\IntegerType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use yii\web\HeaderCollection;

class HeaderCollectionDynamicMethodReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
public function getClass(): string
{
return HeaderCollection::class;
}

public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'get';
}

public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
{
if (count($methodCall->args) < 3) {
// $first === true (the default) and the get-method returns something of type string
return new StringType();
}

$val = $methodCall->args[2]->value;
if ($val instanceof ConstFetch) {
$value = $val->name->parts[0];
if ($value === 'true') {
// $first === true, therefore string
return new StringType();
}

if ($value === 'false') {
// $first === false, therefore string[]
return new ArrayType(new IntegerType(), new StringType());
}
}

// Unable to figure out value of third parameter $first, therefore it can be of either type
return new UnionType([new ArrayType(new IntegerType(), new StringType()), new StringType()]);
}
}
5 changes: 5 additions & 0 deletions tests/Yii/MyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,10 @@ public function actionMy(): void
\Yii::createObject(static function (): \SplObjectStorage {
return new \SplObjectStorage();
})->count();

(int)\Yii::$app->request->headers->get('Content-Length');
(int)\Yii::$app->request->headers->get('Content-Length', 0, true);
$values = \Yii::$app->request->headers->get('X-Key', '', false);
reset($values);
}
}

0 comments on commit 76aa3bb

Please sign in to comment.