質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.22%

PHP7新機能・定数に配列を定義

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 4
  • VIEW 5,299

Kosuke_Shibuya

score 18517

先日こちらのページ PHPマニュアル > 付録 > 変更履歴 を眺めていたときに、

イメージ説明

「define() に配列を定義できるようになった」と記述されており、

define

イメージ説明

実際に以下のコードで試したところ

<?php

define('ARRAY_SAMPLE_01', ['a', 'b', 'c']);

define('ARRAY_SAMPLE_02', ['a' => 100, 'b' => 200, 'c' => 300]);

var_dump(ARRAY_SAMPLE_01);
var_dump(ARRAY_SAMPLE_01[0]);

var_dump(ARRAY_SAMPLE_02);
var_dump(ARRAY_SAMPLE_02['b']);

確かに動くのですが、いったいどんな場面で使えばいいの?というのが疑問です。
そもそも定数に定義できるのはスカラー値であるというルールのもとで利用していたので、配列を定義したいと思ったことがありません。

そこで質問なのですが、

  1. これまで定数に配列を定義したいと思ったことがありますか?
  2. また、それはどんなケースでしたか?
  3. オブジェクト定数ではなく、グローバル空間に配列を定数を定義する積極的なメリットはあるか

ちなみにこちらのコードは、PHP5.6, PHP7 両方の環境で動作しました。

<?php

class SAMPLE
{

    const ARR = ['a', 'b', 'c'];

}

var_dump(SAMPLE::ARR[0]);
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+6

PHPの定数定義の方法について、変遷を調べてみました。(参考: PHP>マニュアル>言語リファレンス>定数>構文PHP>マニュアル>関数リファレンス>その他の基本モジュール>その他>その他の関数>define)

  • 〜5.2
    define: スカラー値のみ
    const: 存在しない
  • 5.3〜5.5
    define: スカラー値のみ
    const: スカラー値のみ
  • 5.6
    define: スカラー値のみ
    const: スカラー値(スカラー式も可)と配列 ※ リソースも可能だが非推奨
  • 7.0〜
    define: スカラー値と配列 ※ リソースも可能だが非推奨
    const: スカラー値(スカラー式も可)と配列 ※ リソースも可能だが非推奨

defineは関数式、constは代入式という書き方の違いがあります。defineはそもそも関数として扱われるため、値の部分に任意の式を書くことができます。7.0からdefineで配列も可能にしたのは、単にconstにあわせていったと思われます。

なお、(Cを除く)他の言語の定数は、再代入できない(言語によっては警告を出すだけや、慣習としてそうするというのもある)ただの変数として扱う場合が多いです。そのため、

  1. 定義は代入式
  2. 任意のデータ(オブジェクト)を扱える

という場合がほとんどです。初期のPHPは関数式のdefineだけで、しかもスカラー値のみであり、他の言語とは大きくかけ離れていました。それをバージョンアップの度に徐々にあわせていったと考えられます。


では、上を踏まえて、質問の回答です。

1. これまで定数に配列を定義したいと思ったことがありますか?

あまりPHPを書かないのでPHPでそうしたいと思ったことは無いのですが、PHP以外の言語では普通に使っています。

2. また、それはどんなケースでしたか?

指定フォルダ内のファイルを処理するスクリプトで、除外するファイル一覧として['System Volume Information', '$RECYCLE.BIN', 'Desktop.ini', ...]みたいなのを作った事があります。そのプログラムで変わることが無いような、サポート済み形式とか、定義済みの名前とか、そういった物の一覧を初めから用意したいときに使っています。たとえば、HTML5を処理するようなプログラムで使用できる要素名一覧を定数配列に入れておくとかです。

3. オブジェクト定数ではなく、グローバル空間に配列を定数を定義する積極的なメリットはあるか

constもグローバル空間に使用できます。まずは、クラス内とクラス外という比較で言えば、

  1. クラス内だと名前空間が分かれるため、名前の衝突防止等が期待できます。(大規模開発では必須)
  2. クラス内だとそのクラスに関連する定数だと一目でわかります。

と言う違いがあります。クラスを意識した作りにするのであればクラス内で書くべきでしょう。ただ、オブジェクト指向を使わないようなフラットなPHPにおいて、そのためだけにクラスを作るのはあまり意味が無いと思います。

では、グローバル空間において、constdefineですが、違いは代入式と関数式というところです。

  1. constの代入式の方が、変数の代入と書き方が同じになるため、わかりやすいような気がします。
  2. defineは関数式なので、値部分を任意の式にできます。constの右辺はスカラー式しか許されていません

特に2.の違いが重要です。

define("HOGE", array_merge([1, 2], [8, 9]));

と書くことができますが、

const HOGE = array_merge([1, 2], [8, 9]);

と書くことはできません。関数等を用いて配列を作り上げたい(他にもたとえばrange(1, 10)など)ときはdefineを使うしかないようです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/18 14:35

    回答ありがとうございます。
    やはり、オブジェクト指向での設計においては、あまり出番はなさそうだな、という印象ですね。
    アプリケーションのメンテナンスコストを考えると、多用するのは避けた方が良さそうだな…と感じています。

    キャンセル

+3

普段ほとんどdefine自体使わないので、興味深くちょっと調べてみたところ、以下のような例を見つけました。

define('ALLOWED_IMAGE_EXTENSIONS', ['jpg', 'jpeg', 'gif', 'png']);

元ネタ

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/18 14:39

    あげて頂いた例はちょうど想像していたような例です。アプリケーション全体の設定など、めったに変更されないようなものでないと使いどころはないし、オブジェクト指向設計においては、画像クラスのオブジェクト定数(またはプロパティ)に持つべきかと思われます。
    軽量のアプリケーションなど、全体の見通しがしやすいもので利用しないといけないな、との印象ですね。

    キャンセル

+1

詳しい説明はraccyさんが網羅してるので、
配列として定数を定義できるメリットに絞って考えてみました。

僕が考えついた所としては、

  • プログラム内で割と使う回すけど属性、値の組
  • クラス化とかするほど大層なものではない
  • だけど値は書き換えられたらまずいので不変の性質は持たせたい(イミュータブルなクラスみたいに)

上記要件に当てはまる場合はさっくり書けるようになりますよ、というのがdefineで配列を扱えるようにしたしたメリットかなと個人的に思ってます。

またここからは想像のお話なので、
興味なければ読み飛ばして下さい。

defineで配列が定義できるようになりましたの延長で、
いずれかはクラスなどのオブジェクトも定義できるようになりましたなるかもしれないし、ならないかもしれません。

もしクラスのインスタンス自体を定数持ちさせることが可能になれば、
とあるオブジェクトを特定の値で初期化し、
それを定数のように使い回したいというかとが出来るようになってきそうです
(C#.NETのstaticとreadonlyキーワードの合わせ技みたいな役割。ただ参照保持した定数なんでインスタンスの上書きは禁止できても、内部状態の変化は禁止できなかったはず^^;)

質問内容とは全く関係ありませんが、
参考までにC#の定数内訳で参考となるページを貼り逃げしときます。
【C#の定数】const と static readonly の使い分け

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/18 14:32

    回答ありがとうございます。
    やはり、オブジェクト指向での設計においては、あまり出番はなさそうですよね。
    関連クラスにオブジェクト定数として定義する方が、メンテナンスコストが低くなると思いますね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる