skip to content

In PHP, what is the difference between defining a global constant with define() and with the const keyword?

level: middleimportance: must knowfreq 62%

answer

  1. compile-time statement vs runtime function call
  2. top level only vs anywhere
  3. current namespace prefix applied or not
  4. constant expression vs any runtime value
  5. define() returns bool; third argument ignored

basics

~20 s

const is a top-level statement with a constant-expression value, prefixed with the current namespace. define() is a function call that runs anywhere, accepts any runtime value and uses its string name exactly as given, with no namespace prefix.

solid answer

~50 s

`const TAX_RATE = 0.2;` is a **statement**: it may only appear at the top level of a file (not inside a function, `if`, loop or `try`), its value must be a **constant expression**, and its name is prefixed with the current namespace, so inside `namespace App\Payroll` it declares `App\Payroll\TAX_RATE`. `define('TAX_RATE', $rate)` is an ordinary **function call**: it can run inside a function or behind an `if`, its value can be anything computed at runtime (since PHP 8.1 even an object), and its name string is used verbatim, so it declares a global `TAX_RATE` unless you spell the namespace into the string. `define()` returns `true`, or `false` with a warning when the name is taken, and its old third argument no longer makes constants case-insensitive. Use `const` by default and `define()` for conditional or computed constants.

code

php · 16 lines
php
<?php
declare(strict_types=1);

namespace App\Payroll;

const API_VERSION = 'v2';   // declares App\Payroll\API_VERSION
const TAX_RATE = 0.2;       // declares App\Payroll\TAX_RATE

if (!\defined('PAYROLL_DEBUG')) {
    // define() may run inside a block; the name is global as written
    \define('PAYROLL_DEBUG', getenv('PAYROLL_DEBUG') === '1');
}

echo API_VERSION, PHP_EOL;                    // v2
var_dump(\defined('App\Payroll\TAX_RATE'));  // bool(true)
var_dump(\defined('TAX_RATE'));               // bool(false)

go deeper

for a junior

Know the two syntaxes and that const only works at the top level of a file, while define() works anywhere, including inside an if block.

for a middle

Explain the three mechanical differences: statement versus function call, constant expression versus runtime value, and namespace prefixing versus a verbatim string name.

for a senior

Show you can spot the namespace trap in review, where define() and const create two different constants, and justify const as the default for payroll-style configuration.

for a principal

Treat global constants as a configuration policy: when a value belongs in a constant at all versus injected configuration, and how to keep them namespaced and analysable.

## Two ways to make a global constant A PHP **constant** is a name bound once to a value that cannot be changed or removed for the rest of the request. Constants have no `$` sign, are case-sensitive, and are visible from every scope without `global`. PHP gives you two ways to create one outside a class: - the **`const` statement**: `const API_VERSION = 'v2';` - the **`define()` function**: `define('API_VERSION', 'v2');` Both produce the same kind of constant, read the same way (`echo API_VERSION;`). The differences are all about *when*, *where* and *under what name* the constant is created. Class constants are a separate feature declared with `const` inside a class body; this answer is about global (non-class) constants. ## The differences at a glance | Aspect | `const` | `define()` | |---|---|---| | Kind of construct | language statement | function, `define(string $constant_name, mixed $value, bool $case_insensitive = false): bool` | | Where it may appear | top level of a file or namespace block only | anywhere code runs: functions, `if` blocks, loops | | Value | a **constant expression** (literals, operators, other constants, enum cases, `new` since 8.1, casts and static closures since 8.5) | any value computed at runtime, including function results; objects since PHP 8.1 | | Name | fixed identifier, prefixed with the **current namespace** | a string used exactly as written; can be built dynamically | | Failure on a taken name | warning, first value kept | warning, returns `false`, first value kept | ## Where each form is allowed `const` is part of PHP's grammar for **top-level statements**. Writing it inside a function body, an `if`, a loop or a `try` block is a parse error, because those blocks only accept inner statements. That rule is why interviewers ask "which form works in a conditional block?": only `define()` does. ```php if (!defined('PAYROLL_DEBUG')) { define('PAYROLL_DEBUG', getenv('PAYROLL_DEBUG') === '1'); // fine // const PAYROLL_DEBUG = false; // ParseError: unexpected token "const" } ``` Two nuances are worth knowing: 1. "Compile-time" describes the **name and value expression**, which are fixed when the file is compiled. The constant itself is registered when execution reaches the statement, so using it on an earlier line of the same file still fails. 2. A file that is `include`d is compiled as its own top level, so a `const` inside an included file works even when the `include` itself sits in a function or behind an `if`. ## Values: constant expression versus anything The right-hand side of `const` must be a **constant expression**, something the engine can evaluate without running arbitrary code: - scalars, arrays and operators: `const MONTHLY_CAP = 12 * 1000;` - other constants and enum cases: `const DEFAULT_RATE = TAX_RATE / 2;` - `new SomeClass(...)` for global constants since PHP 8.1 - casts, static closures and first-class callables since PHP 8.5 A function call such as `const LOADED_AT = time();` fails with "Constant expression contains invalid operations". `define()` has no such limit: `define('LOADED_AT', time());` is fine because the argument is an ordinary runtime expression. ## Names and namespaces Inside `namespace App\Payroll;`, `const TAX_RATE = 0.2;` declares **`App\Payroll\TAX_RATE`**: the compiler prefixes the name. `define('TAX_RATE', 0.2)` declares a **global** `TAX_RATE`, because a string name is always treated as fully qualified. To make a namespaced constant with `define()` you spell the namespace in the string, for example `define(__NAMESPACE__ . '\\TAX_RATE', 0.2)`. Mixing the two forms by accident produces two different constants that happen to share a short name. ## Leftovers from older PHP - The third parameter of `define()`, `$case_insensitive`, used to create case-insensitive constants. Since **PHP 8.0**, passing `true` only emits a warning that the argument is ignored; all user constants are case-sensitive. - `define()` rejects class-constant names: `define('Payroll::RATE', 1)` throws a `ValueError`. Class constants are only declared with `const` inside a class. ## Which one to choose - Prefer **`const`** for fixed configuration such as `API_VERSION` and `TAX_RATE`: it is namespace-aware, visible to static analysis, and fails loudly when misplaced. - Use **`define()`** when the name or value is only known at runtime, or when the constant must be created conditionally, typically guarded with `defined()`.

  • Can a const statement be used inside a function if the constant is only needed there?
    No. `const` is only allowed at the top level of a file or namespace block, so inside a function it is a parse error. Inside a function you either call `define()`, which creates a global constant when the line runs, or, more often, use a local variable or a class constant instead.
  • Why does const TAX_RATE = round(0.2049, 2); fail while define() with the same value works?
    The value of `const` must be a constant expression, and a function call is not one, so compilation stops with "Constant expression contains invalid operations". `define()` is a normal function call whose arguments are evaluated at runtime, so `round()` runs first and its result is stored.
  • What does passing true as the third argument of define() do in PHP 8.5?
    Nothing useful. Since PHP 8.0 case-insensitive user constants no longer exist, so `true` there only raises a warning saying the argument is ignored, and the constant is created case-sensitive as usual. Passing `false`, or omitting it, is silent.

saying these in an interview costs you the question

  • Says const can be used inside an if block to define a constant conditionally.
  • Believes define() inside a namespace creates a constant in that namespace.
  • Claims const accepts any runtime value, such as a function call result.
  • Thinks define() with true as the third argument still makes a case-insensitive constant.
  • Says a constant defined with define() can be redefined later with a new value.