こんにちは。いっとくです!
先日やっとパーフェクトPHPという難関をクリアしたのですが、手を動かしながらやったとは言え、それだけで自分の血肉とするのには不十分だということで四の五の言わずにアウトプット!!
ほぼ同じだけどちょっと違うconstとdefine()
ソースコードをいじっているとよく見かける、constやdefine()の文字。
どちらも定数を定義するためのものだけど、なぜか僕が普段いじっているサービスのソースコードの中にはどちらも存在している。
…なぜだ!動きなんて変わらないはずなのになんで2パターンの書き方があるんだ!
どっちでもちゃんと動くので別に気にしなければいいことなんだろうけど、なんか気になるな〜と思っていたら、パーフェクトPHPの中に実はちょっと違うよみたいなことが書いてました。
ってことで実際にコードを書いて違いを検証してみました!
PHPは7.2です。
中に突っ込めるデータの型が違う
まずは中に入れられるデータの型に違いがあります。
結論から言うとdefine()の方が幅広くぶち込めます。
検証で使ったコードは以下のもの。
constant.php <?php function test(){ echo 'テスト関数'; } $string = '文字列'; class Test { private function aaaa() { echo '空です'; } } $test = new Test; // まずはconstで色々な定数を定義しまくる const CONSTANT1 = '魚'; const CONSTANT2 = 100; const CONSTANT3 = true; const CONSTANT4 = [1, 2, 'サン']; const CONSTANT5 = '魚' . 'は美味しいです'; const CONSTANT6 = 100 + 100; const CONSTANT7 = array_merge([1, 2, ' サン'], [4]); const CONSTANT8 = function() { echo '無名関数'; }; const COJNSTANT9 = test(); const CONSTANT10 = $string; const CONSTANT11 = $_SERVER['HTTP_HOST']; const CONSTANT12 = $test; // 続いてdefine()で定数を定義しまくる define('DEFINE1', '魚'); define('DEFINE2', 100); define('DEFINE3', true); define('DEFINE4', [1, 2, 'サン']); define('DEFINE5', '魚' . 'は美味しいです'); define('DEFINE6', 100 + 100); define('DEFINE7', array_merge([1, 2, ' サン'], [4])); define('DEFINE8', function() { echo ’無名関数; }); define('DEFINE9', test()); define('DEFINE10', $string); define('DEFINE11', $_SERVER['HTTP_HOST']); define('DEFINE12', $test); echo '<pre>'; // あとはひたすらvar_dumpで出力してみる var_dump(CONSTANT1); // 魚 var_dump(CONSTANT2); // 100 var_dump(CONSTANT3); // true var_dump(CONSTANT4); // [1, 2, 'サン'] var_dump(CONSTANT5); // 魚は美味しいです var_dump(CONSTANT6); // 200 var_dump(CONSTANT7); // ERROR!! var_dump(CONSTANT8); // ERROR!! var_dump(CONSTANT9); // ERROR!! var_dump(CONSTANT10); // ERROR!! var_dump(CONSTANT11); // ERROR!! var_dump(CONSTANT12); // ERROR!! // ここからはdefine()で定義したやつ var_dump(DEFINE1); // 魚 var_dump(DEFINE2); // 100 var_dump(DEFINE3); // true var_dump(DEFINE4); // [1, 2, 'サン'] var_dump(DEFINE5); // 魚は美味しいです var_dump(DEFINE6); // 200 var_dump(DEFINE7); // [1, 2, 'サン', 4] var_dump(DEFINE8); // ERROR!! var_dump(DEFINE9); // NULL var_dump(DEFINE10); // 文字列 var_dump(DEFINE11); // localhost var_dump(DEFINE12); // ERROR!!
constキーワードで定義した定数は文字列、数値、真偽値、配列を入れることができ、定義する時に文字列結合や数値の計算ができます。
しかし、array_mergeなどの定義済み関数や、無名関数、ユーザー定義関数、変数、スーパーグローバル変数、オブジェクトなどを入れようとするとエラーが発生します。
対してdefine()はconstで入れられる値にプラスして、定義済み関数や変数、スーパーグローバル関数も入れることが可能。
ユーザー定義関数を入れた時だけ、なぜかNULLが返ってくる。
入れられる型に違いはありますが、定数の使い方を考えると、文字列、数値、真偽値、配列あたりを使うことがほとんどだと思うので、どっちでもいいよ!って気がします。
クラス内で使うときは宣言できる場所が違う
クラス内で定数を定義するときは、書く場所を間違えるとエラーが出たりします。
constInClass.php <?php namespace Food; const CONSTANT1 = '野菜'; define('DEFINE1', '野菜'); class constTest { const CONSTANT2 = '魚'; define('DEFINE2', '魚'); // ERROR!! public function testMethod() { // const CONSTANT3 = '肉'; // ERROR!! define('DEFINE3', '肉'); } }
なぜかはわかりませんが、クラス直下でdefine()を使ったとき、メソッド内でconstを使ったときにエラーが発生します。
メソッド内で定数を作る必要が発生することはそうないと思いますが、class直下で作ることはたまにありそうなので、define()を使わないように注意しましょう。
名前空間の影響の受け方が違う
こちらもたまに関係ありそうな仕様の違い。
constとdefine()では名前空間の影響の受け方が違います。
実際の動きを見るために、上で使ったconstInClass.phpを読み込んだcallConst.phpで出力してみます。
callConst.php <?php require 'constInCLass.php'; use \Food\constTest; echo \Food\CONSTANT1; // 野菜 echo \Food\DEFINE1; // ERROR!!
正直僕はまだプログラミングを初めて経験が浅いので、名前空間の影響を受けるとか受けないとか言われても全然ピンと来なかったのですが、実際に試してみると一目瞭然。
名前空間を使っているとき、constだと別ファイルからも読み込めるが、define()だとエラーが出てしまう…ということだと思う!
実務レベルで考えると定数ってまとめて置いて共通化して使うと思うんですね。
また、ほとんどの場合フレームワークを使っての開発になることを考えると、名前空間使ってるだろうし基本的にはconstで定義した方が良さそう。
速度面はそんなに変わらない
調べていると、constと違ってdefineは関数なので速度が劣るという情報がありました。
ちょっと気になったので、for文をめちゃくちゃ回して時間を計測してみましたが、正直どちらも変わりませんでした(測り方間違ってたらすんません!)
どちらにしろ定義して呼び出すくらいなら回数もしれているので、人間が体感できるほどの速度の差になることはまずないでしょう
結論:定数はconstでいいんじゃね!?
以上、constとdefineで作る定数の違いについてでした!
僕は普段の業務で定数を使うとき、モデルにまとめておいて呼び出すことがほとんどなので、そう考えるとconst一択のように感じます。
あと調べる過程で、コンパイル時に置き換わるかどうかが違うみたいなことが書いていました。それによって出来上がるものにどんな違いができるのか全然わからなかったので誰か日本語で教えてれたら嬉しいです。
定数なんてこんな細かく知っておく必要ないよ!って気もするけど、知らないよりは知っていた方がいいよね!
深いところまで知りたいぜって人は古い本ですがパーフェクトPHPがかなりおすすめです。

以上、PHP修行中のいっとくでした!
コメント