【问题标题】:PHP | define() vs. constPHP | define() 与 const
【发布时间】:2011-01-27 17:09:02
【问题描述】:

在 PHP 中,可以通过两种方式声明常量:

  1. 带有define关键字

    define('FOO', 1);
    
  2. 使用const 关键字

    const FOO = 1;
    

  • 这两者之间的主要区别是什么?
  • 何时以及为何应使用其中一种,何时使用另一种?

【问题讨论】:

  • 关于性能(像我这样微优化浪费时间),见this answerconstdefine快两倍。关于页面加载时间和内存使用情况:参见 this questionthis article... 另请参见操作码缓存 here

标签: php variables constants psr-1 psr-12


【解决方案1】:

从 PHP 5.3 开始,define constants 有两种方法:使用 const 关键字或使用 define() 函数:

const FOO = 'BAR';
define('FOO', 'BAR');

这两种方式的根本区别在于const 在编译时定义常量,而define 在运行时定义它们。这导致了const 的大部分缺点。 const 的一些缺点是:

  • const 不能用于有条件地定义常量。要定义一个全局常量,它必须在最外层范围内使用:

     if (...) {
         const FOO = 'BAR';    // Invalid
     }
     // but
     if (...) {
         define('FOO', 'BAR'); // Valid
     }
    

    你为什么要这样做?一种常见的应用是检查常量是否已经定义:

     if (!defined('FOO')) {
         define('FOO', 'BAR');
     }
    
  • const 接受静态标量(数字、字符串或其他常量,例如 truefalsenull__FILE__),而 define() 接受任何表达式。由于const 中也允许使用 PHP 5.6 常量表达式:

     const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
     define('BIT_5', 1 << 5); // Always valid
    
  • const 接受一个普通的常量名称,而define() 接受任何表达式作为名称。这允许执行以下操作:

     for ($i = 0; $i < 32; ++$i) {
         define('BIT_' . $i, 1 << $i);
     }
    
  • consts 始终区分大小写,而define() 允许您通过将true 作为第三个参数传递来定义不区分大小写的常量(注意:定义不区分大小写的常量自 PHP 7.3.0 起已弃用并已删除自 PHP 8.0.0 起):

     define('FOO', 'BAR', true);
     echo FOO; // BAR
     echo foo; // BAR
    

所以,这是不好的一面。现在来看看我个人除非出现上述情况之一,否则总是使用const的原因:

  • const 读起来更好听。它是一种语言构造而不是函数,并且与您在类中定义常量的方式一致。

  • const 是一种语言结构,可以通过自动化工具进行静态分析。

  • const 在当前命名空间中定义一个常量,而define() 必须传递完整的命名空间名称:

     namespace A\B\C;
     // To define the constant A\B\C\FOO:
     const FOO = 'BAR';
     define('A\B\C\FOO', 'BAR');
    
  • 从 PHP 5.6 开始,const 常量也可以是数组,而 define() 还不支持数组。但是,在 PHP 7 中这两种情况都支持数组。

     const FOO = [1, 2, 3];    // Valid in PHP 5.6
     define('FOO', [1, 2, 3]); // Invalid in PHP 5.6 and valid in PHP 7.0
    

最后,请注意const 也可以在类或接口中用于定义class constant 或接口常量。 define 不能用于此目的:

class Foo {
    const BAR = 2; // Valid
}
// But
class Baz {
    define('QUX', 2); // Invalid
}

总结

除非您需要任何类型的条件或表达式定义,否则请使用 consts 而不是 define()s - 只是为了便于阅读!

【讨论】:

  • 据我所知,使用 PHP 5.6,即使使用 const 语言结构,您也可以使用简单的标量表达式 - 请参阅 wiki.php.net/rfc/const_scalar_exprs
  • 使用 const 的另一个好处是没有引号,这意味着它的格式与在 IDE 中使用的相同。
  • 这应该是 PHP 文档中的内容。这是我见过的最好的解释,尤其是大多数人忘记的部分(编译与运行时)。
  • define('a', $_GET['param']);, const b = a; 完美运行并获取值,而 const c = $_GET['param']; 无效。 const 真的是编译时间吗?我几乎不这么认为......(在 PHP 7.0.7 上测试)
  • wiki.php.net/rfc/case_insensitive_constant_deprecation "在 PHP 8.0 中:消除声明不区分大小写的常量的可能性。" 对于未来在区分大小写方面冒险的任何人
【解决方案2】:

在 PHP 5.3 之前,const 不能在全局范围内使用。你只能在课堂上使用它。当您想要设置某种常量选项或与该类相关的设置时,应该使用它。或者,也许您想创建某种枚举。

define 可以用于相同的目的,但只能在全局范围内使用。它应该只用于影响整个应用程序的全局设置。

一个好的const用法的例子是摆脱幻数。看看PDO's constants。例如,当您需要指定提取类型时,您可以输入PDO::FETCH_ASSOC。如果不使用 const,您最终会输入类似 35 的内容(或定义为 FETCH_ASSOC 的任何内容)。这对读者来说毫无意义。

一个好的define 用法示例可能是指定应用程序的根路径或库的版本号。

【讨论】:

  • 在命名空间中使用const 可能值得一提。
  • 另外需要注意的是,PHP5.3可以非常多的在全局范围内使用const。
  • 5.2 也可以。 consts 与定义的美妙之处在于,您必须在它们前面加上类名。使用它们使代码更具可读性和更漂亮。这对我来说是一个奖励。
  • @ryeguy 但是在 PHP 5.3 之后可以像定义一样全局使用 const 呢?
  • @andho,将另一个归结为“改进”之舞的 PHP 向前一步,向后一步。他。 :)
【解决方案3】:

我知道这已经得到解答,但当前的答案都没有提到命名空间以及它如何影响常量和定义。

从 PHP 5.3 开始,const 和定义在大多数方面都是相似的。但是,仍然存在一些重要的区别:

  • 不能从表达式中定义常量。 const FOO = 4 * 3; 不起作用,但 define('CONST', 4 * 3); 起作用。
  • 传递给define 的名称必须包含要在该命名空间中定义的命名空间。

下面的代码应该说明差异。

namespace foo 
{
    const BAR = 1;
    define('BAZ', 2);
    define(__NAMESPACE__ . '\\BAZ', 3);
}

namespace {
    var_dump(get_defined_constants(true));
}

用户子数组的内容为['foo\\BAR' =&gt; 1, 'BAZ' =&gt; 2, 'foo\\BAZ' =&gt; 3]

=== 更新 ===

即将推出的 PHP 5.6 将通过 const 提供更多的灵活性。您现在可以根据表达式定义 const,前提是这些表达式由其他 const 或文字组成。这意味着以下内容应从 5.6 开始有效:

const FOOBAR = 'foo ' . 'bar';
const FORTY_TWO = 6 * 9; // For future editors: THIS IS DELIBERATE! Read the answer comments below for more details
const ULTIMATE_ANSWER = 'The ultimate answer to life, the universe and everything is ' . FORTY_TWO;

您仍然无法根据变量或函数返回来定义 const,所以

const RND = mt_rand();
const CONSTVAR = $var;

还是会出。

【讨论】:

  • 忍不住问:你有意识地将FORTY_TWO定义为54吗?
  • “六乘九?四十二?我总是说宇宙存在根本性的问题”如果您需要完整的解释,请查看道格拉斯·亚当斯的作品。
  • 哦。我知道 42 是生命、宇宙和一切的答案,但我错过了 6 到 9 部分。谢谢你的解释!
【解决方案4】:

define 我用于全局常量。

const 我用于类常量。

define 不能进入类范围,而 const 可以。不用说,你不能在类范围之外使用const

另外,使用const,它实际上成为类的成员,而使用define,它将被推送到全局范围。

【讨论】:

  • 如其他答案中所述, const 可以在 PHP 5.3+ 中的类之外使用
  • 只有 const 关键字可以用来创建命名空间常量,而不仅仅是类
【解决方案5】:

我相信从 PHP 5.3 开始,您可以在类之外使用const,如第二个示例所示:

http://www.php.net/manual/en/language.constants.syntax.php

<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';

echo CONSTANT;
?>

【讨论】:

    【解决方案6】:

    NikiC 的答案是最好的,但让我在使用命名空间时添加一个不明显的警告,这样您就不会陷入意外行为。要记住的是,定义在全局命名空间中始终,除非您明确地将命名空间添加为定义标识符的一部分。不明显的是命名空间标识符胜过全局标识符。所以:

    <?php
    namespace foo
    {
      // Note: when referenced in this file or namespace, the const masks the defined version
      // this may not be what you want/expect
      const BAR = 'cheers';
      define('BAR', 'wonka');
    
      printf("What kind of bar is a %s bar?\n", BAR);
    
      // To get to the define in the global namespace you need to explicitely reference it
      printf("What kind of bar is a %s bar?\n", \BAR);
    }
    
    namespace foo2
    {
      // But now in another namespace (like in the default) the same syntax calls up the 
      // the defined version!
      printf("Willy %s\n", BAR);
      printf("three %s\n", \foo\BAR);  
    }
    ?>
    

    产生:

    What kind of bar is a cheers bar? 
    What kind of bar is a wonka bar?
    willy wonka 
    three cheers
    

    这对我来说让整个 const 概念变得不必要地令人困惑,因为在许多其他语言中 const 的想法是,无论您在代码中的何处,它始终是相同的,而 PHP 并不能真正保证这一点。

    【讨论】:

    • 是的,但是BAR\foo\BAR 只是相同的常量。我同意这确实令人困惑,但是如果您还认为命名空间逻辑这样的事情是一致的,并且constdefine() 都不像 C macro (#define),那么PHP 可以有一些借口。
    • const 概念正是它应该表现的方式——你在一个命名空间中!您希望它没有命名空间标识符,然后在命名空间之外创建它。这也使其与类中定义的 const 一致,即使它使用不同的语法。是的,define 也是一致的,只是以不同的方式。
    【解决方案7】:

    这些答案大多是错误的,或者只说明了一半。

    1. 您可以使用命名空间来确定常量的范围。
    2. 您可以在类定义之外使用“const”关键字。然而,就像在 使用“const”关键字分配的值必须是 常量表达式。

    例如:

    const AWESOME = 'Bob'; // Valid
    

    不好的例子:

    const AWESOME = whatIsMyName(); // Invalid (Function call)
    const WEAKNESS = 4+5+6; // Invalid (Arithmetic) 
    const FOO = BAR . OF . SOAP; // Invalid (Concatenation)
    

    要创建变量常量,像这样使用define():

    define('AWESOME', whatIsMyName()); // Valid
    define('WEAKNESS', 4 + 5 + 6); // Valid
    define('FOO', BAR . OF . SOAP); // Valid
    

    【讨论】:

    • PHP >=5.6 在 Zend Engine Compiler 中进行了一些更改,现在正以另一种方式处理 const。
    【解决方案8】:

    是的,const 是在编译时定义的,因为不能为 nikic 状态分配表达式,而 define() 可以。但也不能有条件地声明 const(出于同样的原因)。 IE。你不能这样做:

    if (/* some condition */) {
      const WHIZZ = true;  // CANNOT DO THIS!
    }
    

    而你可以使用define()。所以,这并没有真正归结为个人喜好,两者都有正确和错误的使用方式。

    顺便说一句...我希望看到某种可以分配表达式的类 const,一种可以隔离到类的 define()?

    【讨论】:

      【解决方案9】:

      补充 NikiC 的答案。 const 可以通过以下方式在类中使用:

      class Foo {
          const BAR = 1;
      
          public function myMethod() {
              return self::BAR;
          }
      }
      

      define() 不能这样做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-23
        相关资源
        最近更新 更多