vkcom/modulite-phpstan

一个为纯PHP(非KPHP)项目提供Modulite支持的PHPStan插件

安装次数: 21,414

依赖者: 2

建议者: 0

安全: 0

星星: 13

关注者: 10

分支: 3

开放性问题: 7

类型:phpstan-extension

v1.0.2 2023-09-27 16:41 UTC

README

Modulite是一种将模块引入PHP语言的概念。PHP没有原生模块(内部类、私有命名空间、显式导出),而Modulite试图消除这一缺点。

实际上,所有的“模块化”都表示为.modulite.yaml文件,该文件声明了导出和需求。有一个PHPStorm插件可以深度集成到IDE中,可视化yaml配置并提供修改它的操作。

此PHPStan插件读取.modulite.yaml文件,如果您的代码破坏了模块化,则会引发错误。这允许您在Git钩子、CI等中对整个项目进行检查。

提示。如果您不熟悉Modulite,请考虑一个PHPStorm插件和一个着陆页(俄语)

安装和配置

要安装,只需使用Composer

composer require --dev vkcom/modulite-phpstan

安装后,将插件包含在您的phpstan.neon中,并传递两个参数

parameters:
    modulite:
        projectRoot: path    # project root is where composer.json/composer.lock/vendor exist
        srcRoot: path        # typically, projectRoot/src ; .modulite.yaml files will be searched recursively

includes:
    - vendor/vkcom/modulite-phpstan/extension.neon

示例项目

克隆 modulite-example-project,运行composer install,运行vendor/bin/phpstan analyze,并查看一些错误。

示例项目故意包含一些错误 :) 它还描述了将代码变为完美的几个步骤。

screen-err-phpstan

您也可以在开发Composer包时使用Modulite。此外,您还可以控制哪些符号从您的包中导出。这种能力在文档中有涵盖。

插件的工作原理

正如预期的那样,modulite-phpstan分析函数调用、类使用、PHPDocs等,并确保您的代码符合exportrequire和其他Modulite规则。

我们建议您在开发时使用PHPStorm,因为PHPStorm的插件可以顺畅地集成到IDE中,生成.modulite.yaml文件,这些文件由modulite-phpstan分析。

通常,项目结构如下

my_project/     # projectRoot
    src/        # srcRoot
    tests/
    vendor/
    composer.json

当PHPStan开始分析您的代码时,此插件

  • {srcRoot}内部查找所有.modulite.yaml
  • {projectRoot}/vendor内部查找所有.modulite.yamlcomposer.json文件

插件必须扫描vendor,因为Composer包也需要进行检查等。此外,包也可以使用Modulite开发并包含私有符号,因此当嵌入到您的项目中时,插件也会检查它们的使用。

Modulite文件在PHPStan运行时解析、解析和验证一次。如果没有错误,将执行所有模块化检查。否则,yaml错误将被输出,不会执行任何检查。

vendor目录外的Composer包

在罕见情况下,您可能在同一存储库中本地开发Composer包。由于安装到vendor,它们只是符号链接

my_project/     # projectRoot
    src/        # srcRoot
    packages/   # additionalPackagesRoot
        utils-common/
            src/
            composer.json
    tests/
    vendor/
        doctrine/
        phpstan/
        utils/
            common/   (symlink to packages/utils-common)
    composer.json     (contains "repositories" type "path" into packages/*)

在这种情况下,PHPStan的内部反射发现了一些位于packages/中的类,从Modulite的角度来看,它们应该在vendor/中。如果没有额外的提示,Modulite将产生错误,认为vendor/使用了范围之外的文件。

为了解决这个问题,除了srcRoot外,还传递additionalPackagesRoot参数。然后modulite-phpstan也将扫描该目录并创建必要的路径映射。

关于PHPStan缓存的遗憾之处

如果PHP文件未更改,PHPStan不会在其中执行分析。它缓存文件状态和错误,并直接输出它们,它只分析差异和更改的依赖关系。

如上所示,

  • 当PHP代码未更改,但通过PHPStorm插件更改了.modulite.yaml文件时,不会运行检查
  • 当部分PHP代码更改且.modulite.yaml文件也更改时,PHPStan将仅对更改的文件运行检查,并将之前(缓存的)错误输出给未更改的文件,尽管未更改的文件在yaml修改后可能不包含错误

目前,一个100%有效的方法是定期清除缓存

vendor/bin/phpstan clear-result-cache

这将使PHPStan分析整个项目,插件将按预期工作。

可能,可以通过对PHPStan缓存内部结构的深入了解来修复此问题,了解如何将其嵌入以及如何告知PHPStan关于PHP<->yaml互连。如果您熟悉编写插件,请在此问题中提出建议。

限制

  • 如果您遇到意外行为,请尝试清除PHPStan缓存(如上所述的部分)。
  • 每次运行都会递归扫描vendor/目录,这可能会花费明显的时间;这可以改进,请为此问题投票。
  • projectRootsrcRoot参数是必需的,但可能它们可以自动计算;如果您熟悉编写插件,请在此问题中添加注释。
  • 仅分析静态方法调用,$obj->method()不被分析,这就是为什么实例方法不能添加到force-internal。这是故意的,因为静态调用可以明确解析,而实例调用依赖于类型推断,这肯定会在IDE和PHPStan之间有所不同;实际上,静态调用和类使用已经足够了。

贡献说明

请注意,Modulite行为的所有逻辑必须在3个地方相同

  • PHPStorm中的Modulite;检查以IDEA检查的形式表示,符号解析也依赖于PHPStorm内部。
  • PHPStan中的Modulite(此存储库)。
  • KPHP中的Modulite;KPHP是VK发明的一种PHP编译器;此外,模块的初始实现是为KPHP+PHPStorm组合制作的,后来相同的逻辑被公开为PHPStan插件,用于常规PHP项目;与yaml验证和规则检查相关的大量代码是从C++实现移植的,并且必须与KPHP保持同步,以保持可持续性。

如果您发现了一个错误,它可能是一个与PHPStan特性相关的特定错误,或者它可能是一个也存在于其他实现中的错误,应该同时修复。如果您有一个功能请求,它必须在三个存储库中同时实现,并使用相同的测试进行覆盖。因此,请随时提交问题,我们将找到管理它们的方法。

如果您熟悉PHPStan内部,并且有建议使此插件更符合标准,我们将很高兴看到您的评论和PR。

提问并提供反馈

此插件由VK.com的KPHP团队开发。

要与我们社区沟通,请使用GitHub问题或Telegram聊天