プログラムの中で「あとから変わってほしくない値」を扱いたい場面はよくあります。たとえばサイトの URL、データベースの接続情報、消費税率など、一度決めたら勝手に書き換わっては困る値です。こうした値を保持するのが PHP の定数で、定義の方法として define 関数と const キーワードの2つが用意されています。この記事では、定数とは何かというところから、define と const それぞれの使い方、両者の違い、そしてクラス定数やマジック定数までを、初心者〜中級者の方向けに解説します。
目次
そもそも定数とは何か
定数とは、一度定義したら再代入できない値のことです。変数($name)は途中で何度でも中身を書き換えられますが、定数は最初に決めた値をプログラムの終わりまで保ち続けます。うっかり別の値を入れてしまう事故を防げるので、設定値のように「変わってはいけない値」に向いています。
変数との見た目の違いとして、定数の名前には先頭の $ を付けません。また、名前はすべて大文字にするのが慣習です(SITE_URL のように単語の区切りはアンダースコアでつなぎます)。これは PHP の文法上の決まりではなく読みやすさのための習慣ですが、コードを見た人が「これは定数だ」とすぐ判断できるので、特別な理由がない限り従っておくとよいでしょう。
define で定数を定義する
もっとも基本的な定義方法が define 関数です。書式は define(string $constant_name, mixed $value) で、第1引数に定数名(文字列)、第2引数にその値を渡します。定義した定数は、名前をそのまま書くだけで参照できます。
<?php
// 定数を定義する
define('SITE_URL', 'https://example.com');
define('TAX_RATE', 0.1);
// 参照するときは $ を付けず、名前をそのまま書く
echo SITE_URL; // https://example.com
echo 1000 * (1 + TAX_RATE); // 1100
// 定数への再代入はできない
// SITE_URL = 'https://other.com'; // これは文法エラー
define の大きな特徴は、実行時に評価されることです。そのため、条件分岐やループの中でも呼び出せますし、第2引数には計算式や関数の戻り値を渡すこともできます。動作環境によって値を切り替えたいといった、動きのある定義に向いています。
<?php
// 条件分岐の中で定義できる(実行時に評価される)
if (getenv('APP_ENV') === 'production') {
define('DEBUG_MODE', false);
} else {
define('DEBUG_MODE', true);
}
// 関数の戻り値や式もそのまま値にできる
define('CACHE_DIR', __DIR__ . '/cache');
define('MAX_ITEMS', 10 * 5);
echo CACHE_DIR; // 実行中のファイルのディレクトリ + /cache
第3引数(大文字小文字の区別)は使わない
古いコードでは、define の第3引数に true を渡して「大文字小文字を区別しない定数」を作っている例を見かけることがあります。しかし、この case-insensitive(大文字小文字を無視する)定数の機能は PHP 7.3 で非推奨となり、PHP 8.0 で完全に廃止されました。現在の PHP では第3引数に true を渡すこと自体がエラーになります。定数名は常に大文字小文字を区別する、と理解しておけば問題ありません。新しくコードを書くときに第3引数を使う理由はありません。
const で定数を定義する
もう一つの方法が const キーワードです。const NAME = value; のように、変数への代入に似た書き方で定義します。define よりも見た目がすっきりしており、クラスの中で定数を定義するときにも使える点が特徴です。
<?php
// const キーワードで定義する
const SITE_NAME = 'webool';
const VERSION = '2.0.0';
echo SITE_NAME; // webool
echo VERSION; // 2.0.0
const はコンパイル時に定義されるため、書ける場所に制約があります。具体的には、名前空間のトップレベルか、クラス・インターフェイスの内部でしか使えません。if などの条件分岐やループ、関数の中では使えないのです。この点が define との一番大きな違いになります。
<?php
// これは NG。条件分岐の中では const は使えない
if (true) {
const FOO = 'bar'; // Parse error になる
}
// こうしたいときは define を使う
if (true) {
define('FOO', 'bar'); // OK
}
値に指定できるものにも違いがあります。かつて const には定数式(リテラルや、すでに定義済みの定数を組み合わせた式など)しか書けませんでした。PHP 8.0 以降は式の扱いが緩和され、他の定数を参照した簡単な演算などは書けますが、それでも実行時に決まる値(関数の戻り値など)は基本的に渡せません。動的に決まる値を持たせたいなら define を選びます。
define と const はどう使い分けるか
ここまで見てきた両者の違いを、表で整理しておきます。ポイントは「いつ評価されるか(コンパイル時か実行時か)」で、そこから使える場所や値が決まってきます。
| 観点 | define | const |
|---|---|---|
| 評価のタイミング | 実行時 | コンパイル時 |
| 書ける場所 | どこでも(条件分岐・ループ・関数内も可) | トップレベルまたはクラス/インターフェイス内のみ |
| 条件分岐の中での定義 | できる | できない |
| 値に渡せるもの | 式・関数の戻り値など動的な値も可 | 基本は定数式(PHP 8.0+ で式は緩和されるが実行時の値は不可) |
| クラス定数の定義 | 不可 | 可(クラス内で使う) |
| 名前空間の扱い | 名前を文字列で指定するため注意が必要 | 現在の名前空間に属する |
実際の使い分けとしては、条件によって値を切り替えたい、あるいは計算結果や環境変数を定数にしたいときは define、単純に固定値を宣言するだけ・クラスの中で定数を持ちたいときは const、と覚えておけばほとんどの場面で困りません。どちらか一方に統一するより、性質に合わせて選ぶのが自然です。
定義済みかどうかを defined で確認する
まだ定義されていない定数を参照すると、PHP 8.0 以降は Error が発生します(それより前は警告のうえ定数名の文字列として扱われました)。同じ定数を二重に define しようとしても警告が出ます。そこで、定義済みかどうかを事前に調べたいときは defined 関数を使います。引数に定数名を文字列で渡すと、定義済みなら true、未定義なら false を返します。
<?php
// まだ定義されていなければ定義する(二重定義の警告を防ぐ)
if (!defined('SITE_URL')) {
define('SITE_URL', 'https://example.com');
}
var_dump(defined('SITE_URL')); // bool(true)
var_dump(defined('UNKNOWN')); // bool(false)
WordPress の wp-config.php などで if (!defined('ABSPATH')) のような書き方をよく見かけますが、これはまさに「まだ定義されていなければ定義する」というパターンです。設定ファイルが複数回読み込まれても安全にするための定番の書き方です。
定数に配列も入れられる
定数に持たせられるのは、文字列や数値だけではありません。PHP 7 以降は配列も定数にできます。define でも const でも配列を値に指定でき、設定のまとまりを1つの定数にまとめておくときに便利です。
<?php
// define で配列を定数にする(PHP 7 以降)
define('ALLOWED_EXTENSIONS', ['jpg', 'png', 'gif']);
// const でも配列を持てる
const DB_CONFIG = [
'host' => 'localhost',
'name' => 'my_app',
];
echo ALLOWED_EXTENSIONS[0]; // jpg
echo DB_CONFIG['host']; // localhost
配列の要素にはインデックスやキーでアクセスできます。ただし定数なので、ALLOWED_EXTENSIONS[] = 'webp'; のように後から要素を追加・変更することはできません。中身も含めて固定されると考えておきましょう。
クラスの中で使うクラス定数
const はクラスの中でも使えます。これをクラス定数と呼び、そのクラスに関係する固定値(ステータスコード、上限値など)をまとめておくのに向いています。クラス外からは クラス名::定数名、クラス内からは self::定数名 でアクセスします。
<?php
class Order
{
// クラス定数を定義する
const STATUS_PENDING = 'pending';
const STATUS_PAID = 'paid';
const MAX_ITEMS = 20;
public function describe(): string
{
// クラス内からは self:: で参照する
return '上限は ' . self::MAX_ITEMS . ' 個です';
}
}
// クラス外からは クラス名:: で参照する
echo Order::STATUS_PAID; // paid
echo (new Order())->describe(); // 上限は 20 個です
クラス定数は public / protected / private の可視性を付けられる(PHP 7.1 以降)ため、外部に公開したくない値を隠すこともできます。文字列で管理しがちなステータス値などをクラス定数にまとめておくと、タイプミスに気づきやすくなり、コードの見通しもよくなります。
あらかじめ用意されているマジック定数
PHP には、書かれた場所に応じて値が変わる特別な定数が最初から用意されています。これをマジック定数と呼びます。前後をアンダースコア2つで挟んだ名前が特徴で、大文字小文字を区別しません。デバッグやログ出力、ファイルパスの組み立てなどでよく使います。代表的なものを紹介します。
| マジック定数 | 展開される内容 |
|---|---|
__LINE__ | 現在の行番号 |
__FILE__ | 実行中のファイルのフルパス |
__DIR__ | 実行中のファイルがあるディレクトリ |
__FUNCTION__ | 現在の関数名 |
__CLASS__ | 現在のクラス名 |
__METHOD__ | 現在のメソッド名(クラス名::メソッド名) |
<?php
// __DIR__ は require のパス組み立てで定番
require __DIR__ . '/lib/helper.php';
function debug_log(string $message): void
{
// どのファイルの何行目かをログに残す
error_log($message . ' @ ' . __FILE__ . ':' . __LINE__);
}
とくに __DIR__ は、他のファイルを読み込むときのパスを実行場所に依存させないために欠かせません。require __DIR__ . '/lib/helper.php'; と書いておけば、どこから呼ばれても正しいファイルを読み込めます。
まとめ
PHP の定数は、一度決めたら再代入できない値で、名前は大文字にするのが慣習です。定義方法は2つあり、define は実行時に評価されるため条件分岐やループの中でも使え、式や関数の戻り値も値にできます。一方 const はコンパイル時に定義され、トップレベルかクラス内でしか書けませんが、記述がシンプルでクラス定数にも使えます。動的に値を決めたいなら define、固定値の宣言やクラス定数なら const、と使い分けるとよいでしょう。定義済みかどうかは defined で確認でき、PHP 7 以降は配列も定数にできます。クラス定数は クラス名:: や self:: でアクセスし、__DIR__ などのマジック定数は場所に応じて値が変わる便利な組み込み定数です。用途に合った方法を選んで、変わってはいけない値を安全に扱っていきましょう。