無意識理解から脱する【PHPの定数定義 編】

Blog Single

現在行なっているプロジェクトではPHP7.1を使用しているのですが、時々それよりも古いバージョンのものを使用することがあります。
久しぶりにそういうことがあると忘れがちになるのが、定数の定義方法です。

知っている方がほとんどだとは思いますが、まず前提としてPHPの定数定義方法には以下の2通りあります。

  • define()
  • const

バージョンアップに伴って、仕様が少しずつ変更されているこの2つ。
違いや定義方法を忘れてしまうといちいち調べる時間が非常に勿体無い!
という訳で今回は、バージョン毎の変化も合わせて定数の定義方法をおさらいしてみます。

define()

define()で定義した定数はどのクラス、どのメソッド内でも呼び出すことができるグローバルなものとして扱うことができます。
namespace配下で定義してあってもグローバルに使用できます。
ただしクラス定数としては使用できません。
また第3引数をtrueにすると定数名の大文字小文字を区別せずに定義することもできます。

// 全バージョン共通の書き方
define('FAVORITE_FISH1', 'Chromis viridis: デバスズメダイ');
echo FAVORITE_FISH1; // -> 'Chromis viridis: デバスズメダイ'
echo favorite_fish1; // -> ERROR

define('FAVORITE_FISH2', 'Betta splendens: ベタ', true);
echo FAVORITE_FISH2; // -> 'Betta splendens: ベタ'
echo favorite_fish2; // -> 'Betta splendens: ベタ'

class SampleA
{
    define('FAVORITE_FISH3', 'Cetoscarus ocellatus: イロブダイ'); // -> ERROR
}

PHP7.0になると、定数定義できる型に配列が追加されました。
もちろん連想配列の形式でも定義できます。

// PHP7.0以降
define('DAYS', array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'));
var_dump(DAYS[3]); // -> 'Wednesday'

define('MONTHS', array(
    1 => 'January',
    2 => 'February',
    3 => 'March',
    4 => 'April',
    5 => 'May',
    6 => 'June',
    7 => 'July',
    8 => 'August',
    9 => 'September',
    10 => 'October',
    11 => 'November',
    12 => 'December'
));
var_dump(MONTHS[9]); // -> 'September'

const

constを使用できるようになったのはPHP5.3からです。
define()ではできなかったクラス定義が可能なところが大きな利点です。
namespace配下で定義したものは依存するので、別のnamespaceで呼び出す際には注意が必要です。
現在では式を用いた定義が有効となっていますが、PHP5.6より前のバージョンではエラーとなっていました。

class SampleA
{
    // PHP5.6以降
    const PRICE = 1000 * 2;

    // PHP5.6以前
    const LABEL = '¥' . self::PRICE; // -> ERROR
}

PHP7.1以降では、アクセス修飾子をつけることができるようになっています。
これはクラス定数にのみ使用することができます。
アクセスレベルは通常のプロパティやメソッドの場合と同様です。

// PHP7.1以降
class SampleB
{
    public const COUNTRY = 'Japan';
    private const CURRENCY = 'yen';
}

echo SampleB::COUNTRY;
echo SampleB::CURRENCY; // -> ERROR

どちらを使うべきなのか

公式ではどちらを使うべきかの推奨はありませんが、
個人的な見解を言いますと、constの方がクラス定数としても使うことができ、定義時の制限が少ないので良いように思います。
プロジェクトのファイル構成にも左右されるので、適した場所とタイミングで使用するのがやはり一番ベストです。

最後に

意外とバージョンによって細かい部分が変更されていますね。
基本的な定義方法は崩れていないにしても、常に最新バージョンで慣れきっていると遭遇した時に一瞬焦ります。
こういう変化の流れがあったんだなと片隅に覚えておくといいと思います。

ちなみに各バージョンのサポート期限を載せておきます。
(これを見ると旧バージョンの定義方法を覚えなくてもいいのでは…と思ってしまうかもしれませんが)

Version 初回リリース日 アクティブサポート期日 セキュリティサポート期日
5.6 2014/8/28 2017/1/19 2018/12/31
7.0 2015/12/3 2017/12/3 2018/12/3
7.1 2016/12/1 2018/12/1 2019/12/1
7.2 2017/11/30 2019/11/30 2020/11/30

参考

Posted by Mao Miyaji
千葉にある夢の国を愛して止まない、元「魚のお姉さん」のエンジニア。PHP, TypeScriptメインで、暇さえあれば色々な言語を一かじり。

Other Posts: