rector/type-perfect

高级类型声明检查

安装: 343 271

依赖者: 54

建议者: 0

安全: 0

星标: 74

关注者: 4

分支: 4

开放问题: 2

类型:phpstan-extension

0.2.0 2024-09-08 14:41 UTC

This package is auto-updated.

Last update: 2024-09-18 18:17:24 UTC


README

Downloads

高级类型声明检查 PHPStan 规则。

我们使用这些规则来提升客户代码的质量,超越 PHPStan 的功能。

  • 这些规则使跳过的对象类型明确,参数类型更窄,并帮助您填写更准确的对象类型提示。
  • 即使您的代码未通过第 0 级,这些规则也易于启用
  • 它们易于解决,并使您的代码立即更加稳固和可靠。

如果您关心代码质量和类型安全,请将这 10 条规则添加到您的 CI 中。


安装

composer require rector/type-perfect --dev

注意:请确保您使用 phpstan/extension-installer 来加载必要的服务配置或包含 vendor/rector/type-perfect/config/extension.neon 文件。


默认启用 2 个检查。第一个确保我们不会错过使用 instanceof 来让后续代码知道确切对象类型的机会

private ?SomeType $someType = null;

if (! empty($this->someType)) {
    // ...
}

if (! isset($this->someType)) {
    // ...
}

// here we only know, that $this->someType is not empty/null

🙅

if (! $this->someType instanceof SomeType) {
    return;
}

// here we know $this->someType is exactly SomeType

✔️


第二个规则检查我们是否使用显式的对象方法而不是魔法数组访问

$article = new Article();

$id = $article['id'];
// we have no idea, what the type is

🙅

$id = $article->getId();
// we know the type is int

✔️


配置

您可以通过配置启用以下规则。我们按照从简单到强大的顺序,以及我们在旧项目上应用它们的顺序,来选择它们。

您可以选择全部启用

parameters:
    type_perfect:
        no_mixed_property: true
        no_mixed_caller: true
        null_over_false: true
        narrow_param: true
        narrow_return: true

或者一个一个地启用


1. Null over False

parameters:
    type_perfect:
        null_over_false: true

布尔类型通常用于开/关、是/否响应。但有时,false 被误用为 无结果 响应,其中 null 会更准确

public function getProduct()
{
    if (...) {
        return $product;
    }

    return false;
}

🙅

我们应该使用 null,因为它自 PHP 7.1 起启用了严格的类型声明

public function getProduct(): ?Product
{
    if (...) {
        return $product;
    }

    return null;
}

✔️


2. No mixed Property

parameters:
    type_perfect:
        no_mixed_property: true

此规则关注 PHPStan 在获取属性时的盲点。如果我们有一个未知类型的属性,PHPStan 就无法分析它。它会静默地忽略它。

private $someType;

public function run()
{
    $this->someType->vale;
}

它看不到 vale 属性名中的拼写错误。它应该是 value

🙅

private SomeType $someType;

public function run()
{
    $this->someType->value;
}

此规则确保所有属性获取都知道它们调用的类型。

✔️


3. No mixed Caller

parameters:
    type_perfect:
        no_mixed_caller: true

与上面相同,但针对方法调用

private $someType;

public function run()
{
    $this->someType->someMetho(1, 2);
}

它看不到 someMetho 名称中的拼写错误,以及第二个参数必须是 string

🙅

private SomeType $someType;

public function run()
{
    $this->someType->someMethod(1, 'active');
}

此组确保方法调用知道它们调用的类型。

✔️


4. Narrow Param Types

我们拥有的参数类型越窄,代码就越可靠。stringmixed 更好,intscalar 更好,ExactObjectstdClass 更好。

parameters:
    type_perfect:
        narrow_param: true

在私有方法调用和公共方法调用的情况下,我们的项目通常知道传递给它确切的数据类型

// in one file
$product->addPrice(100.52);

// another file
$product->addPrice(52.05);

但出于恐惧和“为了安全起见”,我们保持 addPrice() 参数类型为空、mixed 或文档块。

🙅

如果在 100% 的情况下传递 float 类型,PHPStan 就知道它可以添加,并进一步改进分析

-/**
- * @param float $price
- */
-public function addPrice($price)
+public function addPrice(float $price)
{
    $this->price = $price;
}

这就是此组的作用所在。它检查所有传递的类型,并告诉我们如何缩小参数类型声明。

✔️


5. Narrow Return Types

最后但同样重要的是,返回类型越窄,代码就越可靠。

parameters:
    type_perfect:
        narrow_return: true

它在哪里有帮助?假设我们有两种类型的谈话,它们具有不同的行为

final class ConferenceTalk extends Talk
{
    public function bookHotel()
    {
        // ...
    }
}

final class MeetupTalk extends Talk
{
    public function bookTrain()
    {
        // ...
    }
}

然后我们有一个工厂(仓库或服务)返回通用的 Talk 类型

final class TalkFactory
{
    public function createConferenceTalk(): Talk
    {
        return new ConferenceTalk();
    }

    public function createMeetupTalk(): Talk
    {
        return new MeetupTalk();
    }
}

在这种情况下,我们失去了严格的类型,必须在运行时验证类型

$talk instanceof ConferenceTalk

🙅

这就是这个小组发挥作用的地方。如果我们返回确切的类型,我们应该在返回类型声明中使用确切的类型,以使代码尽可能可靠

 final class TalkFactory
 {
-    public function createConferenceTalk(): Talk
+    public function createConferenceTalk(): ConferenceTalk
     {
         return new ConferenceTalk();
     }

-    public function createMeetupTalk(): Talk
+    public function createMeetupTalk(): MeetupTalk
     {
         return new MeetupTalk();
     }
}

✔️

逐个添加集合,修复你觉得有用的,忽略其余部分。


编码愉快!