php - define () contra const


Pregunta bastante simple: en PHP, ¿cuándo usas

define('FOO', 1);

y cuando usas

const FOO = 1;

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


Answers



A partir de PHP 5.3 hay dos formas de definir constantes : ya sea usando la palabra clave const o usando la función define() :

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

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

  • const no se puede usar para definir condicionalmente las 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 comprobar si la constante ya está definida:

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

    const BIT_5 = 1 << 5;    // valid since PHP 5.6, invalid previously
    define('BIT_5', 1 << 5); // always valid
  • const toma un nombre de 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);
    }
  • const s siempre son sensibles a mayúsculas y minúsculas, mientras que define() permite definir constantes insensibles a mayúsculas y minúsculas pasando el true como tercer argumento:

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

Entonces, ese era el lado malo de las cosas. Ahora veamos la razón por la que personalmente siempre uso const menos que ocurra una de las situaciones anteriores:

  • const simplemente lee mejor. Es una construcción de lenguaje en lugar de una función y también es consistente con la forma en que define las constantes en las clases.
  • const define una constante en el espacio de nombre actual, mientras que define() tiene que pasar 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');
  • Como las constantes const PHP 5.6 también pueden ser matrices, mientras que define() aún no admite matrices. Sin embargo, las matrices serán compatibles con 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, valid in PHP 7.0
  • Como las estructuras son construcciones de lenguaje y se definen en el momento de la compilación, son un poco más rápidas que define() s.

    Es bien sabido que PHP define() s es lento cuando se usa una gran cantidad de constantes. La gente incluso ha inventado cosas como apc_load_constants() y hidef para evitar esto.

    const s hacen que la definición de constantes sea aproximadamente el doble de rápida (en las máquinas de desarrollo con XDebug activado aún más). El tiempo de búsqueda, por otro lado, no cambia (ya que ambos tipos constantes comparten la misma tabla de búsqueda): Demo .

Finalmente, tenga en cuenta que const también se puede usar dentro de una clase o interfaz para definir una constante de clase o constante de interfaz. define no 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 cualquier tipo de definición condicional o de expresión, use const s en lugar de define() s - ¡simplemente por el bien de la legibilidad!




Hasta PHP 5.3, const no se podía usar en el ámbito global. Solo puedes usar esto desde dentro de 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.

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

Un ejemplo de buen uso de const es deshacerse de los números mágicos. Eche un vistazo a las constantes de PDO . Cuando necesite especificar un tipo de búsqueda, debería escribir PDO::FETCH_ASSOC , por ejemplo. Si no se usan consts, terminarás escribiendo algo así como 35 (o lo que sea que FETCH_ASSOC se defina como). Esto no tiene sentido para el lector.

Un ejemplo de uso de buena define es tal vez especificar la ruta raíz de su aplicación o el número de versión de una biblioteca.




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

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

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

El siguiente código debe 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 del 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 otras consts o literales. Esto significa que lo siguiente debe 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, todavía no podrás definir consts en términos de variables o funciones, por lo que

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

todavía estará fuera.







define uso para constantes globales.

const uso para constantes de clase.

No puedes define en el alcance de la clase, y con const puedes. Huelga decir que no puede usar const fuera del alcance de la clase

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




La respuesta de NikiC es la mejor, pero permíteme agregar una advertencia no obvia al usar espacios de nombres para que no te atrapen con un comportamiento inesperado. Lo que hay que recordar es que define 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 supera al identificador global. Asi que :

<?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 cual para mí hace que toda la noción de concisión sea innecesariamente confusa, ya que la idea de una constante en docenas de otros lenguajes es que siempre es igual dondequiera que se encuentre en su código, y PHP realmente no lo garantiza.




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

  1. Puede delimitar sus constantes usando 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 de variables, use define () de la siguiente manera:

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



Sí, const se define en tiempo de compilación y como estados nikic no pueden asignarse una expresión, como define () 's puede. Pero también const no se puede 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 (). Entonces, realmente no se reduce a las preferencias personales, hay una forma correcta y una incorrecta de usar ambas.

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




Para agregar la respuesta de NikiC. const se 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() .