shipmonk/composer-dependency-analyser

快速检测composer依赖问题(死依赖、影子依赖、放置错误的依赖)

1.7.0 2024-08-08 08:12 UTC

README

  • 💪 强大:检测未使用、影子和不正确放置的composer依赖
  • 高性能:在2秒内扫描15,000个文件!
  • ⚙️ 可配置:通过PHP配置进行细粒度忽略
  • 🕸️ 轻量级:没有composer依赖
  • 🍰 易于使用:第一次尝试无需配置
  • 兼容:PHP 7.2 - 8.3

比较

*在约15,000个文件的代码库上测量的时间

安装

composer require --dev shipmonk/composer-dependency-analyser

请注意,此包本身没有composer依赖。

使用

vendor/bin/composer-dependency-analyser

示例输出

Found shadow dependencies!
(those are used, but not listed as dependency in composer.json)

  • nette/utils
    e.g. Nette\Utils\Strings in app/Controller/ProductController.php:24 (+ 6 more)

Found unused dependencies!
(those are listed in composer.json, but no usage was found in scanned paths)

  • nette/utils

(scanned 13970 files in 2.297 s)

检测到的问题

此工具读取您的composer.json并扫描autoload & autoload-dev部分中列出的所有路径

影子依赖

  • 这些是您的依赖项的依赖项,但未在composer.json中列出
  • 当您的直接依赖项更新到不再需要该影子依赖项的新版本时,您的代码可能会出现错误
  • 您应该在依赖项中列出所有这些包

未使用的依赖

  • 任何非开发依赖项都应在扫描路径中至少有单次使用
  • 为了避免误报,您可能需要调整扫描路径或通过--config忽略某些包

生产代码中的开发依赖项

  • 对于库,这很危险,因为您的用户可能没有安装这些依赖项
  • 对于应用程序,当您使用composer install --no-dev运行时,可能会破坏它
  • 您应该将这些从require-dev移动到require

仅在开发路径中使用的生产依赖项

  • 对于库,这种分类错误可能导致用户不必要地需要依赖项
  • 您应该将这些从require移动到require-dev

未知类

  • 任何无法自动加载的类都会被报告,因为我们无法确定它是否是影子依赖

未知函数

  • 任何在运行时使用但未定义的函数都会被报告,因为我们无法确定它是否是影子依赖

Cli选项

  • --composer-json path/to/composer.json用于自定义composer.json路径
  • --dump-usages symfony/console显示特定包的使用情况,*占位符受支持
  • --config path/to/config.php用于自定义配置文件路径
  • --version显示版本
  • --help显示使用方法和cli选项
  • --verbose以查看更多示例类和用法
  • --show-all-usages以查看所有用法
  • --format以使用不同的输出格式,可用的是:console(默认),junit
  • --ignore-unknown-classes以全局忽略未知类
  • --ignore-unknown-functions以全局忽略未知函数
  • --ignore-shadow-deps以全局忽略影子依赖
  • --ignore-unused-deps以全局忽略未使用的依赖
  • --ignore-dev-in-prod-deps以全局忽略生产代码中的开发依赖
  • --ignore-prod-only-in-dev-deps以全局忽略仅在开发路径中使用的生产依赖

配置

当名为 composer-dependency-analyser.php 的文件位于当前工作目录(cwd)中时,它会自动加载。该文件必须返回 ShipMonk\ComposerDependencyAnalyser\Config\Configuration 对象。您可以通过 --config 命令行选项使用自定义路径和文件名。以下是一个示例:

<?php

use ShipMonk\ComposerDependencyAnalyser\Config\Configuration;
use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType;

$config = new Configuration();

return $config
     //// Adjusting scanned paths
    ->addPathToScan(__DIR__ . '/build', isDev: false)
    ->addPathToExclude(__DIR__ . '/samples')
    ->disableComposerAutoloadPathScan() // disable automatic scan of autoload & autoload-dev paths from composer.json
    ->setFileExtensions(['php']) // applies only to directory scanning, not directly listed files

    //// Ignoring errors
    ->ignoreErrors([ErrorType::DEV_DEPENDENCY_IN_PROD])
    ->ignoreErrorsOnPath(__DIR__ . '/cache/DIC.php', [ErrorType::SHADOW_DEPENDENCY])
    ->ignoreErrorsOnPackage('symfony/polyfill-php73', [ErrorType::UNUSED_DEPENDENCY])
    ->ignoreErrorsOnPackageAndPath('symfony/console', __DIR__ . '/src/OptionalCommand.php', [ErrorType::SHADOW_DEPENDENCY])

    //// Ignoring unknown symbols
    ->ignoreUnknownClasses(['Memcached'])
    ->ignoreUnknownClassesRegex('~^DDTrace~')
    ->ignoreUnknownFunctions(['opcache_invalidate'])
    ->ignoreUnknownFunctionsRegex('~^opcache_~')

    //// Adjust analysis
    ->enableAnalysisOfUnusedDevDependencies() // dev packages are often used only in CI, so this is not enabled by default
    ->disableReportingUnmatchedIgnores() // do not report ignores that never matched any error

    //// Use symbols from yaml/xml/neon files
    // - designed for DIC config files (see below)
    // - beware that those are not validated and do not even trigger unknown class error
    ->addForceUsedSymbols($classesExtractedFromNeonJsonYamlXmlEtc)

所有路径都应存在。如果您需要一些全局功能,您可以在配置文件中执行它,并将展开的列表传递给例如 ignoreErrorsOnPaths

从非PHP文件检测类

一些类可能只在您的DIC配置文件中使用。这里有简单的方法来提取它们

$classNameRegex = '[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*'; // https://php.ac.cn/manual/en/language.oop5.basic.php
$dicFileContents = file_get_contents(__DIR__ . '/config/services.yaml');

preg_match_all(
    "~$classNameRegex(?:\\\\$classNameRegex)+~", // at least one backslash
    $dicFileContents,
    $matches
); // or parse the yaml properly

$config->addForceUsedSymbols($matches[1]); // possibly filter by class_exists || interface_exists

类似的方法可以帮助您避免在未使用的依赖项中产生误报。另一种仅针对DIC使用的做法是扫描生成的PHP文件,但这给我们带来了更差的结果。

扫描位于其他地方的代码库

  • 这可以通过将 --composer-json 指向其他代码库的 composer.json 来完成

禁用彩色输出

  • NO_COLOR 环境变量设置为禁用彩色输出
NO_COLOR=1 vendor/bin/composer-dependency-analyser

限制

  • 扩展依赖项不会进行分析(例如 ext-json

贡献

  • 通过 composer check 检查您的代码
  • 通过 composer fix:cs 自动修复编码风格
  • 所有功能必须经过测试

支持的PHP版本

  • 运行时需要PHP 7.2 - 8.4
  • 被扫描的代码库应使用PHP >= 5.3