web-dev-qa-db-fra.com

define () vs. const

En PHP, quand utilisez-vous

define('FOO', 1);

et quand utilisez-vous

const FOO = 1;

?

Quelles sont les principales différences entre ces deux?

634
danjarvis

A partir de PHP 5.3, il y a deux façons de définir des constantes : soit en utilisant le mot clé const, soit en utilisant la fonction define() :

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

La différence fondamentale entre ces deux méthodes est que const définit les constantes au moment de la compilation, tandis que define les définit au moment de l'exécution. Cela cause la plupart des inconvénients de const. Certains inconvénients de const sont les suivants:

  • const ne peut pas être utilisé pour définir des constantes de manière conditionnelle. 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 ça quand même? Une application courante consiste à vérifier si la constante est déjà définie:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • const accepte un scalaire statique (nombre, chaîne ou autre constante comme true, false, null, __FILE__), alors que define() prend n'importe quelle expression. Depuis PHP 5.6, les expressions constantes 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
    
  • const prend un nom de constante simple, alors que define() accepte n'importe quelle expression en tant que 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, alors que define() vous permet de définir des constantes ne respectant pas la casse en passant true comme troisième argument:

    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 personnellement toujours const à moins que l’une des situations ci-dessus ne se produise:

  • const lit simplement plus agréable. C'est une construction de langage au lieu d'une fonction et elle est cohérente avec la définition des constantes dans les classes.
  • const, étant une construction de langage, peut être analysé statiquement par un outil automatisé.
  • const définit une constante dans l'espace de nom actuel, tandis que define() doit recevoir le nom complet de l'espace de nom:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • Depuis PHP 5.6 _, les constantes const peuvent également être des tableaux, alors que define() ne les prend pas encore en charge. Toutefois, les tableaux seront pris en charge dans les deux cas dans 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 const peut également être utilisé dans une classe ou une interface pour définir une constante constante de classe ou constante. define ne peut pas être utilisé à cette fin:

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

Résumé

Sauf si vous avez besoin de n'importe quel type de définition conditionnelle ou expressionelle, utilisez consts au lieu de define()s - simplement pour des raisons de lisibilité!

1007
NikiC

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

define peut ê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 bon exemple d'utilisation de const consiste à supprimer les nombres magiques. Jetez un oeil à constantes de PDO . Lorsque vous devez spécifier un type d'extraction, vous devez, par exemple, entrer PDO::FETCH_ASSOC. Si les consts n'étaient pas utilisés, vous finissiez par saisir quelque chose comme 35 (ou tout ce que FETCH_ASSOC soit défini comme). Cela n'a aucun sens pour le lecteur.

Un exemple d'utilisation correcte de define consiste peut-être à spécifier le chemin racine de votre application ou le numéro de version d'une bibliothèque.

196
ryeguy

Je sais que cette question a déjà été résolue, mais aucune des réponses actuelles ne fait mention du espacement de noms et de son incidence sur les constantes et les définitions.

A partir de PHP 5.3, les const et définitions sont similaires à bien des égards. Il subsiste cependant quelques différences importantes:

  • Les const 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 à define doit inclure l'espace de nom à définir dans cet espace de nom.

Le code ci-dessous devrait 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].

=== UPDATE ===

La prochaine PHP 5.6 permettra un peu plus de flexibilité avec const. Vous pourrez maintenant définir des const en termes d'expressions, à condition que ces expressions soient composées d'autres const ou de littéraux. Cela signifie que les éléments suivants devraient être valides à partir de la version 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;

Vous ne pourrez toujours pas définir consts en termes de variables ou de retours de fonction, alors

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

sera toujours dehors.

37
GordonM

Je crois qu'à partir de PHP 5.3, vous pouvez utiliser const en dehors des classes, comme indiqué 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;
?>
22
mattle

define J'utilise pour les constantes globales.

const J'utilise pour les constantes de classe.

Vous ne pouvez pas define dans la portée de classe, et avec const vous le pouvez. Il va sans dire que vous ne pouvez pas utiliser const en dehors de la portée de la classe.

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

21
Jacob Relkin

La réponse de NikiC est la meilleure, mais permettez-moi d'ajouter une mise en garde non évidente lorsque vous utilisez des espaces de noms afin que vous ne soyez pas surpris par un comportement inattendu. Il est important de se rappeler que les définitions sont toujours dans l'espace de noms global, sauf si vous ajoutez explicitement l'espace de noms dans le cadre de l'identificateur de définition. Ce qui n’est pas évident, c’est que l’identificateur namespaced remplace l’identificateur global. Alors :

<?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 déroutante inutilement puisque l’idée d’un const dans des dizaines de langages est qu’elle est toujours la même où que vous soyez dans votre code, et PHP ne le garantit pas vraiment.

15
slartibartfast

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

  1. Vous pouvez définir la portée de vos constantes en utilisant des espaces de noms.
  2. Vous pouvez utiliser le mot clé "const" en dehors des définitions de classe. Cependant, comme dans les classes, les valeurs attribué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 de variable, utilisez define () comme suit:

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

Oui, les const sont définis au moment de la compilation et, comme les états nikiques, aucune expression ne peut être affectée, contrairement à ce que peut définir (). Mais aussi les const ne peuvent pas être déclarés sous condition (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 revient pas vraiment à vos préférences personnelles, il existe une façon correcte et une mauvaise d'utiliser les deux.

En passant ... je voudrais voir une sorte de const de classe qui peut être assignée à une expression, une sorte de define () qui peut être isolé aux classes?

6
MrWhite

Pour ajouter la réponse de NikiC. const peut ê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().

5
Marcus Lind

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';

Avec define mot-clé constant, vous obtiendrez les facilités de cas
insensible mais avec le mot clé const 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
1
GaziAnis