PHP|定义()vs. const

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

  1. 使用define关键字

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

    const FOO = 1;
    

  • 这两者之间的主要区别是什么?
  • 何时以及为什么你应该使用一个,何时使用另一个?
255836 次浏览

define我用于全局常量。

const我用于类常量。

您不能define进入类范围,而使用const您可以。

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

在PHP 5.3之前,const不能在全局范围内使用。您只能在类中使用它。当您想要设置某种常量选项或属于该类的设置时,应该使用它。或者您可能想创建某种枚举。

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

好的const用法的一个例子是摆脱魔术数字。看看PDO常数。例如,当你需要指定获取类型时,你会键入PDO::FETCH_ASSOC。如果不使用consts,你最终会键入类似35(或FETCH_ASSOC定义的任何内容)的东西。这对读者来说没有意义。

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

我相信从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;
?>

从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);
    }
    
  • #EYZ始终区分大小写,而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也可以在类或接口中用于定义类常数或接口常量。define不能用于此目的:

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

总结

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

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

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

然而,你可以使用定义()。所以,它并不真正归结为个人偏好,有一种正确和错误的使用方式。

顺便说一句……我想看到某种可以分配表达式的类const,一种可以隔离到类的定义()?

我知道这个问题已经回答过了,但目前的答案都没有提到命名空间以及它如何影响常量和定义。

从PHP 5.3开始,consts和定义在大多数方面都很相似。然而,仍然有一些重要的区别:

  • 不能从表达式中定义常量。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;

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

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

仍将出局。

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. 您可以使用命名空间来限定常量的范围。
  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('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid

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

class Foo {
const BAR = 1;


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

你不能用define()做到这一点。