schlndh/maria-stan

MariaDB查询的静态分析器

安装次数: 4,098

依赖: 0

建议: 0

安全性: 0

星标: 10

关注者: 1

分支: 1

开放性问题: 0

类型:phpstan-extension

dev-master 2024-09-27 13:05 UTC

This package is auto-updated.

Last update: 2024-09-27 13:07:16 UTC


README

MariaStan是MariaDB查询的静态分析工具。其主要目的是作为PHPStan扩展的基础。

当前状态 (24. 04. 2024):

MariaStan尚未完成。它覆盖了我使用的大型代码库中的大约90%用例(数百张表,数千个查询)。因此,活动不多。但是,它正在积极维护,即如果它对我造成问题,它可能会得到修复。

如果您尝试在自己的项目中使用它,您可能会遇到未实现的用例(例如,我的项目中不使用的语法/函数)。如果发生这种情况,您应该准备好自己解决问题(大多数事情应该都很简单)。

对于任何内容,都没有向后兼容性的承诺,也没有发布 - 我只是使用master。

MariaStan已在MariaDB 10.11和PHP 8.1-8.3上进行了测试。

安装

使用composer require --dev schlndh/maria-stan:dev-master安装MariaStan。然后您需要在您的phpstan.neon中添加以下内容

includes:
    - ./vendor/schlndh/maria-stan/extension.neon

配置

MariaStan需要访问数据库模式。最简单的方法是让它直接连接到数据库。您需要在您的phpstan.neon中添加以下配置并设置正确的凭证

parameters: 
    maria-stan:
        db:
            # Change these to match your database
            host: 127.0.0.1
            port: 3306
            user: 'root'
            password: ''
            database: 'db'

MariaStan需要访问数据库以获取查询分析的模式。它只读取表模式,不写入任何内容。尽管如此,不要给它访问包含任何重要数据的任何数据库的权限。

或者,在分析期间也可以不访问数据库使用MariaStan。在这种情况下,您需要首先使用MariaDbFileDbReflection::dumpSchema导出模式并将其保存到文件中。以下是一个示例脚本,它执行此操作

<?php

declare(strict_types=1);

use MariaStan\DbReflection\MariaDbFileDbReflection;

require_once __DIR__ . '/vendor/autoload.php';

$mysqli = new mysqli('127.0.0.1', 'root', '');
file_put_contents(__DIR__ . '/maria-stan-schema.dump', MariaDbFileDbReflection::dumpSchema($mysqli, 'database'));

然后,将以下内容添加到您的phpstan.neon

parameters:
    maria-stan:
        reflection:
            file: %rootDir%/../../../maria-stan-schema.dump
services:
    mariaDbReflection: @mariaDbFileDbReflection

请注意,相对路径的自动扩展仅在PHPStan自己的配置中工作(即它是硬编码的配置键列表)。因此,您必须提供到导出文件的绝对路径。

有关参数的完整列表,请参阅extension.neon

用法

MariaStan包括一个用于MySQLi的示例PHPStan扩展。然而,此扩展的目的是简单地验证与PHPStan的集成。我不期望任何人实际直接使用MySQLi。因此,您应该编写自己的PHPStan扩展,并将其与MariaStan集成。如果想要使用MySQLi扩展,请在phpstan.neon中包含./vendor/schlndh/maria-stan/extension.mysqli.neon

您可以将MySQLi扩展作为起点进行修改,以适应您的需求。基本思想是从PHPStan获取查询字符串,将其传递给MariaStan进行分析,然后将结果类型和错误报告回PHPStan。

在您开始实现将 MariaStan 集成到项目中的自定义扩展之前,您可以快速尝试它。您可以从检查一个简单的示例开始,该示例使用 MySQLi 扩展。然后您可以通过 MySQLi 从您的代码库中调用查询,并使用 MySQLi 扩展来分析它们,以确保 MariaStan 支持您的项目使用的功能。

功能

以下是一个功能列表,您可以根据 MariaStan 实现 PHPStan 扩展(其中大部分应在 MySQLi 扩展中演示):

  • 查询结果的类型推断。当使用 PHPStan 与处理数据库数据的代码一起使用时,这一点非常有价值。
    • 有时 MariaStan 可以推断比数据库返回的类型更窄的类型(例如 mysqli_result::fetch_fields)。这是因为 MariaStan 可以(在简单情况下)理解像 SELECT col FROM tbl WHERE col IS NOT NULL 这样的查询,并从结果类型中删除 NULL,而 MariaDB 似乎不会这样做。
  • 基本的错误检测。例如
    • 未知表、列...
    • 模糊的列名,
    • 占位符数量不匹配,
    • INSERT/REPLACE 中缺少必需列的数据
    • ...
  • 报告已弃用表/列的使用。
  • 行数范围:在简单情况下,MariaStan 可以确定返回的行数(例如 SELECT COUNT(*) FROM tbl),这可以用来缩小像 mysqli_result::fetch_all(即 non-empty-array)这样的方法的返回类型。
  • 列类型覆盖:您可以为列覆盖类型(例如,因为表是“静态的”),甚至可以通过外键自动传播它。
  • 自定义 PHPDoc 类型:例如 MySQLiTableAssocRowType

限制

  • 目前尚未实现 PHPStan 的缓存失效。不清楚这样的事情是否容易实现。请参阅 此讨论。然而,这仅与模式更改(即如果您在 PHP 文件中更改查询,PHPStan 将自动使其无效)有关。
  • 不支持查询构建器。分析器期望输入为字符串的查询。
  • 查询必须完全在静态中已知。如果您有如下代码
    function foo(mysqli $db, int $count) {
        return $db->prepare("SELECT * FROM tbl WHERE id IN (" . implode(',', array_fill(0, $count, '?')) . ')');
    }
    PHPStan 将无法进行静态评估,因此 MariaStan 没有可分析的内容。
  • 不支持临时表。
  • 不支持多数据库。
  • 上述限制是长期的主要限制。但除此之外,其他功能只是部分实现。

类似项目

staabm/phpstan-dba

据我所知,phpstan-dba 通过执行查询来获取有关结果类型、错误等信息。另一方面,MariaStan 分析查询是静态的。phpstan-dba 的好处包括

  • 轻松支持多数据库。使用 MariaStan 这是不可能的(可能除 MySQL 之外)。
  • 由于数据库执行繁重的工作,因此具有更完整和可靠的错误检查。另一方面,数据库一次只返回一个错误,而 MariaStan 可能一次能够发现多个问题。
  • 查询计划分析。这在静态中似乎不可行。另一方面,我不确定这在实践中有多有用,尤其是如果您不想让 phpstan-dba 访问生产数据。
  • 它似乎更容易入门,因为它有多个数据库抽象的扩展。

phpstan-dba 的方法有一些小缺点

  • 没有通往完全静态分析的道路(即在任何时刻都不需要运行的数据库)。目前,MariaStan 也需要一个运行的数据库(从 information_schema 获取数据,不一定在分析时间)。但可以实现 CREATE TABLE(等)解析,并在其上实现数据库反射。
  • 由于查询被执行,因此在数据/模式修改查询上必须小心。我在几个地方看到一些条件,将其限制为SELECT查询,以及事务的使用。因此,我不确定它对INSERT等操作的支持程度如何。(至少在测试中有一些)。