define () vs.const

658

En PHP, ¿cuándo usas

define('FOO', 1);

y cuando usas

const FOO = 1;

?

¿Cuáles son las principales diferencias entre esos dos?

danjarvis
fuente
44
Sobre el rendimiento (pérdida de tiempo con micro-optimización como yo), vea esta respuesta : constes dos veces más rápido que define. Acerca del tiempo de carga de la página y el uso de la memoria: vea esta pregunta y este artículo ... Vea también algo sobre el código de memoria caché aquí .
Peter Krauss
2
No mire solo la respuesta aceptada actual, sino que consulte stackoverflow.com/a/3193704/1412157, ya que debería haber sido la respuesta aceptada
LucaM
1
Acabo de ver la notificación de tu comentario. He actualizado la respuesta aceptada.
danjarvis

Respuestas:

1039

A partir de PHP 5.3, hay dos formas de definir constantes : utilizando la constpalabra clave o utilizando la define()función:

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

La diferencia fundamental entre esas dos formas es que constdefine constantes en tiempo de compilación, mientras que las definedefine en tiempo de ejecución. Esto causa la mayoría de constlas desventajas. Algunas desventajas de constson:

  • constno se puede usar para definir condicionalmente constantes. Para definir una constante global, debe usarse en el ámbito más externo:

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

    ¿Por qué querrías hacer eso de todos modos? Una aplicación común es verificar si la constante ya está definida:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • constacepta un escalar estático (número, cadena o cualquier otra constante como true, false, null, __FILE__), mientras que define()toma cualquier expresión. Como PHP 5.6 también se permiten expresiones constantes const:

    const BIT_5 = 1 << 5;    // Valid since PHP 5.6 and invalid previously
    define('BIT_5', 1 << 5); // Always valid
    
  • consttoma un nombre constante simple, mientras que define()acepta cualquier expresión como nombre. Esto permite hacer cosas como esta:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • consts siempre distingue entre mayúsculas y minúsculas, mientras define()que le permite definir constantes que no distinguen entre mayúsculas y minúsculas pasando truecomo tercer argumento (Nota: la definición de constantes que distinguen mayúsculas de minúsculas es obsoleta a partir de PHP 7.3.0):

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

Entonces, ese era el lado malo de las cosas. Ahora echemos un vistazo a la razón por la que personalmente siempre uso a constmenos que ocurra una de las situaciones anteriores:

  • constsimplemente se lee mejor. Es una construcción de lenguaje en lugar de una función y también es coherente con la forma en que define constantes en las clases.
  • const, al ser una construcción de lenguaje, puede analizarse estáticamente mediante herramientas automatizadas.
  • constdefine una constante en el espacio de nombres actual, mientras define()que debe pasarse el nombre completo del espacio de nombres:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • Dado que las constconstantes de PHP 5.6 también pueden ser matrices, define()aún no son compatibles. Sin embargo, las matrices serán compatibles para ambos casos 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
    

Finalmente, tenga en cuenta que consttambién se puede usar dentro de una clase o interfaz para definir una constante de clase o constante de interfaz. defineno se puede usar para este propósito:

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

Resumen

A menos que necesite algún tipo de definición condicional o expresiva, use consts en lugar de define()s, ¡simplemente por razones de legibilidad!

NikiC
fuente
1
Como sé con PHP 5.6, tendrá la posibilidad de usar expresiones escalares simples incluso con la constconstrucción del lenguaje - vea wiki.php.net/rfc/const_scalar_exprs
mabe.berlin
66
Otro beneficio de usar constes la falta de comillas, lo que significa que está formateado de la misma manera que se usa en su IDE.
rybo111
3
Esto debería ser lo que hay en los documentos PHP. Es la mejor explicación que he visto, especialmente la parte que la mayoría de la gente olvida (compilación versus tiempo de ejecución).
James
44
define('a', $_GET['param']);, const b = a;funciona perfectamente y obtiene el valor mientras const c = $_GET['param'];no es válido. ¿ constRealmente es tiempo de compilación? Apenas lo creo ... (probado en PHP 7.0.7)
mcserep
1
wiki.php.net/rfc/case_insensitive_constant_deprecation " En PHP 8.0: Eliminar la posibilidad de declarar constantes entre mayúsculas y minúsculas. " para cualquier otra persona aventurarse aquí en el futuro en lo que respecta a mayúsculas y minúsculas
Scuzzy
196

Hasta PHP 5.3, constno se podía utilizar en el ámbito global. Solo puedes usar esto desde una clase. Esto debe usarse cuando desee establecer algún tipo de opción constante o configuración que pertenezca a esa clase. O tal vez quieras crear algún tipo de enumeración.

definepuede usarse para el mismo propósito, pero solo puede usarse en el ámbito global. Solo debe usarse para configuraciones globales que afectan a toda la aplicación.

Un ejemplo de buen constuso es deshacerse de los números mágicos. Echa un vistazo a las constantes de PDO . Cuando necesite especificar un tipo de búsqueda, escriba PDO::FETCH_ASSOC, por ejemplo. Si no se usaran const, terminaría escribiendo algo como 35(o lo que FETCH_ASSOCse define como). Esto no tiene sentido para el lector.

Un ejemplo de buen defineuso es quizás especificar la ruta raíz de su aplicación o el número de versión de una biblioteca.

ryeguy
fuente
12
Vale la pena mencionar el uso de constcon espacios de nombres.
salathe
31
También se debe tener en cuenta que PHP5.3 puede usar mucho const en el ámbito global.
Gordon
5.2 puede también. La belleza de consts vs define es que debe prefijarlos con el nombre de la clase. Usarlos hace que el código sea más legible y más bonito. Y eso es un extra para mí.
lucifurious
1
@ryeguy, pero ¿qué pasa después de PHP 5.3, donde const se puede usar globalmente como definir?
andho
1
@andho, apunta otro al baile PHP de un paso adelante, un paso atrás, baile de "mejoras". Él. :)
contrato del Prof. Falken incumplió
37

Sé que esto ya está respondido, pero ninguna de las respuestas actuales menciona el espacio de nombres y cómo afecta a las constantes y las definiciones.

A partir de PHP 5.3, los consts y define son similares en la mayoría de los aspectos. Sin embargo, todavía hay algunas diferencias importantes:

  • Los concursos no se pueden definir a partir de una expresión. const FOO = 4 * 3;no funciona, pero lo define('CONST', 4 * 3);hace.
  • El nombre pasado definedebe incluir el espacio de nombres que se definirá dentro de ese espacio de nombres.

El siguiente código debería ilustrar las diferencias.

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

namespace {
    var_dump(get_defined_constants(true));
}

El contenido de la sub-matriz de usuario será ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

=== ACTUALIZACIÓN ===

El próximo PHP 5.6 permitirá un poco más de flexibilidad con const. Ahora podrá definir consts en términos de expresiones, siempre que esas expresiones estén formadas por otros consts o literales. Esto significa que lo siguiente debería ser válido a 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;

Sin embargo, aún no podrá definir consts en términos de variables o retornos de funciones, por lo que

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

Todavía estará fuera.

GordonM
fuente
8
No pude resistir preguntar: ¿Te definiste conscientemente FORTY_TWOcomo 54?
Punchlinern
99
"¿Seis por nueve? ¿Cuarenta y dos? Siempre dije que había algo fundamentalmente incorrecto en el universo" Echa un vistazo a las obras de Douglas Adams si necesitas una explicación completa.
GordonM
2
Oh. Sabía que 42 es la respuesta de la vida, el universo y todo, pero me había perdido el Six por nueve partes. ¡Gracias por la explicación!
Punchlinern
20

define Yo uso para constantes globales.

const Yo uso para constantes de clase.

No puede defineentrar en el alcance de la clase, y con constusted puede. No hace falta decir que no se puede usar constfuera del alcance de la clase.

Además, con const, en realidad se convierte en un miembro de la clase, y con define, será llevado a un alcance global.

Jacob Relkin
fuente
8
Como se señaló en otras respuestas, const se puede usar fuera de las clases en PHP 5.3+
MrWhite
Solo la palabra clave const se puede usar para crear una constante de espacio de nombres, no solo clases
Alireza Rahmani Khalili
16

La respuesta de NikiC es la mejor, pero permítame agregar una advertencia no obvia cuando use espacios de nombres para que no se vea atrapado con un comportamiento inesperado. Lo que debe recordar es que las definiciones siempre están en el espacio de nombres global a menos que agregue explícitamente el espacio de nombres como parte del identificador de definición. Lo que no es obvio al respecto es que el identificador de espacio de nombres prevalece sobre el identificador global. Entonces :

<?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

Lo que para mí hace que toda la noción constante sea innecesariamente confusa, ya que la idea de una constante en docenas de otros idiomas es que siempre es lo mismo donde sea que esté en su código, y PHP realmente no garantiza eso.

slartibartfast
fuente
1
Sí, pero BARy \foo\BARson sólo no las mismas constantes. Estoy de acuerdo en que es realmente confuso, pero si también considera que cosas como la lógica del espacio de nombres son consistentes de esta manera, y que ni consttampoco define()es como una macro C ( #define), entonces PHP puede tener alguna excusa.
Sz.
1
La noción constante es exactamente la forma en que debería comportarse: ¡estás en un espacio de nombres! Lo desea sin el identificador de espacio de nombres, luego créelo fuera del espacio de nombres. Esto también lo hace coherente con el const que se define en una clase, incluso si usa una sintaxis diferente. Sí, definir también es consistente, de una manera diferente.
Gerard ONeill
12

La mayoría de estas respuestas son incorrectas o solo cuentan la mitad de la historia.

  1. Puede determinar sus constantes mediante el uso de espacios de nombres.
  2. Puede usar la palabra clave "const" fuera de las definiciones de clase. Sin embargo, al igual que en las clases, los valores asignados con la palabra clave "const" deben ser expresiones constantes.

Por ejemplo:

const AWESOME = 'Bob'; // Valid

Mal ejemplo:

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

Para crear constantes variables use define () así:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid
AwesomeBobX64
fuente
1
PHP> = 5.6 se han realizado algunos cambios en Zend Engine Compiler y ahora const está siendo tratado de otra manera.
Ankit Vishwakarma
6

Sí, los const se definen en tiempo de compilación y como a los estados nikic no se les puede asignar una expresión, como se puede definir (). Pero también los const no se pueden declarar condicionalmente (por la misma razón). es decir. No puedes hacer esto:

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

Mientras que podría con un define (). Por lo tanto, en realidad no se trata de preferencias personales, hay una forma correcta y una incorrecta de usar ambos.

Como comentario aparte, me gustaría ver algún tipo de constante de clase a la que se le pueda asignar una expresión, una especie de define () que se pueda aislar a las clases.

Señor White
fuente
5

Para agregar a la respuesta de NikiC. constse puede usar dentro de las clases de la siguiente manera:

class Foo {
    const BAR = 1;

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

No puedes hacer esto con define().

Marcus Lind
fuente
4

Nadie dice nada sobre php-doc, pero para mí eso también es un argumento muy significativo para la preferencia de const:

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

Con la definición de la palabra clave constante, obtendrá las facilidades de mayúsculas y minúsculas, pero con la palabra clave constante 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
GaziAnis
fuente