define () vs. const

658

No PHP, quando você usa

define('FOO', 1);

e quando você usa

const FOO = 1;

?

Quais são as principais diferenças entre os dois?

danjarvis
fonte
4
Sobre desempenho (perda de tempo com micro-otimização como eu), veja esta resposta : consté duas vezes mais rápido que define. Sobre o tempo de carregamento da página e o uso de memória: consulte esta pergunta e este artigo ... Consulte também algo sobre o cache do opcode aqui .
Peter Krauss
2
Não só olhar para a resposta aceita atual, mas por favor, dê uma olhada para stackoverflow.com/a/3193704/1412157 como deveria ter sido a resposta aceita
Lucam
1
Acabei de ver a notificação do seu comentário. Atualizei a resposta aceita.
Danjarvis 30/07/2015

Respostas:

1039

No PHP 5.3, existem duas maneiras de definir constantes : Usando a constpalavra - chave ou a define()função:

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

A diferença fundamental entre essas duas maneiras é que constdefine constantes em tempo de compilação, enquanto as definedefine em tempo de execução. Isso causa a maioria das constdesvantagens. Algumas desvantagens constsão:

  • constnão pode ser usado para definir condicionalmente constantes. Para definir uma constante global, ela deve ser usada no escopo mais externo:

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

    Por que você faria isso de qualquer maneira? Uma aplicação comum é verificar se a constante já está definida:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • constaceita um escalar estática (número, string ou outra constante, como true, false, null, __FILE__), enquanto define()toma qualquer expressão. Desde PHP 5.6, expressões constantes também são permitidas const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
    
  • constrecebe um nome constante e simples, enquanto define()aceita qualquer expressão como nome. Isso permite fazer coisas como esta:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • consts sempre diferenciam maiúsculas de minúsculas, ao passo que define()permitem definir constantes que não diferenciam maiúsculas de minúsculas, passando truecomo terceiro argumento (Nota: definir constantes que não diferenciam maiúsculas de minúsculas é preterido no PHP 7.3.0.):

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

Então, esse era o lado ruim das coisas. Agora, vamos ver o motivo pelo qual eu sempre uso pessoalmente, a constmenos que ocorra uma das situações acima:

  • constsimplesmente lê melhor. É uma construção de linguagem em vez de uma função e também é consistente com a forma como você define constantes nas classes.
  • const, sendo uma construção de linguagem, pode ser analisada estaticamente por ferramentas automatizadas.
  • constdefine uma constante no espaço para nome atual, enquanto define()deve ser passado o nome completo do espaço para nome:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • Como as constconstantes do PHP 5.6 também podem ser matrizes, enquanto define()ainda não suporta matrizes. No entanto, matrizes serão suportadas para ambos os casos no 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
    

Por fim, observe que consttambém pode ser usado em uma classe ou interface para definir uma constante de classe ou constante de interface. definenão pode ser utilizado para este fim:

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

Sumário

A menos que você precise de qualquer tipo de definição condicional ou expressional, use consts em vez de define()s - simplesmente para facilitar a leitura!

NikiC
fonte
1
Como eu sei com PHP 5.6 você terá a possibilidade de usar expressões escalares simples mesmo com a constconstrução da linguagem - ver wiki.php.net/rfc/const_scalar_exprs
mabe.berlin
6
Outro benefício do uso consté a falta de aspas, o que significa que é formatado da mesma forma que é usado no seu IDE.
rybo111
3
Esse deve ser o conteúdo dos documentos PHP. É a melhor explicação que eu já vi, especialmente a parte que a maioria das pessoas esquece (compilação versus tempo de execução).
James
4
define('a', $_GET['param']);, const b = a;funciona perfeitamente e obtém o valor enquanto const c = $_GET['param'];é inválido. É constrealmente tempo de compilação? Eu dificilmente penso assim ... (testado no PHP 7.0.7)
mcserep 4/17/17
1
wiki.php.net/rfc/case_insensitive_constant_deprecation " No PHP 8.0: Remover a possibilidade de declarar constantes de maiúsculas e minúsculas. " para qualquer outra pessoa se aventurar aqui para o futuro no que diz respeito à sensibilidade caso
Scuzzy
196

Até o PHP 5.3, constnão podia ser usado no escopo global. Você só pode usar isso de dentro de uma classe. Isso deve ser usado quando você deseja definir algum tipo de opção constante ou configuração que pertence a essa classe. Ou talvez você queira criar algum tipo de enum.

definepode ser usado para a mesma finalidade, mas só pode ser usado no escopo global. Só deve ser usado para configurações globais que afetam o aplicativo inteiro.

Um exemplo de bom constuso é se livrar dos números mágicos. Dê uma olhada nas constantes da DOP . Quando você precisar especificar um tipo de busca, digite PDO::FETCH_ASSOC, por exemplo. Se consts não fossem usados, você acabaria digitando algo como 35(ou o que FETCH_ASSOCfor definido como). Isso não faz sentido para o leitor.

Um exemplo de bom defineuso é talvez especificar o caminho raiz do aplicativo ou o número da versão da biblioteca.

ryeguy
fonte
12
Vale a pena mencionar o uso de constcom namespaces.
Salathe
31
Deve-se notar também que o PHP5.3 pode usar const constantemente no escopo global.
Gordon
5.2 também pode. A beleza de consts vs. define é que você deve prefixá-los com o nome da classe. Usá-los torna o código mais legível e mais bonito. E isso é um bônus para mim.
lucifurious
1
@ryeguy, mas e depois do PHP 5.3, em que const pode ser usado globalmente como define?
andho
1
@andho, giz outro para a dança PHP de um passo à frente, um passo para trás, dança de "melhorias". Ele. :)
Contrato do Prof. Falken violado
37

Sei que isso já foi respondido, mas nenhuma das respostas atuais faz menção ao namespacing e como isso afeta constantes e define.

A partir do PHP 5.3, consts e define são semelhantes na maioria dos aspectos. Ainda existem, no entanto, algumas diferenças importantes:

  • Consts não podem ser definidos a partir de uma expressão. const FOO = 4 * 3;não funciona, mas define('CONST', 4 * 3);funciona.
  • O nome passado para definedeve incluir o espaço para nome a ser definido dentro desse espaço para nome.

O código abaixo deve ilustrar as diferenças.

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

namespace {
    var_dump(get_defined_constants(true));
}

O conteúdo da sub-matriz do usuário será ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== ATUALIZAÇÃO ===

O próximo PHP 5.6 permitirá um pouco mais de flexibilidade com const. Agora você poderá definir consts em termos de expressões, desde que essas expressões sejam compostas de outros consts ou literais. Isso significa que o seguinte deve ser válido a partir da versão 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;

Você ainda não será capaz de definir consts em termos de variáveis ​​ou retornos de funções, portanto,

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

ainda estará fora.

GordonM
fonte
8
Não pude resistir a perguntar: você definiu conscientemente FORTY_TWOcomo 54?
Punchlinern
9
"Seis por nove? Quarenta e dois? Eu sempre disse que havia algo fundamentalmente errado com o universo". Confira os trabalhos de Douglas Adams se precisar de uma explicação completa.
precisa saber é o seguinte
2
Oh. Eu estava ciente de que 42 é a resposta da vida, do universo e de tudo, mas eu tinha perdido o Seis em nove partes. Obrigada pelo esclarecimento!
Punchlinern
22

Acredito que, a partir do PHP 5.3, você possa usar constfora das classes, como mostrado aqui no segundo exemplo:

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

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

echo CONSTANT;
?>
mattle
fonte
20

define Eu uso para constantes globais.

const Eu uso para constantes de classe.

Você não pode defineentrar no escopo da classe e com constvocê pode. Escusado será dizer que você não pode usar constfora do escopo da classe.

Além disso, com const, ele realmente se torna um membro da classe e define, com , será empurrado para o escopo global.

Jacob Relkin
fonte
8
Como observado em outras respostas, const pode ser usado fora das classes no PHP 5.3+
MrWhite
Apenas a palavra-chave const pode ser usado para criar uma constante namespaced, não apenas as classes
Alireza Rahmani Khalili
16

A resposta do NikiC é a melhor, mas deixe-me acrescentar uma ressalva não óbvia ao usar espaços de nome para que você não seja pego com comportamento inesperado. É importante lembrar que define sempre está no espaço para nome global, a menos que você inclua explicitamente o espaço para nome como parte do identificador de definição. O que não é óbvio nisso é que o identificador no namespace supera o identificador global. Assim :

<?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);  
}
?>

produz:

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

O que para mim torna desnecessariamente confusa toda a noção de const, já que a idéia de uma const em dezenas de outras linguagens é que ela é sempre a mesma onde quer que você esteja no seu código, e o PHP realmente não garante isso.

slartibartfast
fonte
1
Sim, mas BARe \foo\BARsimplesmente não são as mesmas constantes. Concordo que é realmente confuso, mas se você também considerar coisas como a lógica de namespacing consistentes dessa maneira, e que constnem define()é nem como uma macro C ( #define), o PHP pode ter alguma desculpa.
Sz.
1
A noção de const é exatamente como deve se comportar - você está em um espaço para nome! Você o deseja sem o identificador do espaço para nome e, em seguida, crie-o fora do espaço para nome. Isso também o torna consistente com a const que está sendo definida em uma classe, mesmo que use sintaxe diferente. Sim, define também é consistente, de uma maneira diferente.
precisa
12

A maioria dessas respostas está errada ou conta apenas metade da história.

  1. Você pode escopo suas constantes usando namespaces.
  2. Você pode usar a palavra-chave "const" fora das definições de classe. No entanto, assim como nas classes, os valores atribuídos usando a palavra-chave "const" devem ser expressões constantes.

Por exemplo:

const AWESOME = 'Bob'; // Valid

Mau exemplo:

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

Para criar constantes variáveis, use define () da seguinte forma:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid
AwesomeBobX64
fonte
1
PHP> = 5.6 algumas alterações foram feitas no Zend Engine Compiler e o const está sendo tratado de outra maneira agora.
Ankit Vishwakarma
6

Sim, const são definidos em tempo de compilação e como estados nikic não podem ser atribuídos a uma expressão, como define () pode. Mas também const's não podem ser declarados condicionalmente (pelo mesmo motivo). ie Você não pode fazer isso:

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

Considerando que você poderia com um define (). Portanto, não se resume a preferência pessoal, existe uma maneira correta e errada de usar as duas coisas.

Como um aparte ... Eu gostaria de ver algum tipo de classe const que pode ser atribuída a uma expressão, um tipo de define () que pode ser isolado para classes?

Sr. White
fonte
5

Para adicionar a resposta do NikiC. constpode ser usado nas classes da seguinte maneira:

class Foo {
    const BAR = 1;

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

Você não pode fazer isso com define().

Marcus Lind
fonte
4

Ninguém diz nada sobre php-doc, mas para mim esse também é um argumento muito significativo para a preferência de const:

/**
 * My foo-bar const
 * @var string
 */
const FOO = 'BAR';
Николай Лубышев
fonte
0

Com definir a palavra-chave constante, você obterá as facilidades de distinção entre maiúsculas e minúsculas, mas com a palavra-chave const, você não conseguiu.

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
GaziAnis
fonte