关于PHP define() vs const

define() vs const

非常简单的问题:在PHP中,您何时使用

1
define('FOO', 1);

你什么时候用

1
const FOO = 1;

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


从php5.3开始,定义常量有两种方法:使用const关键字或使用define()函数:

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

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

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

    1
    2
    3
    4
    5
    6
    7
    if (...) {
        const FOO = 'BAR';    // invalid
    }
    // but
    if (...) {
        define('FOO', 'BAR'); // valid
    }

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

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

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

    1
    2
    3
    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
  • consts总是区分大小写,而define()允许您通过将true作为第三个参数来定义不区分大小写的常量:

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

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

  • const读起来更清楚。它是一种语言构造,而不是函数,并且与您在类中定义常量的方式一致。
  • const是一种语言结构,可以通过自动化工具进行静态分析。
  • const在当前命名空间中定义了一个常量,而define()必须传递完整的命名空间名称:

    1
    2
    3
    4
    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
  • 由于php 5.6const常量也可以是数组,而define()还不支持数组。然而,在php 7中,两种情况都支持数组。

    1
    2
    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

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

1
2
3
4
5
6
7
class Foo {
    const BAR = 2; // valid
}
// but
class Baz {
    define('QUX', 2); // invalid
}

总结

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


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

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

很好的const用法的一个例子是去掉幻数。看看PDO的常数。例如,当需要指定提取类型时,可以键入PDO::FETCH_ASSOC。如果不使用consts,您最终会键入类似于35的内容(或FETCH_ASSOC的定义)。这对读者来说毫无意义。

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


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

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

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

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

1
2
3
4
5
6
7
8
9
10
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起有效:

1
2
3
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;

但是,您仍然无法根据变量或函数返回定义常量,因此

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

仍将外出。


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

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

1
2
3
4
5
6
<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';

echo CONSTANT;
?>

我用define表示全局常数。

我用const来表示类常量。

您不能将define放入类范围,使用const可以。不用说,您不能在类范围之外使用const

另外,在const中,它实际上是一个类的成员,而在define中,它将被推向全球范围。


Nikic的回答是最好的,但是让我在使用名称空间时添加一个不明显的警告,这样您就不会被意外行为捕获。要记住的是,除非将命名空间显式添加为define标识符的一部分,否则定义始终位于全局命名空间中。不明显的是,名称空间标识符胜过全局标识符。所以:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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?
"
, 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?
"
, \BAR);
}

namespace foo2
{
  // But now in another namespace (like in the default) the same syntax calls up the
  // the defined version!
  printf("Willy %s
"
, BAR);
  printf("three %s
"
, \foo\BAR);  
}
?>

生产:

1
2
3
4
What kind of bar is a cheers bar?
What kind of bar is a wonka bar?
willy wonka
three cheers

对我来说,这使得整个const概念不必要地令人困惑,因为在许多其他语言中,const的概念是,在代码中的任何位置都是相同的,而php并不能真正保证这一点。


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

  • 您可以使用名称空间来确定常量的范围。
  • 可以在类定义之外使用"const"关键字。但是,就像在类使用"const"关键字指定的值必须是常量表达式。
  • 例如:

    1
    const AWESOME = 'Bob'; // Valid

    坏榜样:

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

    要创建变量常量,请使用define(),如下所示:

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


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

    1
    2
    3
    4
    5
    6
    7
    class Foo {
        const BAR = 1;

        public function myMethod() {
            return self::BAR;
        }
    }

    你不能用define()来做这个。


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

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

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

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


    没有人提到php-doc,但对我来说,这也是一个非常重要的理由来支持const的偏好:

    1
    2
    3
    4
    5
    /**
     * My foo-bar const
     * @var string
     */

    const FOO = 'BAR';

    使用define关键字常量,您将获得case的功能不敏感,但对于const关键字,您没有。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
                      define("FOO", 1,true);
                      echo foo;//1
                      echo"<br/>";
                      echo FOO;//1
                      echo"<br/>";

                      class A{
                      const FOO = 1;
                      }

                      echo A::FOO;//valid
                      echo"<br/>";

                  //but

                      class B{
                      define FOO = 1;//syntax error, unexpected 'define'
                      }

                      echo B::FOO;//invalid