Monday, June 11, 2012

define() vs const


Pretty straightforward question: In PHP, do you prefer to do (and why):




define('FOO', 1);



OR




const FOO = 1;



Also, the code is NOT in a class.



Thanks.


Source: Tips4all

8 comments:

  1. Until PHP 5.3, const could not be used in the global scope. You could only use this from within a class. This should be used when you want to set some kind of constant option or setting that pertains to that class. Or maybe you want to create some kind of enum.

    define can be used for the same purpose, but it can only be used in the global scope. It should only be used for global settings that affect the entire application.

    An example of good const usage is to get rid of magic numbers. Take a look at PDO's constants. When you need to specify a fetch type, you would type PDO::FETCH_ASSOC, for example. If consts were not used, you'd end up typing something like 35 (or whatever FETCH_ASSOC is defined as). This makes no sense to the reader.

    An example of good define usage is maybe specifying your application's root path or a library's version number.

    ReplyDelete
  2. As of PHP 5.3 there are two ways to define constants: Either using the const keyword or using the define() function:

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


    The fundamental difference between those two ways is that const defines constants at compile time, whereas define defines them at run time. What does that mean for you?


    const cannot be used to conditionally define constants. It has to be used in the outermost scope:

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


    Why would you want to do that anyways? One common application is to check whether the constant is already defined:

    if (!defined('FOO')) {
    define('FOO', 'BAR');
    }

    const accepts a static scalar (number, string or other constant like true, false, null, __FILE__), whereas define() takes any expression:

    const BIT_5 = 1 << 5; // invalid
    define('BIT_5', 1 << 5); // valid

    const takes a plain constant name, whereas define() accepts any expression as name. This allows to do things like this:

    for ($i = 0; $i < 32; ++$i) {
    define('BIT_' . $i, 1 << $i);
    }

    consts are always case sensitive, whereas define() allows you to define case insensitive constants by passing true as the third argument:

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



    So, that was the bad side of things. Now let's look at the reason why I personally always use const unless one of the above situations occurs:


    const simply reads nicer. It's a language construct instead of a function and also is consistent with how you define constants in classes.
    As consts are language constructs and defined at compile time they are a bit faster than define()s.

    It is well known that PHP define()s are slow when using a large number of constants. People have even invented things like apc_load_constants() and hidef to get around this.

    consts make the definition of constants approximately twice as fast (on development machines with XDebug turned on even more). Lookup time on the other hand does not change (as both constant types share the same lookup table): Demo.


    Summary

    Unless you need any type of conditional or expressional definition, use consts instead of define()s - simply for the sake of readability!

    ReplyDelete
  3. I believe that as of PHP 5.3, you can use const outside of classes, as shown here in the second example:

    http://www.php.net/manual/en/language.constants.syntax.php

    <?php
    // Works as of PHP 5.3.0
    const CONSTANT = 'Hello World';

    echo CONSTANT;
    ?>

    ReplyDelete
  4. define i use for global constants.

    const i use for class constants.

    You cannot define into class scope, and with const you can.
    Needless to say, you cannot use const outside class scope

    Also, with const, it actually becomes a member of the class, with define, it will be pushed to global scope.

    ReplyDelete
  5. I know this is already answered, but none of the current answers make any mention of namespacing and how it affects constants and defines.

    As of PHP 5.3, consts and defines are similar in most respects. There are still, however, some important differences:


    Consts cannot be defined from an expression. const FOO = 4 * 3; doesn't work, but define('CONST', 4 * 3); does.
    The name passed to define must include the namespace to be defined within that namespace.


    The code below should illustrate the differences.

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

    namespace {
    var_dump(get_defined_constants(true));
    }


    The content of the user sub-array will be ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3].

    ReplyDelete
  6. Yes, const are defined at compile-time and as nikic states cannot be assigned an expression, as define()'s can. But also const's cannot be conditionally declared (for the same reason). ie. You cannot do this:

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


    Whereas you could with a define(). So, it doesn't really come down to personal preference, there is a correct and a wrong way to use both.

    As an aside... I would like to see some kind of class const that can be assigned an expression, a sort of define() that can be isolated to classes?

    ReplyDelete
  7. define is general purpose and const can be used in classes.

    ReplyDelete
  8. NikiC's answer is the best, but let me add a non-obvious caveat when using namespaces so you don't get caught with unexpected behavior. The thing to remember is that defines are always in the global namespace unless you explicitly add the namespace as part of the define identifier. What isn't obvious about that is that the namespaced identifier trumps the global identifier. So :

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


    produces:

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


    Which to me makes the whole const notion needlessly confusing since the idea of a const in dozens of other languages is that it is always the same wherever you are in your code, and PHP doesn't really guarantee that.

    ReplyDelete