给 PHP 包作者和用户的 Composer 技巧

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

Composer 可能是 PHP 生态系统中最重要的工具之一。它已成为 PHP 中包管理的 事实 标准。尽管如此,Composer 还是有一些隐藏的或不太明显的特性,以及许多开发人员都不知道的功能。无论您是包的作者和维护者,还是在自己的项目中使用某些包,在使用 Composer 时都应该熟悉并遵循一些标准和最佳实践。本文在这方面提供了一些有用的建议。

包作者

作为某个 PHP 库的开发人员,您倾向于提供给社区,以使其对其他开发人员有用。但是,这需要以负责任和适当的方式进行。这里有一些最常被忽视的事情,但所有作者都应该遵守。

标签发布

请标记你的包的发布!并且在标记时, 从语义上 进行。不要强迫其他开发人员依赖 dev-master,就 Composer 的稳定性标志而言,它是不稳定的,而且它可以随时更改。

您可以通过创建/推送 VCS 标签手动标记发布,或者如果您的项目托管在 GitHub 上,您可以在项目页面上 创建发布

自动加载

Composer 有自己的 自动加载机制 ,除了源代码的自动加载规范外,您还可以在测试命名空间中的类的情况下定义它(您为您的库编写单元测试,对吧?)。许多开发人员不关心并以这种方式在他们的 composer.json 中设置自动加载:


 {
    "autoload": {
        "psr-4": { 
            "MyLibrary\\": "src/",
            "MyLibrary\\Tests\\": "tests/"
        }
    }
}

但这很糟糕。当你的包被用作依赖项时,不要污染生产中的自动加载器。 Composer 还具有用于开发目的的 autoload-dev 属性,这是此示例的正确自动加载规范:


 {
    "autoload": {
        "psr-4": { 
            "MyLibrary\\": "src/",
            "MyLibrary\\Tests\\": "tests/"
        }
    }
}

或者,您可以通过指定 classmap 规则来优化库源的自动加载:


 {
    "autoload": {
        "psr-4": { 
            "MyLibrary\\": "src/",
            "MyLibrary\\Tests\\": "tests/"
        }
    }
}

分支别名

分支别名是可以放入 composer.json 的属性,目的是将非类似版本的分支名称(即 master、develop)映射到可比较的版本名称(即 1.0 2.1.0 )。这在有人需要最新的 dev-master 情况下很有用,如果其他包需要 1.0.* 可能会出现问题,这将导致冲突,因为 dev-master 1.0.* 约束不匹配。别名可以在 composer.json extra 部分下定义,例如:


 {
    "autoload": {
        "psr-4": { 
            "MyLibrary\\": "src/",
            "MyLibrary\\Tests\\": "tests/"
        }
    }
}

Composer 文档中有 一篇关于别名本身的很棒的文章

分支别名不是那么重要,因为包用户仍然可以通过要求 内联别名 来绕过这个障碍。

包用户

我们 PHP 开发人员享受拥有大量有用库的好处,这些库可以使用 Composer 轻松集成到我们的项目中。尽管如此,还是应该注意一些重要的细节。

准确的版本要求

在设置依赖项的版本要求时,您希望尽可能准确。应不惜 一切代价 避免声明 * 的版本约束。此外,根据最新的开发版本,换句话说,使用 dev-master 约束,在我看来是粗心和冒险的,应该避免这种方法,即使包没有发布,这是其维护者的缺陷负责。

至少您应该使用 * 通配符以模式形式指定约束,例如: 1.0.* 2.* 和类似的。但除了通配符运算符之外,Composer 还提供了所谓的“下一个重要版本”运算符—— 波浪号 插入符 ,它们对尊重 语义版本 控制的项目非常有用,并被推荐用于最大化包间兼容性。

尽管如此,仍然存在某种风险,即某种错误或 BC 中断最终会出现在您的某些依赖项中,从而破坏您的代码。当然,您可以严格指定包的确切版本,但结果是,如果其他依赖项需要不同的版本,这种方法可能会导致依赖项解析最终失败并中止任何安装或更新过程。

作曲家锁

锁定文件的目的是记录项目中依赖项的确切版本。这意味着在安装依赖项并提交 composer.lock 文件后,当您的同事运行 composer install 时,他/她将获得相同版本的依赖项,即使同时发布了新版本。

关于 composer.lock 文件经常出现的问题是它是否应该提交给 repo。这是永恒的争论,对吧?但就我而言,没有两难选择,我遵循以下简单规则:

  • 在应用程序的情况下始终提交 composer.lock
  • 在组件的情况下永远不要提交 composer.lock

换句话说,这意味着你应该只为应用程序提交 composer.lock 文件,但如果是其他人在他/她的项目中安装和使用的库,你不应该提交它。

申请的原因很明显。将 composer.lock 放入 version 可确保您和您的队友使用完全相同版本的依赖包。更重要的是,它确保在生产和开发环境中使用相同的依赖项。这也意味着不需要版本查找或依赖项解析,从而加快了部署本身。

至于在组件开发的情况下不提交 composer.lock 的原因,如果您确实将依赖项锁定到某个版本,您可能不会意识到您的库无法使用某些较新的版本,即使您的 CI 构建正在通过,因为它将始终使用完全相同版本的依赖项运行。

生产部署

好的,现在毫无疑问, composer.lock 已提交,所以部署应该非常简单,您只需要运行 composer install 命令即可读取锁定版本的依赖项并安装它们,对吧?不完全的。

在生产环境中,您要确保排除所有开发内容。您可以使用 –no-dev 标志来做到这一点:


 {
    "autoload": {
        "psr-4": { 
            "MyLibrary\\": "src/",
            "MyLibrary\\Tests\\": "tests/"
        }
    }
}

这将完全省略开发所需的所有包的安装( require-dev 包),而且 Composer 自动加载器生成将跳过 autoload-dev 规则。

生产中非常需要的另一个标志是 --optimize-autoloader 。它将根据常规自动加载规则 (PSR-0/4) 生成一个类映射,这将加速您应用程序中的自动加载。

考虑到这些,这里推荐在执行生产部署时运行 composer install 的方法:


 {
    "autoload": {
        "psr-4": { 
            "MyLibrary\\": "src/",
            "MyLibrary\\Tests\\": "tests/"
        }
    }
}

长话短说

包作者的提示:

包用户提示:

  • 定义版本要求时尽可能准确;使用 下一个重要的发布操作符
  • 在应用程序的情况下始终提交 composer.lock,在组件的情况下永远不会
  • 生产部署安装命令: composer install --no-ansi --no-dev --no-interaction --no-progress --optimize-autoloader

参考