代码之家  ›  专栏  ›  技术社区  ›  danjarvis

define()与const

  •  606
  • danjarvis  · 技术社区  · 15 年前

    非常简单的问题:在PHP中,什么时候使用

    define('FOO', 1);
    

    你什么时候用

    const FOO = 1;
    

    这两者的主要区别是什么?

    10 回复  |  直到 6 年前
        1
  •  966
  •   NikiC    6 年前

    从php 5.3开始,有两种方法可以 define constants :使用 const 关键字或使用 define() 功能:

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

    这两种方法的根本区别在于 康斯特 在编译时定义常量,而 define 在运行时定义它们。这导致了 康斯特 的缺点。的一些缺点 康斯特 是:

    • 康斯特 不能用于有条件地定义常量。要定义全局常量,必须在最外部的作用域中使用它:

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

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

      if (!defined('FOO')) {
          define('FOO', 'BAR');
      }
      
    • 康斯特 接受静态标量(数字、字符串或其他类似常量 true , false , null , __FILE__ )鉴于 定义() 接受任何表达式。因为php 5.6常量表达式在 康斯特 也:

      const BIT_5 = 1 << 5;    // valid since PHP 5.6, invalid previously
      define('BIT_5', 1 << 5); // always valid
      
    • 康斯特 采用普通常量名,而 定义() 接受任何表达式作为名称。这样做可以做到:

      for ($i = 0; $i < 32; ++$i) {
          define('BIT_' . $i, 1 << $i);
      }
      
    • 康斯特 S总是区分大小写,而 定义() 允许您通过传递来定义不区分大小写的常量 作为第三个论点:

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

    所以,这是坏的一面。现在让我们来看看为什么我个人总是使用 康斯特 除非出现上述情况之一:

    • 康斯特 只是读得更好。它是一种语言结构而不是函数,并且与您如何在类中定义常量是一致的。
    • 康斯特 作为一种语言结构,可以通过自动化工具进行静态分析。
    • 康斯特 在当前命名空间中定义常量,而 定义() 必须传递完整的命名空间名称:

      namespace A\B\C;
      // To define the constant A\B\C\FOO:
      const FOO = 'BAR';
      define('A\B\C\FOO', 'BAR');
      
    • 从php 5.6开始 康斯特 常量也可以是数组,而 定义() 尚不支持数组。然而,在php 7中,两种情况都支持数组。

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

    最后,请注意 康斯特 也可以在类或接口内用于定义 class constant 或接口常数。 定义 不能用于此目的:

    class Foo {
        const BAR = 2; // valid
    }
    // but
    class Baz {
        define('QUX', 2); // invalid
    }
    

    总结

    除非您需要任何类型的条件或表达定义,否则请使用 康斯特 S而不是 定义() 只是为了可读性!

        2
  •  194
  •   Brant Bobby    13 年前

    在php 5.3之前, const 无法在全局范围内使用。你只能在一个类中使用这个。当您希望设置某种与该类相关的常量选项或设置时,应该使用此选项。或者您可能想要创建某种枚举。

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

    好的例子 康斯特 用法是去掉幻数。看看 PDO's constants . 当需要指定提取类型时,您将键入 PDO::FETCH_ASSOC 例如。如果警察不使用的话,你最后会键入 35 (或者别的什么) FETCH_ASSOC 定义为)。这对读者来说毫无意义。

    好的例子 定义 用法可能是指定应用程序的根路径或库的版本号。

        3
  •  35
  •   GordonM    8 年前

    我知道这已经被回答了,但是目前的答案都没有提到名称间距以及它如何影响常量和定义。

    从PHP5.3开始,consts和defines在大多数方面都是相似的。然而,仍然存在一些重要的差异:

    • 不能从表达式定义常量。 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' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3] .

    ===更新===

    即将推出的php 5.6允许在 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 RND = mt_rand();
    const CONSTVAR = $var;
    

    仍将外出。

        4
  •  22
  •   mattle    15 年前

    我相信从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;
    ?>
    
        5
  •  18
  •   Jacob Relkin    15 年前

    define 我用它来表示全局常量。

    const 我用于类常量。

    你不能 定义 在类范围内,并使用 康斯特 你可以。 不用说,你不能用 康斯特 类范围之外

    此外,还有 康斯特 ,它实际上成为类的成员, 定义 ,将被推向全球范围。

        6
  •  13
  •   slartibartfast    13 年前

    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并不能真正保证这一点。

        7
  •  12
  •   AwesomeBobX64    12 年前

    大多数答案都是错误的,或者只讲了一半的故事。

    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
    
        8
  •  5
  •   MrWhite    15 年前

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

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

    而您可以使用define()。所以,这并不是真正的个人偏好,有一个正确和错误的方法来使用两者。

    作为旁白…我想看看可以分配给表达式的类常量,一种可以隔离到类的define()?

        9
  •  5
  •   Marcus Lind    8 年前

    加上尼基的回答。 const 可在类内按以下方式使用:

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

    你不能这么做 define() .

        10
  •  3
  •   Николай Лубышев    7 年前

    没有人说任何关于php-doc的事情,但对我来说,这也是一个非常重要的论据,它优先于 const :

    /**
     * My foo-bar const
     * @var string
     */
    const FOO = 'BAR';