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

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

新規登録して質問してみよう
ただいま回答率
85.40%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

258閲覧

php のクラスにおいて、継承される定数を制限したい

munekun

総合スコア61

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2024/07/21 01:49

編集2024/07/21 02:14

実現したいこと

php のクラス継承で、子クラスは親クラスの定数を一部しか使えないよう制限したいです。

現状と問題

以下のように PrivateItemKindSharedItemkind などがあり、一方にしかない値 (TAG_KIND_ID) があります。

しかし以下のようにすると、BOOK_KIND_ID の値が 2 だったり 1 だったり、ズレることになりますよね。(TAG_KIND_IDPrivateItemKind でしか使わないため、ID の連番を詰めると BOOK_KIND_ID の値がズレる。)

このズレれをうまく解消する方法を知りたいです。

php

1class PrivateItemKind 2{ 3 const TAG_KIND_ID = 1; 4 const BOOK_KIND_ID = 2; // BOOK_KIND_ID の値が 2 5 const USER_KIND_ID = 3; 6} 7 8class SharedItemkind 9{ 10 const BOOK_KIND_ID = 1; // BOOK_KIND_ID の値が 1 11 const USER_KIND_ID = 2; 12}

解決策

解決策A

まず素朴に考える解決策は、以下のように定数名に接頭辞をつけ区別することです。これなら「同じ定数名なのに値が違う」という上記のズレは生じません。

php

1class PrivateItemKind 2{ 3 const PRIVATE_TAG_KIND_ID = 1; 4 const PRIVATE_BOOK_KIND_ID = 2; 5 const PRIVATE_USER_KIND_ID = 3; 6} 7 8class SharedItemkind 9{ 10 const SHARED_BOOK_KIND_ID = 1; 11 const SHARED_USER_KIND_ID = 2; 12}

しかし「本というアイテム種別」という同じ意味なのに、プライベートなのかシェアされたのかという違いによって異なる定数名にすることに違和感を覚えます。(そうすることが一般的なら、私の違和感は初心者特有のものでしょうから受け入れたいと思いますが、いかがでしょうか?)

解決策B

続いての解決策の方が筋が良さそうかと思い本質問のタイトルとさせていただきました。
つまり、親クラス ItemKindMaster で定数を宣言し、子クラスは必要な値のみ宣言するという方法です。

php

1abstract class ItemKindMaster 2{ 3 const TAG_KIND_ID = 1; 4 const BOOK_KIND_ID = 2; 5 const USER_KIND_ID = 3; 6} 7 8class PrivateItemKind extends ItemKindMaster 9{ 10 // 必要な値のみ宣言する 11 const TAG_KIND_ID = parent::TAG_KIND_ID; 12 const BOOK_KIND_ID = parent::BOOK_KIND_ID; 13 const USER_KIND_ID = parent::USER_KIND_ID; 14} 15 16class SharedItemkind extends ItemKindMaster 17{ 18 // 必要な値のみ宣言する 19 const BOOK_KIND_ID = parent::BOOK_KIND_ID; 20 const USER_KIND_ID = parent::USER_KIND_ID; 21}

こちらの方法でも「同じ定数名なのに値が違う」という上記のズレは生じなくなるのでよさそうかと思ったのですが、

しかし (ItemKindMaster を継承しているので当たり前ですが)、以下のように呼べてしまいました。
SharedItemkind には TAG_KIND_ID を持たせたくないのに、これでは困ります。

php

1echo SharedItemkind::TAG_KIND_ID;

そこで改めて質問になります。子クラスは親クラスの定数を一部しか使えないよう制限したい (SharedItemkindTAG_KIND_ID を持たせたくない) のですが、どうすべきでしょうか?

バージョン

php 8.2 です。

補足

もしかして以下のように、null を再代入し、使えないことを明示する。という解決策がベストでしょうか?

php

1abstract class ItemKindMaster 2{ 3 const TAG_KIND_ID = 1; 4 const BOOK_KIND_ID = 2; 5 const USER_KIND_ID = 3; 6} 7 8class PrivateItemKind extends ItemKindMaster 9{ 10 const TAG_KIND_ID = parent::TAG_KIND_ID; 11 const BOOK_KIND_ID = parent::BOOK_KIND_ID; 12 const USER_KIND_ID = parent::USER_KIND_ID; 13} 14 15class SharedItemkind extends ItemKindMaster 16{ 17 const TAG_KIND_ID = null; // 使えないことを明示する 18 const BOOK_KIND_ID = parent::BOOK_KIND_ID; 19 const USER_KIND_ID = parent::USER_KIND_ID; 20}

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2024/07/21 04:51

> SharedItemkind には TAG_KIND_ID を持たせたくないのに 「あるけど使わない」では、具体的に何が困るのでしょうか?
munekun

2024/07/21 05:40

コメントありがとうございます。検証のときに邪魔になりそうだと思いました。うっかり利用してしまうとデータベースに想定しない値が入ってしまうのではと懸念しています。
otn

2024/07/21 07:59 編集

> うっかり利用してしまうとデータベースに想定しない値が入ってしまうのではと それは、DBに書く処理の中で、値をチェックしてエラーにすべきですが、それが漏れているということですかね? 私も「何が困るんだろう??」と思ってました。
munekun

2024/07/23 02:59

そのチェックにおいて、「ItemKindMaster に含まれる値である」というチェックだけだど、「プライベートアイテムではないのにうっかり TAG_KIND_ID を持たせてしまっていも、チェックを通ってしまう」という問題に困ったのです。 なので PrivateItemKind と SharedItemkind というふうに分けてみようと思い、質問に至った次第です。
guest

回答2

0

ベストアンサー

TAG_KIND_IDPrivateItemKind でしか使わないため、ID の連番を詰めると BOOK_KIND_ID の値がズレる。

IDは、「連番」とか「(間を)詰める」とかを考える事が、勘違いや「沼」への第一歩だと思います。
ナニカを特定する値でありさえすれば良いのではありませんか?

「本というアイテム種別」という同じ意味なのに、プライベートなのかシェアされたのかという違いによって異なる定数名にすることに違和感を覚えます。

同じ意味ではなく「プライベートなのかシェアされたのかという違い」があるのでは?
それを意味するのがTAG_KIND_IDとするには定数名が筋悪だと思いますが、

もしかして以下のように、null を再代入

で示されているのは、当初の予定と値がズレているのでは?
__当初はSharedItemkind::BOOK_KIND_ID1、例示では2

少し無理やり感はありますが、ご提示のモノを改造するとこんな感じかと。

PHP

1abstract class ItemKindMaster 2{ 3 const KIND_ID_BASE = 0; 4} 5 6class PrivateItemKind extends ItemKindMaster 7{ 8 const TAG_KIND_ID = parent::KIND_ID_BASE + 1; 9 const BOOK_KIND_ID = parent::KIND_ID_BASE + 2; 10 const USER_KIND_ID = parent::KIND_ID_BASE + 3; 11} 12 13class SharedItemkind extends ItemKindMaster 14{ 15 const BOOK_KIND_ID = parent::KIND_ID_BASE + 1; 16 const USER_KIND_ID = parent::KIND_ID_BASE + 2; 17} 18echo SharedItemkind::TAG_KIND_ID; // Fatal error: Uncaught Error: Undefined constant SharedItemkind::TAG_KIND_ID

ただし、前述の通り、方向性が良いのかは少々疑問がありますが...

投稿2024/07/21 03:27

tezcello

総合スコア301

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

munekun

2024/07/21 05:40

> 「連番」とか「(間を)詰める」とかを考える事が、勘違いや「沼」への第一歩 たしかに、人間向けだとこう考えて沼ってしまいますけれど、機械にとっては関係なくて「ナニカを特定する値でありさえすれば良い」ですね。 > ご提示のモノを改造するとこんな感じかと。 すごい、そんな方法、全然思いつけませんでした。ありがとうございます。
tezcello

2024/07/21 06:00

一応解決という事なので、考えた甲斐がありました。 > たしかに、(略) 逆方向にも考えてみると良いと思います。 これらの ID値はどこかに記録されるモノなのでしょうけれど、(質問者さんのやりたい事のままにすると)その記録された値には意味が複数あって、状況を加味しないと意味を特定する事が出来ません。 これは困る事になりませんか? __いや、必ず困った事に...
guest

0

  • BOOK_KIND_ID の値が 2 だったり 1 だったり、ズレることを避けたい
  • PrivateItemKindからは PrivateItemKind::TAG_KIND_ID では変数にアクセスさせたくない

という要件であれば下記で満たせるかと思います

php

1class PrivateItemKind 2{ 3 const BOOK_KIND_ID = 2; 4 const USER_KIND_ID = 3; 5} 6 7class SharedItemkind extends PrivateItemKind 8{ 9 const TAG_KIND_ID = 1; 10}

ただ、privateなconstが複数になると管理が複雑になるでしょう。
(次に FOO_KIND_ID がきたら4にするのか等)
privateまたはpublicなものを離れた値にする、変更が起きやすいものであればDB管理にするなどの工夫も必要になります。

実業務上でクラスをこのような実装にしなければいけないケースはあまり思いつきません。
そもそもなぜprivateにする必要があるのか、idをソースコードに持つ仕様だと変更し辛いが良いのか、といった部分は再確認されたほうが良いかと思います。

投稿2024/07/21 05:43

Eggpan

総合スコア3190

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

munekun

2024/07/23 02:55

> という要件であれば下記で満たせるかと思います たしかにそうですね。ありがとうございます。ただ質問は簡易にしてしまいましたが、実際は包含関係ではない (一方にしかない値は互いに持つ) ので、すこし工夫が必要そうでした。 > 実業務上でクラスをこのような実装にしなければいけないケースはあまり思いつきません あれ?そうなのですね。マスタテーブルの枠槍を持ったクラスという感じで作ってみたのですが、そもそも妙な実装だったでしょうか。考え直してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.40%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問