Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

struggle-for-php/sfp-psalm-typed-local-variable-plugin

Repository files navigation

sfp-psalm-typed-local-variable-plugin

finding mismatch type assignment in function/method scope with psalm.

Packagist Mutation testing badge Psalm coverage

Installation

$ composer require --dev struggle-for-php/sfp-psalm-typed-local-variable-plugin
$ vendor/bin/psalm-plugin enable struggle-for-php/sfp-psalm-typed-local-variable-plugin

latest version supports psalm ^4.

Demo

<?php
class Entity{}
interface Repository
{
 public function findOneById(int $id): ?Entity;
}
interface Mock{}
/** @return \DateTimeInterface&Mock */
function date_mock() {
 return new class('now') extends \DateTime implements Mock{};
}
class Demo
{
 /** @var Repository */
 private $repository;
 function typed_by_phpdoc() : void
 {
 /** @var string|null $nullable_string */
 $nullable_string = null;
 $nullable_string = "a";
 $nullable_string = true; // ERROR
 }
 function typed_by_assignement() : void
 {
 $date = new \DateTimeImmutable('now');
 if (\rand() % 2 === 0) {
 $date = new \DateTime('tomorrow'); // ERROR
 }
 $bool = true; //direct typed without doc-block
 $bool = false; // ok (currently, this plugin treats true|false as bool)
 $bool = 1; // ERROR
 }
 function mismatch_by_return() : void
 {
 /** @var Entity $entity */
 $entity = $this->repository->findOneById(1); // ERROR
 }
 function works_with_intersection() : void
 {
 /** @var \DateTimeInterface&Mock $date */
 $date = new \DateTime('now'); // ERROR
 $date = date_mock(); // success
 }
}
$ ./vendor/bin/psalm -c demo.psalm.xml
Scanning files...
Analyzing files...
E
ERROR: InvalidScalarTypedLocalVariableIssue - demo/demo.php:23:28 - Type true should be a subtype of null|string
 $nullable_string = true; // ERROR
ERROR: InvalidTypedLocalVariableIssue - demo/demo.php:30:21 - Type DateTime should be a subtype of DateTimeImmutable
 $date = new \DateTime('tomorrow'); // ERROR
ERROR: InvalidScalarTypedLocalVariableIssue - demo/demo.php:35:17 - Type 1 should be a subtype of bool
 $bool = 1; // ERROR
ERROR: InvalidTypedLocalVariableIssue - demo/demo.php:41:19 - Type Entity|null should be a subtype of Entity
 $entity = $this->repository->findOneById(1); // ERROR
ERROR: InvalidTypedLocalVariableIssue - demo/demo.php:47:17 - Type DateTime should be a subtype of DateTimeInterface&Mock
 $date = new \DateTime('now'); // ERROR
------------------------------
5 errors found
------------------------------

Plugin Issues

All issue names has TypedLocalVariableIssue suffix.

eg.

function foo(array $a) : void {
 /** @var string[] $x */
 $x = $a;
}

eg.

class A {}
class B extends A {}
function takesA(A $a) : void {
 /** @var B $b */
 $b = $a;
}

If you want suppress specific issue, please setting psalm.xml like below.

<issueHandlers>
 <PluginIssue name="MixedTypeCoercionTypedLocalVariableIssue">
 <errorLevel type="suppress">
 <file name="src/Foo.php"/>
 </errorLevel>
 </PluginIssue>
</issueHandlers>

Disclaimer

This is Experimental plugin.

Limitation

  • NOT support global variables.
  • NOT support variables in namespace.
  • NOT support Variable variables
  • Non-each inline VariableReference.
    • eg.
/** @var string $var1 */
/** @var bool $var2 */
$var1 = 'string'; // cannot determine type for $var1
// should fix like below
/** @var string $var1 */
$var1 = 'string';
/** @var bool $var2 */
$var2 = true;

Todo

  • optional setting for only from_docblock typed.

About

finding mismatch type assignment in function/method scope with psalm.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

Languages

AltStyle によって変換されたページ (->オリジナル) /