标签: phpstan

PHPStan 和 Doctrine:$id 永远不会被写入,只能读取

我将 PHP8、symfony5 和doctrine2 与 phpstan 一起使用并收到以下错误:

Property App\Entity\User::$id is never written, only read.  
Run Code Online (Sandbox Code Playgroud)

代码:

<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Table(name="`user`")
 * @ORM\Entity(repositoryClass=UserRepository::class)
 * @UniqueEntity(fields={"email"}, message="There is already an account with this email")
 */
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    public const ROLE_USER = 'ROLE_USER';
    public const ROLE_ADMIN = 'ROLE_ADMIN';

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true) …
Run Code Online (Sandbox Code Playgroud)

php doctrine phpstan

9
推荐指数
2
解决办法
8425
查看次数

PHPStan 中未定义变量,但已在其他地方声明

PHPStan 中如何处理这些场景:

  1. 假设您使用纯 PHP 作为模板引擎。例如,
// view.php

<b><?=$foo?></b>
Run Code Online (Sandbox Code Playgroud)

  1. 假设你有 2 个文件a.php并且b.php
// a.php     
$foo = 'bar';

// b.php     
require 'a.php';     
echo $foo;
Run Code Online (Sandbox Code Playgroud)

PHPStan 都会将此报告为Undefined variable: $foo

你如何处理这个问题?PHPStan 是否可以配置为以某种方式执行您的应用程序,以便它知道这些变量实际上是在运行时定义的?

php analysis phpstan

7
推荐指数
1
解决办法
4915
查看次数

PHPStan:具有泛型类的属性未指定其类型:TKey、T

我在一个Symfony项目上运行PHPStan,其中我在Doctrine实体中有以下关系:

/**
 * @ORM\OneToMany(targetEntity="App\Entity\Course\Slide", mappedBy="chapter", cascade={"persist"}, orphanRemoval=true)
 * @ORM\OrderBy({"listOrder" = "ASC"})
 *
 * @var ArrayCollection<Slide>
 */
private $slides;
Run Code Online (Sandbox Code Playgroud)

使用规则级别 6运行分析我收到以下有关该属性(及其 getter 返回类型)的消息:

App\Entity\Course\Chapter::$slides具有泛型类的属性Doctrine\Common\Collections\ArrayCollection未指定其类型:TKey, T
您可以通过checkGenericClassInNonGenericObjectType: false在您的phpstan.neon.

我的编辑尝试只会混淆 PHPStan,可能是因为我没有完全理解这里的泛型。但是仅仅因为我不明白而将消息静音将是愚蠢的。

我应该在 PHPDoc 中添加或更改什么?

generics doctrine static-analysis phpdoc phpstan

7
推荐指数
2
解决办法
3719
查看次数

我怎样才能让 phpstan 找到我的自定义扩展类?

为了实现对某些魔术_get()函数的检查,我正在尝试实现“类反射扩展”。该手册提到了如何编写扩展文件本身,以及如何通过service向 neon 文件添加一部分来安装它们。

我写了一个扩展,并像这样添加它:

services:
    -
        class: TestClass
        tags:
            - phpstan.broker.methodsClassReflectionExtension
Run Code Online (Sandbox Code Playgroud)

这会导致以下错误:

服务“0226”:未找到类 TestClass。

我尝试过的事情:

  • 使用独立的 phar
  • 使用 phpstan 的 Composer 安装
  • 使用特定的命名空间 (PHPStan) 作为扩展(在文件和 neon 中)
  • 使用“随机”命名空间(在文件和霓虹灯中)
  • 将文件添加到我知道正在扫描以进行分析的目录
  • 将带有扩展名的目录添加到“scanDirectories”参数中
  • 将文件添加到“scanFiles”参数
  • 将扩展名添加到“paths”参数中的目录
  • 添加(已弃用的)自动加载指令并在其中添加文件。

如果找不到文件,这些“添加”尝试中的一些实际上会发出警告:例如,如果我故意在其中之一中犯了一个拼写错误,比如说自动加载错误,它会警告我丢失文件。但前提是我没有定义service

如果我定义了服务并在那里故意输入错误,它会返回上面的类未找到(而不是输入错误),所以我觉得它在任何参数之前检查扩展?

似乎需要将我的文件添加到不同的自动加载机制中。问题是,哪个以及如何?

我在用着

  • phpstan 0.12.40
  • php 7.2.33

php static-analysis phpstan

5
推荐指数
1
解决办法
1630
查看次数

PHP 7.4+ 类属性类型

我确信这个问题已经被问过很多次了,但我似乎找不到一个好的/令人满意的答案,所以请直接告诉我。

使用 PHP 7.4+,我倾向于输入我能输入的所有内容。但我对学说实体属性有一些问题。

如果我正确输入所有内容,我通常会遇到很多像这样的错误。

初始化之前不得访问类型化属性 App\Entity\User::$createdAt

该类型错误的代码示例如下所示

/**
 * @var DateTimeInterface
 * @ORM\Column(type="datetime")
 */
protected DateTimeInterface $createdAt;
Run Code Online (Sandbox Code Playgroud)

因此,我曾经使属性可以为空,即使数据库字段不是。所以它看起来像这样。

/**
 * @var DateTimeInterface|null
 * @ORM\Column(type="datetime")
 */
protected ?DateTimeInterface $createdAt = null;
Run Code Online (Sandbox Code Playgroud)

但是,现在我有另一个问题。我决定在我的项目中实现静态代码分析器,现在我使用 PHPStan。所以现在,当我扫描代码时,我会收到类似的错误。


src/Entity/Trait/TimestampableEntityPropertiesTrait.php 行(在 App\Entity\Article 类的上下文中)


16 属性 App\Entity\Article::$createdAt 类型映射不匹配:属性可以包含 DateTimeInterface|null 但数据库需要 DateTimeInterface。


那么,处理这种情况的正确方法是什么?

任何建议将不胜感激。

编辑

我应该提到,有时,我不想/无法初始化构造函数中的属性,因为我还没有正确的值。

php phpstan

5
推荐指数
1
解决办法
1833
查看次数

在 PHP 中通过 PhpStan 使用 Enum 作为字符串

我正在 Symfony 6 应用程序中试验 PHP 枚举,我认为我找到了一个非常好的用例。一切正常,但 phpstan 一直抱怨我返回的类型。

 ------ -----------------------------------------------------------------------------------------------------------------------------------------------
  Line   src/Entity/User.php
 ------ -----------------------------------------------------------------------------------------------------------------------------------------------
  93     Return type (array<App\Security\Roles>) of method App\Entity\User::getRoles() should be compatible with return type (array<string>) of method
         Symfony\Component\Security\Core\User\UserInterface::getRoles()
 ------ -----------------------------------------------------------------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

我的枚举看起来像这样:

namespace App\Security;

enum Roles: string
{
    case Admin = 'ROLE_ADMIN';
    case User = 'ROLE_USER';
}
Run Code Online (Sandbox Code Playgroud)

在我User实现的实体中Symfony\Component\Security\Core\User\UserInterface,我有这个:

/**
 * @see UserInterface
 * @return array<Roles>
 */
public function getRoles(): array
{
    $roles = $this->roles;
    // guarantee every user at least has ROLE_USER
    $roles[] = …
Run Code Online (Sandbox Code Playgroud)

php enums static-analysis symfony phpstan

5
推荐指数
1
解决办法
2840
查看次数

如何避免方法返回值的数组形状声明重复?

例如,如果我有一个这样的课程:

class Foo
{
   /**
    * @var array<string, array{name: string, age: int}>
    */
   private array $things;

   /**
    * @return array
    */
   public function getThings(): array
   {
      return $this->things;
   }
}
Run Code Online (Sandbox Code Playgroud)

然后 phpstan 会给我一些类似于Method Foo::getThings() return type has no value type specified in iterable type array.

当然,我可以通过将数组形状定义添加到 来解决这个问题@return,但考虑到我已经在属性上定义了这个,有没有办法避免我在这里缺少的重复?

php phpstan

5
推荐指数
1
解决办法
1135
查看次数

PHPStan 转换为更具体的数组形状

在我的代码中,我调用一个方法,其返回值的类型如下:

/**
 * @return array<int, array<string,mixed>>
 */
public function fetchAllAssociative(): array;
Run Code Online (Sandbox Code Playgroud)

子类型array<string, mixed>以通用方式描述数据库记录。我确切地知道这个数据库记录是什么样的,所以我想更具体地记录该方法:

/**
 * @return array<int, array{id: int, firstName: string, lastName: string}>
 */
public function getAllUsers(): array
{
  return $this->userRepository->fetchAllAssociative();
}
Run Code Online (Sandbox Code Playgroud)

然而,PHPStan 抱怨说我应该完全按照以下方式键入我的方法fetchAllAssociative

Method UserRepository::getAllUsers() should return array<int, array{id: int, firstName: string, lastName: string}> but returns array<int, array<string, mixed>>.

有办法投吗?我的解决方法是引入一个新变量并使用@var标签,但我不太喜欢它(其他静态代码分析工具也不喜欢它)

/**
 * @return array<int, array{id: int, firstName: string, lastName: string}>
 */
public function getAllUsers(): array
{
  /**
   * @var array<int, array{id: int, firstName: …
Run Code Online (Sandbox Code Playgroud)

phpstan array-shape

5
推荐指数
1
解决办法
623
查看次数

修复 phpstan(或 larastan)的 Laravel 范围警告?

使用 phpstan/larastan 分析代码时如何处理 Laravel 中的范围?

我收到此错误:

Call to an undefined method Illuminate\Database\Eloquent\Builder::active().
Run Code Online (Sandbox Code Playgroud)

我需要以某种方式输入提示吗?

我试图避免@phpstan-ignore-next-line

值得一提的是,仅当我在作用域内使用作用域时才会出现上述错误。在其他情况下,成功LaraStan阻止PhpStan警告。

laravel phpstan

5
推荐指数
1
解决办法
1951
查看次数

升级到 Laravel 10 后,Larastan 抱怨收集方法参数

升级到 Laravel 10 后,我遇到了 Larastan 错误的困难时期。

下面的代码在 1 小时前还完全正常:

return $this->articleRepository->getDefaultArticles($organizationId)
    ->toBase()
    ->map(function (Article $article) {
        return new Content(
            $article->id,
            $article->title,
            $article->language,
        );
    })
    ->toArray();
Run Code Online (Sandbox Code Playgroud)

现在给我以下错误:

方法 Illuminate\Support\Collection<(int|string),Illuminate\Database\Eloquent\Model>::map() 的参数 #1 $callback 需要 callable(Illuminate\Database\Eloquent\Model, int|string): App\学院\内容,
关闭(应用程序\模型\文章):给出的应用程序\学院\内容

存储库方法有正确的提示:

/**
 * @return Collection<Article>
 */
public function getDefaultArticles(OrganizationId $organizationId): Collection
{
    /** @var Collection<Article> */
    return Article::query()
        ->where('organization_id', $organizationId)
        ->get()
        ->keyBy('id')
        ->values();
}
Run Code Online (Sandbox Code Playgroud)

它给了我 115 个新错误,其中大多数与此类似,与map和等收集方法相关reduce

快速解决方案是使用临时变量并添加类型提示:

/** @var Collection<Article> $articles */
$articles = $this->articleRepository
    ->getDefaultArticles($organizationId)
    ->toBase();
Run Code Online (Sandbox Code Playgroud)

但我不想执行 100 …

php laravel phpstan laravel-10

5
推荐指数
1
解决办法
1246
查看次数