define()与const


658

在PHP中,何时使用

define('FOO', 1);

以及何时使用

const FOO = 1;

两者之间的主要区别是什么?


4
关于性能(像我这样进行微优化的时间浪费),请参见以下答案const比快两倍define。关于页面加载时间和内存使用情况:请参见此问题本文 ...另请参见此处有关操作码缓存的内容。
彼得·克劳斯

2
不要只看当前接受的答案,而请看一下stackoverflow.com/a/3193704/1412157,因为它应该是接受的答案
LucaM 2015年

1
刚刚看到了您的评论通知。我已经更新了接受的答案。
danjarvis

Answers:


1038

从PHP 5.3开始,有两种定义常量的方法:使用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()采取的任何表达式。由于PHP 5.6也允许使用常量表达式const

    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起不建议使用不区分大小写的常量。):

    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也可以在类或接口内使用它来定义类常量或接口常量。define不能用于此目的:

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

摘要

除非您需要任何类型的条件或表达式定义,否则使用consts代替define()s-仅出于可读性考虑!


1
据我所知,使用PHP 5.6时,即使使用const语言结构,也可以使用简单的标量表达式-参见wiki.php.net/rfc/const_scalar_exprs
mabe.berlin 2014年

6
使用的另一个好处const是缺少引号,这意味着它的格式与在IDE中使用的格式相同。
rybo111 2015年

3
这应该是PHP文档中的内容。这是我见过的最好的解释,尤其是大多数人忘记的部分(编译与运行时)。
詹姆斯

4
define('a', $_GET['param']);const b = a;可以完美工作并在const c = $_GET['param'];无效时获取值。const真的是编译时间吗?我几乎不这么认为...(在PHP 7.0.7上测试)
mcserep

1
wiki.php.net/rfc/case_insensitive_constant_deprecation在PHP 8.0中:消除了声明不区分大小写的常量的可能性。 ”对于任何在未来涉及到区分大小写问题的人
Scuzzy,

196

直到PHP 5.3,const才可以在全局范围内使用。您只能在一个班级中使用它。当您要设置某种与该类有关的常量选项或设置时,应使用此选项。或者,也许您想创建某种枚举。

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

良好const用法的一个例子是摆脱魔术数字。看一下PDO的常量。例如,当您需要指定提取类型时,可以输入PDO::FETCH_ASSOC。如果不使用const,您最终将输入类似35(或FETCH_ASSOC定义为)的内容。这对读者没有意义。

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


12
值得一提的是constwith与命名空间的使用。
萨拉特(Salathe)2010年

31
还应该注意,PHP5.3可以在全局范围内非常使用const。
戈登2010年

5.2也可以。consts与define的区别在于,您必须在它们前面加上类名。使用它们使代码更易读和更漂亮。这对我来说是个好处。
lucifurious

1
@ryeguy但是在PHP 5.3之后,可以像定义一样在全局使用const呢?
andho 2012年

1
@andho,将PHP舞蹈的另一步归类为“进步”之舞。他。:)
Falken教授的合同

37

我知道已经回答了这个问题,但是当前的回答都没有提及命名空间及其对常量和定义的影响。

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

  • 不能从表达式定义常量。 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。现在,您将能够根据表达式定义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;

仍然会出来。


8
我不禁要问:您是否有意识地将其定义FORTY_TWO为54?
Punchlinern 2014年

9
“六点九分?四十二点?我总是说宇宙根本有问题。”如果您需要完整的解释,请查阅道格拉斯·亚当斯的著作。
GordonM 2014年

2
哦。我知道42是生命,宇宙和所有事物的答案,但我错过了九分之六。感谢您的解释!
Punchlinern 2014年


20

define 我用全局常量。

const 我使用类常量。

您不能define进入课堂范围,而const可以。不用说,您不能使用const外部类作用域。

同样,使用const,它实际上成为该类的成员,并且使用define,它将被推到全局范围。


8
正如在其他答案中指出的那样,const可以在PHP 5.3+中的类之外使用
MrWhite 2012年

仅const关键字可用于创建命名空间常量,而不仅限于类
Alireza Rahmani Khalili

16

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


1
是的,但BAR\foo\BAR只是相同的常量。我同意这确实令人困惑,但是如果您还考虑到诸如命名空间逻辑这样的方式是一致的,并且既不是constdefine()不像C #define),那么PHP可以找些借口。
Sz。

1
const概念正是它应该表现的方式-您位于名称空间中!您希望它没有名称空间标识符,然后在名称空间之外创建它。这也使它与在类中定义的const一致,即使它使用不同的语法也是如此。是的,定义也以不同的方式保持一致。
Gerard ONeill

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

1
PHP> = 5.6,Zend Engine Compiler进行了一些更改,现在正在以另一种方式处理const。
Ankit Vishwakarma

6

是的,const是在编译时定义的,并且由于尼克状态不能像define()那样分配表达式。但是也不能有条件地声明const(出于相同的原因)。即。你不可以做这个:

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

而您可以使用define()。因此,这并没有真正归结为个人喜好,同时使用两种方法都有正确和错误的方法。

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


5

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

class Foo {
    const BAR = 1;

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

您不能使用来做到这一点define()


4

没有人说过有关php-doc的任何信息,但对我来说,这也是首选参数const

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

0

使用define关键字constant,您将获得不区分大小写的功能,而使用const关键字则没有。

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.