define () vs const

658

En PHP, quand utilisez-vous

define('FOO', 1);

et quand utilisez-vous

const FOO = 1;

?

Quelles sont les principales différences entre ces deux?

danjarvis
la source
4
Concernant les performances (perte de temps avec la micro-optimisation comme moi), voyez cette réponse : constest deux fois plus rapide que define. À propos du temps de chargement des pages et de l'utilisation de la mémoire: voir cette question et cet article ... Voir aussi quelque chose sur le cache opcode ici .
Peter Krauss
2
Ne regardez pas seulement la réponse actuellement acceptée, mais jetez un coup d'œil à stackoverflow.com/a/3193704/1412157 car cela aurait dû être la réponse acceptée
LucaM
1
Je viens de voir la notification pour votre commentaire. J'ai mis à jour la réponse acceptée.
danjarvis

Réponses:

1039

Depuis PHP 5.3, il existe deux façons de définir des constantes : soit en utilisant le constmot - clé, soit en utilisant la define()fonction:

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

La différence fondamentale entre ces deux façons est de constdéfinir les constantes au moment de la compilation, tandis que de les definedéfinir au moment de l'exécution. Cela entraîne la plupart des constinconvénients de. Certains inconvénients constsont:

  • constne peut pas être utilisé pour définir conditionnellement des constantes. Pour définir une constante globale, elle doit être utilisée dans la portée la plus externe:

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

    Pourquoi voudriez-vous faire cela de toute façon? Une application courante consiste à vérifier si la constante est déjà définie:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
  • constaccepte un scalaire (nombre, une chaîne ou une autre constante comme statique true, false, null, __FILE__), alors que define()prend toute expression. Étant donné que les expressions constantes PHP 5.6 sont également autorisées dans const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
  • constprend un nom simple et constant, alors qu'il define()accepte toute expression comme nom. Cela permet de faire des choses comme ça:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
  • consts sont toujours sensibles à la casse, tandis que define()vous permet de définir des constantes insensibles à la casse en passant truecomme troisième argument (Remarque: la définition des constantes insensibles à la casse est déconseillée à partir de PHP 7.3.0.):

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

C'était donc le mauvais côté des choses. Voyons maintenant la raison pour laquelle j'utilise toujours personnellement, constsauf si l'une des situations ci-dessus se produit:

  • constlit simplement mieux. C'est une construction de langage au lieu d'une fonction et est également cohérente avec la façon dont vous définissez les constantes dans les classes.
  • const, étant une construction de langage, peut être analysé statiquement par un outillage automatisé.
  • constdéfinit une constante dans l'espace de noms courant, tandis que define()le nom complet de l'espace de noms doit être passé:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
  • Étant donné que les constconstantes PHP 5.6 peuvent également être des tableaux, tandis que define()ne prend pas encore en charge les tableaux. Cependant, les tableaux seront pris en charge dans les deux cas en 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

Enfin, notez que constpeut également être utilisé dans une classe ou une interface pour définir une constante de classe ou une constante d' interface. definene peut pas être utilisé à cette fin:

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

Sommaire

Sauf si vous avez besoin de tout type de définition conditionnelle ou expressionnelle, utilisez consts au lieu de define()s - simplement par souci de lisibilité!

NikiC
la source
1
Comme je le sais avec PHP 5.6, vous aurez la possibilité d'utiliser des expressions scalaires simples même avec la constconstruction du langage - voir wiki.php.net/rfc/const_scalar_exprs
mabe.berlin
6
Un autre avantage à utiliser constest le manque de guillemets, ce qui signifie qu'il est formaté de la même manière qu'il est utilisé dans votre IDE.
rybo111
3
Cela devrait être le contenu des documents PHP. C'est la meilleure explication que j'ai vue, en particulier la partie que la plupart des gens oublient (compilation vs exécution).
James
4
define('a', $_GET['param']);, const b = a;fonctionne parfaitement et obtient la valeur alors qu'elle const c = $_GET['param'];n'est pas valide. Est-ce constvraiment du temps de compilation? Je le pense à peine ... (testé sur PHP 7.0.7)
mcserep
1
wiki.php.net/rfc/case_insensitive_constant_deprecation « En PHP 8.0: Retirez la possibilité de déclarer des constantes insensibles à la casse. » pour tous ceux qui s'aventurer ailleurs ici dans l'avenir en ce qui concerne la casse
Scuzzy
196

Jusqu'à PHP 5.3, constne pouvait pas être utilisé dans la portée globale. Vous ne pouvez l'utiliser que depuis une classe. Cela doit être utilisé lorsque vous souhaitez définir une sorte d'option constante ou un paramètre qui se rapporte à cette classe. Ou peut-être voulez-vous créer une sorte d'énumération.

definepeut être utilisé dans le même but, mais il ne peut être utilisé que dans la portée globale. Il ne doit être utilisé que pour les paramètres globaux qui affectent l'ensemble de l'application.

Un exemple de bon constusage est de se débarrasser des nombres magiques. Jetez un œil aux constantes de PDO . Lorsque vous devez spécifier un type d'extraction, vous devez taper PDO::FETCH_ASSOC, par exemple. Si consts n'était pas utilisé, vous finiriez par taper quelque chose comme 35(ou quoi que ce FETCH_ASSOCsoit défini comme). Cela n'a aucun sens pour le lecteur.

Un exemple de bonne defineutilisation peut être de spécifier le chemin racine de votre application ou le numéro de version d'une bibliothèque.

ryeguy
la source
12
Il vaut peut-être la peine de mentionner l'utilisation de constwith namespaces.
salathe
31
Il convient également de noter que PHP5.3 peut très bien utiliser const dans la portée globale.
Gordon
5.2 peut aussi. La beauté de consts vs define est que vous devez les préfixer avec le nom de la classe. Leur utilisation rend le code plus lisible et plus joli. Et c'est un bonus pour moi.
lucifurious
1
@ryeguy mais qu'en est-il de PHP 5.3 où const peut être utilisé globalement comme pour define?
andho
1
@andho, lancez un autre vers la danse PHP d'un pas en avant, d'un pas en arrière, danse des "améliorations". Il. :)
contrat du professeur Falken a été rompu le
37

Je sais que cela a déjà été répondu, mais aucune des réponses actuelles ne mentionne l'espace de noms et comment il affecte les constantes et définit.

Depuis PHP 5.3, consts et define sont similaires à la plupart des égards. Il existe cependant encore quelques différences importantes:

  • Les consts ne peuvent pas être définis à partir d'une expression. const FOO = 4 * 3;ne fonctionne pas, mais define('CONST', 4 * 3);fonctionne.
  • Le nom transmis à definedoit inclure l'espace de noms à définir dans cet espace de noms.

Le code ci-dessous doit illustrer les différences.

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

namespace {
    var_dump(get_defined_constants(true));
}

Le contenu du sous-tableau utilisateur sera ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== MISE À JOUR ===

Le prochain PHP 5.6 permettra un peu plus de flexibilité avec const. Vous pourrez désormais définir des consts en termes d'expressions, à condition que ces expressions soient constituées d'autres consts ou de littéraux. Cela signifie que les éléments suivants doivent être valides à partir de 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;

Cependant, vous ne pourrez toujours pas définir de consts en termes de variables ou de retours de fonctions, donc

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

sera toujours sorti.

GordonM
la source
8
Je n'ai pas pu résister à demander: avez-vous consciemment défini FORTY_TWOcomme 54?
Punchlinern
9
"Six par neuf? Quarante-deux? J'ai toujours dit qu'il y avait quelque chose de fondamentalement mauvais dans l'univers" Consultez les travaux de Douglas Adams si vous avez besoin d'une explication complète.
GordonM
2
Oh. Je savais que 42 est la réponse à la vie, à l'univers et à tout, mais j'ai raté le Six par neuf parties. Merci pour l'explication!
Punchlinern
22

Je crois qu'à partir de PHP 5.3, vous pouvez utiliser en constdehors des classes, comme indiqué ici dans le deuxième exemple:

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
la source
20

define J'utilise pour les constantes globales.

const J'utilise pour les constantes de classe.

Vous ne pouvez pas defineentrer dans la portée de la classe et avec constvous le pouvez. Inutile de dire que vous ne pouvez pas utiliser la constportée de classe en dehors.

De plus, avec const, il devient en fait un membre de la classe, et avec define, il sera poussé à la portée globale.

Jacob Relkin
la source
8
Comme indiqué dans d'autres réponses, const peut être utilisé en dehors des classes en PHP 5.3+
MrWhite
Seul le mot clé const peut être utilisé pour créer une constante à espace de nom, pas seulement les classes
Alireza Rahmani Khalili
16

La réponse de NikiC est la meilleure, mais permettez-moi d'ajouter une mise en garde non évidente lors de l'utilisation des espaces de noms afin de ne pas vous faire surprendre par un comportement inattendu. La chose à retenir est que les définitions sont toujours dans l'espace de noms global, sauf si vous ajoutez explicitement l'espace de noms comme partie de l'identificateur de définition. Ce qui n'est pas évident à ce sujet, c'est que l'identifiant de l'espace de nom l'emporte sur l'identifiant global. Donc :

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

produit:

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

Ce qui pour moi rend la notion de const confondante inutilement car l'idée d'un const dans des dizaines d'autres langages est qu'il est toujours le même où que vous soyez dans votre code, et PHP ne le garantit pas vraiment.

slartibartfast
la source
1
Oui, mais BARet ce ne \foo\BARsont tout simplement pas les mêmes constantes. Je suis d' accord qu'il est vraiment déroutant, mais si l' on considère aussi des choses comme la logique de l' espace de nommage étant cohérente de cette façon, et que ni constne define()ressemble à un C macro ( #define), alors PHP peut avoir une excuse.
Sz.
1
La notion de const est exactement la façon dont elle devrait se comporter - vous êtes dans un espace de noms! Vous le voulez sans l'identifiant d'espace de noms, puis créez-le en dehors de l'espace de noms. Cela le rend également cohérent avec le const étant défini dans une classe, même s'il utilise une syntaxe différente. Oui, définir est également cohérent, d'une manière différente.
Gerard ONeill
12

La plupart de ces réponses sont fausses ou ne racontent que la moitié de l'histoire.

  1. Vous pouvez étendre vos constantes à l'aide d'espaces de noms.
  2. Vous pouvez utiliser le mot clé "const" en dehors des définitions de classe. Cependant, tout comme dans les classes, les valeurs affectées à l'aide du mot clé "const" doivent être des expressions constantes.

Par exemple:

const AWESOME = 'Bob'; // Valid

Mauvais exemple:

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

Pour créer des constantes variables, utilisez define () comme ceci:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid
AwesomeBobX64
la source
1
PHP> = 5.6 quelques modifications ont été apportées dans Zend Engine Compiler et const est traité d'une autre manière maintenant.
Ankit Vishwakarma
6

Oui, les const sont définis au moment de la compilation et comme les états nikic ne peuvent pas être assignés à une expression, comme le peuvent les define (). Mais les const ne peuvent pas non plus être déclarés conditionnellement (pour la même raison). c'est à dire. Tu ne peux pas faire ça:

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

Alors que vous pourriez avec un define (). Donc, cela ne se résume pas vraiment à une préférence personnelle, il y a une bonne et une mauvaise façon d'utiliser les deux.

En passant ... Je voudrais voir une sorte de classe const à laquelle on peut assigner une expression, une sorte de define () qui peut être isolé aux classes?

MrWhite
la source
5

Pour ajouter sur la réponse de NikiC. constpeut être utilisé dans les classes de la manière suivante:

class Foo {
    const BAR = 1;

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

Vous ne pouvez pas faire cela avec define().

Marcus Lind
la source
4

Personne ne dit rien sur php-doc, mais pour moi, c'est aussi un argument très important pour la préférence de const:

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

Avec define keyword constant, vous obtiendrez les fonctionnalités de la casse insensible, mais avec const keyword vous ne l'avez pas fait.

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
la source