define () vs. const


658

In PHP, quando usi

define('FOO', 1);

e quando lo usi

const FOO = 1;

?

Quali sono le principali differenze tra questi due?


4
Per quanto riguarda le prestazioni (perdita di tempo con la micro-ottimizzazione come me), vedi questa risposta : constè due volte più veloce di define. Informazioni sul tempo di caricamento della pagina e sull'utilizzo della memoria: vedi questa domanda e questo articolo ... Vedi anche qualcosa sulla cache opcode qui .
Peter Krauss,

2
Non guardare solo la risposta attualmente accettata, ma ti preghiamo di dare un'occhiata a stackoverflow.com/a/3193704/1412157 come avrebbe dovuto essere la risposta accettata
Luca M

1
Ho appena visto la notifica per il tuo commento. Ho aggiornato la risposta accettata.
danjarvis,

Risposte:


1039

A partire da PHP 5.3 ci sono due modi per definire le costanti : usare la constparola chiave o usare la define()funzione:

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

La differenza fondamentale tra questi due modi è che constdefinisce le costanti in fase di compilazione, mentre le definedefinisce in fase di esecuzione. Ciò causa la maggior parte constdegli svantaggi. Alcuni svantaggi di constsono:

  • constnon può essere utilizzato per definire in modo condizionale le costanti. Per definire una costante globale, deve essere utilizzata nell'ambito più esterno:

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

    Perché dovresti farlo comunque? Un'applicazione comune è verificare se la costante è già definita:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • constaccetta uno scalare statico (numero, una stringa o un altro costante come true, false, null, __FILE__), che define()prende qualsiasi espressione. Poiché anche in PHP 5.6 sono consentite espressioni costanti const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
    
  • constprende un semplice nome costante, mentre define()accetta qualsiasi espressione come nome. Ciò consente di fare cose del genere:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • constgli s sono sempre sensibili al maiuscolo / minuscolo, mentre define()consente di definire costanti senza distinzione tra maiuscole e minuscole passando truecome terzo argomento (Nota: la definizione di costanti senza distinzione tra maiuscole e minuscole è obsoleta a partire da PHP 7.3.0.):

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

Quindi, quello era il lato negativo delle cose. Ora diamo un'occhiata al motivo per cui uso sempre personalmente a constmeno che non si verifichi una delle situazioni sopra:

  • constlegge semplicemente meglio. È un costrutto di linguaggio anziché una funzione ed è anche coerente con il modo in cui si definiscono le costanti nelle classi.
  • const, essendo un costrutto linguistico, può essere analizzato staticamente con strumenti automatizzati.
  • constdefinisce una costante nello spazio dei nomi corrente, mentre define()deve essere passato il nome completo dello spazio dei nomi:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • Poiché le constcostanti di PHP 5.6 possono anche essere array, mentre define()non supporta ancora array. Tuttavia, le matrici saranno supportate per entrambi i casi in 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
    

Infine, si noti che constpuò essere utilizzato anche all'interno di una classe o interfaccia per definire una costante di classe o costante di interfaccia. definenon può essere utilizzato per questo scopo:

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

Sommario

A meno che tu non abbia bisogno di qualsiasi tipo di definizione condizionale o espressiva, usa consts invece di define()s - semplicemente per motivi di leggibilità!


1
Come so con PHP 5.6 avrai la possibilità di usare semplici espressioni scalari anche con il constcostrutto del linguaggio - vedi wiki.php.net/rfc/const_scalar_exprs
mabe.berlin

6
Un altro vantaggio dell'uso constè la mancanza di virgolette, il che significa che è formattato allo stesso modo in cui viene utilizzato nel tuo IDE.
Rybo111,

3
Questo dovrebbe essere quello che c'è nei documenti PHP. È la migliore spiegazione che ho visto, in particolare la parte che la maggior parte della gente dimentica (compilazione vs. runtime).
James,

4
define('a', $_GET['param']);, const b = a;funziona perfettamente e ottiene il valore mentre const c = $_GET['param'];non è valido. È constdavvero tempo di compilazione? Non credo proprio ... (testato su PHP 7.0.7)
mcserep il

1
wiki.php.net/rfc/case_insensitive_constant_deprecation " In PHP 8.0: Rimuovi la possibilità di dichiarare costanti senza distinzione tra maiuscole e minuscole. " per chiunque si avventuri qui nel futuro per quanto riguarda la distinzione tra maiuscole
Scuzzy,

196

Fino a PHP 5.3, constnon poteva essere utilizzato nell'ambito globale. Puoi usarlo solo all'interno di una classe. Questo dovrebbe essere usato quando si desidera impostare una sorta di opzione costante o impostazione relativa a quella classe. O forse vuoi creare una sorta di enum.

definepuò essere utilizzato per lo stesso scopo, ma può essere utilizzato solo nell'ambito globale. Dovrebbe essere utilizzato solo per le impostazioni globali che interessano l'intera applicazione.

Un esempio di buon constuso è sbarazzarsi dei numeri magici. Dai un'occhiata alle costanti DOP . Quando è necessario specificare un tipo di recupero, digitare PDO::FETCH_ASSOC, ad esempio. Se non si usassero i consessi, si finirebbe per digitare qualcosa del genere 35(o qualunque cosa FETCH_ASSOCsia definita come). Questo non ha senso per il lettore.

Un esempio di buon defineutilizzo è forse specificare il percorso radice dell'applicazione o il numero di versione di una libreria.


12
Potrebbe valere la pena menzionare l'uso di constcon namespace.
salathe il

31
Va anche notato che PHP5.3 può usare moltissimo const nell'ambito globale.
Gordon,

5.2 può anche. La bellezza di contro vs. definisce è che è necessario prefissarli con il nome della classe. Usarli rende il codice più leggibile e più bello. E questo è un vantaggio per me.
lucida

1
@ryeguy, ma dopo PHP 5.3 dove const può essere usato a livello globale proprio come definire?
andho,

1
@andho, segna un altro con la danza PHP di un passo avanti, un passo indietro, danza di "miglioramenti". Lui. :)
contratto del Prof. Falken è stato violato il

37

So che questa è già una risposta, ma nessuna delle risposte attuali menziona la spaziatura dei nomi e come influenza le costanti e le definizioni.

A partire da PHP 5.3, i consessi e le definizioni sono simili per la maggior parte degli aspetti. Vi sono tuttavia alcune importanti differenze:

  • I costi non possono essere definiti da un'espressione. const FOO = 4 * 3;non funziona, ma define('CONST', 4 * 3);funziona.
  • Il nome passato a definedeve includere lo spazio dei nomi da definire all'interno di quello spazio dei nomi.

Il codice seguente dovrebbe illustrare le differenze.

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

namespace {
    var_dump(get_defined_constants(true));
}

Sarà il contenuto dell'array secondario dell'utente ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== AGGIORNAMENTO ===

Il prossimo PHP 5.6 consentirà un po 'più di flessibilità con const. Ora sarai in grado di definire i consessi in termini di espressioni, a condizione che quelle espressioni siano costituite da altri consensi o letterali. Ciò significa che quanto segue dovrebbe essere valido dal 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;

Tuttavia, non sarai ancora in grado di definire i costi in termini di variabili o ritorni di funzioni

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

sarà ancora fuori.


8
Non ho resistito a chiedere: hai definito consapevolmente FORTY_TWOcome 54?
Punchlinern,

9
"Sei per nove? Quarantadue? Ho sempre detto che c'era qualcosa di fondamentalmente sbagliato nell'universo" Dai un'occhiata alle opere di Douglas Adams se hai bisogno di una spiegazione completa.
GordonM,

2
Oh. Ero consapevole del fatto che 42 è la risposta vita, universo e tutto, ma mi mancava il Sei in nove parti. Grazie per la spiegazione!
Punchlinern,


20

define Uso per le costanti globali.

const Uso per le costanti di classe.

Non puoi definerientrare nell'ambito della classe, e con constte puoi. Inutile dire che non è possibile utilizzare un constambito di classe esterna.

Inoltre, con const, diventa effettivamente un membro della classe e con define, verrà spinto a livello globale.


8
Come notato in altre risposte, const può essere usato al di fuori delle lezioni in PHP 5.3+
MrWhite

Solo la parola chiave const può essere utilizzata per creare una costante con spaziatura dei nomi, non solo classi
Alireza Rahmani Khalili

16

La risposta di NikiC è la migliore, ma lasciami aggiungere un avvertimento non ovvio quando usi gli spazi dei nomi in modo da non rimanere sorpreso da comportamenti inaspettati. La cosa da ricordare è che le definizioni sono sempre nello spazio dei nomi globale a meno che non si aggiunga esplicitamente lo spazio dei nomi come parte dell'identificatore di definizione. Ciò che non è ovvio al riguardo è che l'identificatore con spaziatura dei nomi supera l'identificatore globale. Così :

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

produce:

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

Il che per me rende l'intera nozione inutilmente confusa poiché l'idea di una const in dozzine di altre lingue è che è sempre la stessa ovunque tu sia nel tuo codice, e PHP non lo garantisce davvero.


1
Sì, ma BARe \foo\BARsono solo , non le stesse costanti. Sono d'accordo che è davvero confuso, ma se consideri che cose come la logica dello spazio dei nomi siano coerenti in questo modo, e che né constdefine()è né come una macro C ( #define), allora PHP può avere qualche scusa.
Sz.

1
La const const è esattamente il modo in cui dovrebbe comportarsi: sei in uno spazio dei nomi! Lo vuoi senza l'identificatore dello spazio dei nomi, quindi crealo al di fuori dello spazio dei nomi. Ciò lo rende anche coerente con la const definita in una classe, anche se utilizza una sintassi diversa. Sì, anche la definizione è coerente, in modo diverso.
Gerard ONeill,

12

Molte di queste risposte sono sbagliate o raccontano solo metà della storia.

  1. Puoi ambito le tue costanti usando gli spazi dei nomi.
  2. È possibile utilizzare la parola chiave "const" al di fuori delle definizioni di classe. Tuttavia, proprio come nelle classi, i valori assegnati usando la parola chiave "const" devono essere espressioni costanti.

Per esempio:

const AWESOME = 'Bob'; // Valid

Cattivo esempio:

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

Per creare costanti di variabili usa define () in questo modo:

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

1
PHP> = 5.6 sono state apportate alcune modifiche al compilatore di Zend Engine e const viene ora trattato in un altro modo.
Ankit Vishwakarma,

6

Sì, const è definito in fase di compilazione e poiché agli stati nikic non è possibile assegnare un'espressione, come può definire (). Ma anche le const non possono essere dichiarate condizionatamente (per lo stesso motivo). vale a dire. Non puoi farlo:

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

Considerando che potresti con un define (). Quindi, non si riduce davvero alle preferenze personali, c'è un modo corretto e un modo sbagliato di usare entrambi.

A parte questo ... Vorrei vedere un tipo di const di classe a cui può essere assegnata un'espressione, una sorta di define () che può essere isolata alle classi?


5

Per aggiungere la risposta di NikiC. constpuò essere utilizzato all'interno delle classi nel modo seguente:

class Foo {
    const BAR = 1;

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

Non puoi farlo con define().


4

Nessuno dice nulla su php-doc, ma per me questo è anche un argomento molto significativo per la preferenza di const:

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

0

Con la definizione della costante di parola chiave, otterrai le funzionalità di maiuscole e minuscole, ma con la parola chiave const no.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.