【问题标题】:Are PHP global constants a good modern development practice?PHP 全局常量是一种良好的现代开发实践吗?
【发布时间】:2011-10-07 20:34:51
【问题描述】:

我正在开发一个包含大量 PHP 代码库的新项目。该应用程序使用了相当多的 PHP 常量 (define('FOO', 'bar')),特别是对于数据库连接参数之类的东西。这些常量都定义在一个单独的配置文件中,该文件基本上由应用程序中的每个类直接require_once()'d。

几年前这很合理,但从那时起我就遇到了单元测试错误,并且类之间的这种紧密耦合真的让我很困扰。这些常量闻起来像全局变量,并且在整个应用程序代码中直接引用。

这仍然是个好主意吗?将这些值复制到一个对象中并使用该对象(即一个 Bean - 我说过)通过依赖注入将它们传递给与数据库交互的类是否合理?我这样做是否会破坏 PHP 常量的任何好处(比如速度或其他东西)?

我正在考虑的另一种方法是创建一个单独的配置 PHP 脚本进行测试。我仍然需要想办法让被测类使用沙盒配置脚本而不是全局配置脚本。这仍然感觉很脆弱,但它可能需要对整个应用程序进行较少的彻底修改。

【问题讨论】:

  • #define CONSTANTS 'are fine'?
  • @Marc B:太爱了!
  • 这些常量是/曾经是(超级)全局变量,只能设置一次。这就是为什么它们被用于配置 - 不是出于测试原因,而是(因为没有进行测试)以确保它们不会被其余的热翘起和奶酪支持的意大利面条代码更改 - 只是为了确保代码的任何部分都没有... ;) - 所以为工作选择合适的工具。逐步测试遗留代码是一门艺术。删除常量可能是其中的一部分。
  • 这类问题的答案是意见或讨论,不适合 Stack Overflow。根据faq您应该只根据您面临的实际问题提出实用、可回答的问题。“不具建设性”的最接近的原因列出了诸如 这个问题可能会征求意见的原因意见、辩论、争论、投票或扩展讨论。因此,我将其关闭为“不具建设性”。
  • 好的,我敲定了 3 票重新打开它。我并不是说关闭它是/错误的,但社区已经发声了。

标签: php unit-testing dependency-injection tdd


【解决方案1】:

在我看来,常量应该只在两种情况下使用:

  • 实际常量值(即永远不会改变的东西,SECONDS_PER_HOUR)。
  • 依赖于操作系统的值,只要应用程序可以在任何可能的情况下透明地使用该常量即可。

即便如此,我还是会重新考虑类常量是否更合适,以免污染常量空间。

在您的情况下,我会说常量不是一个好的解决方案,因为您需要根据使用它们的位置提供替代值。

【讨论】:

  • 一个例子可能是 php 文件的文件扩展名define('EXT', '.php'),它不会逐页更改,并且对于项目是全局的。
  • 这确实帮助我找到了问题的根源。我认为所讨论的常量并不是常量,而是它们是全局性的才是真正导致问题的原因。
  • 嗯...如果你不污染常量空间,你就有一个空间没有使用。您不会为任何事情保存它:您只是失去了语言功能(我尊重不使用定义的选择)。
【解决方案2】:

这些常量闻起来像全局变量,它们被直接引用 [...]。将这些值复制到一个对象中并 [...] 通过依赖注入传递它们是否合理?

绝对!我会更进一步,甚至应该避免使用类常量。因为它们是公开的,它们暴露了内部结构并且它们是 API,所以你不能轻易地改变它们,而不会冒着由于紧密耦合而破坏现有应用程序的风险。配置对象更有意义(只是不要让它成为单例)。

另见:

【讨论】:

  • 友好的建议,以更好地解释您的第一句话。问题本身的标题和措辞有些矛盾。标题询问“常量好吗?”,但正文读起来更像是“常量不好吗?”。很难说你站在哪一边。
  • @Mike 很抱歉,如果不清楚:“绝对”是指 OP 对常量是全局状态的担忧以及使用配置对象的想法。
【解决方案3】:

要回答这个问题,讨论所编写代码的风格很重要。

PHP 5 包含许多有用的 OOP 特性,其中之一是类常量。如果您使用面向对象的方法,而不是污染全局命名空间,或者担心覆盖公共常量,您应该使用类常量。

FOO_BAR 最终可能是FOO::BAR,这取决于您想要定义常量的范围。

如果您正在编写更程序化风格的程序,或者将程序化与某些类混合,则全局常量不是问题。如果您正在处理的代码由于您使用的常量而变得难以管理,请尝试更改内容。否则,别担心。

此外,类常量不允许您使用函数返回值,而全局常量。当您拥有一个在整个程序范围内永远不会更改但需要生成的值时,这非常有用。

【讨论】:

    【解决方案4】:

    对数据库连接信息使用常量是非常好的。这可以防止在对象本身内对其进行硬编码,并且由于它是只读的,因此您无法覆盖这些值。

    我不喜欢在对象中硬编码我的设置,因为事情可能会发生变化,但如果你想这样做,那也可以。

    【讨论】:

    • 成为单元测试的大问题。最好使用依赖注入。
    【解决方案5】:

    如果您有 PHP 5.3 或更新版本,您可以使用namespace
    http://www.php.net/manual/en/language.namespaces.php

    它适用于const variable = 'something';
    不幸的是,它不适用于define('variable','something');

    命名空间中的全局变量被封装。在某些情况下,它比拥有一个对象更好。

    【讨论】:

      【解决方案6】:

      我不同意常量,也不同意硬编码:-)

      除了性能,我更喜欢 ZendFramework 的 Zend_Config_Ini。

      您可以重载部分,在内存中保持只读值,以及其他:

      http://framework.zend.com/manual/en/zend.config.adapters.ini.html

      【讨论】:

        猜你喜欢
        • 2012-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-19
        • 1970-01-01
        相关资源
        最近更新 更多