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

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

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

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

Q&A

解決済

1回答

6693閲覧

phpのtraitの使いどころについて

ryuuinn

総合スコア75

PHP

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

1グッド

2クリップ

投稿2016/02/06 07:46

php5.4からtraitが追加され、使い方がよくわかってないので教えてください。

あんまないと思うんですが、下みたいに、何故かTeacherクラスを継承した各先生のクラスが2つあったばあい、なかの処理がビミョーに異なっていて、ほとんど同じって場合。
本当は親のTeacherクラスで処理かいてテンプレートパターンのような形にしたいのですが、
諸事情で親のTeacherクラスが修正出来ないとして、Teachbleのようなトレイトを作って、そこで本来やりたかったようなテンプレートパターンのような事をするのって有りなんでしょうか。

既存のコード

Teacherを継承した、山田先生と小池先生のクラスがあるとします。
各先生はsaitenメソッドを持ってますが、発言や、赤点等の基準が少し違うとします。

php

1<?php 2 3class Teacher 4{ 5} 6 7class Yamada extends Teacher 8{ 9 const NAME = "山田"; 10 11 public function saiten($point) 12 { 13 $this->startCall($point); 14 15 if ($this->isAkaten($point)) { 16 $this->akatenResponse(); 17 } 18 19 if ($this->isHeikin($point)) { 20 $this->heikinReponse(); 21 } 22 23 if ($this->isManten($point)) { 24 $this->mantenResponse(); 25 } 26 } 27 28 private function startCall($point) 29 { 30 echo sprintf("%sが採点しますね\n%d点ですか・・\n", self::NAME, $point); 31 } 32 33 private function akatenResponse() 34 { 35 echo "赤点ですね"; 36 } 37 private function heikinReponse() 38 { 39 echo "平均ですね"; 40 } 41 private function mantenResponse() 42 { 43 echo "満点ですね"; 44 } 45 46 private function isAkaten($point) 47 { 48 return $point < 30; 49 } 50 51 private function isHeikin($point) 52 { 53 return $point >= 30 && $point < 100; 54 } 55 56 private function isManten($point) 57 { 58 return $point === 100; 59 } 60} 61 62class Koike extends Teacher 63{ 64 const NAME = "小池"; 65 66 public function saiten($point) 67 { 68 $this->startCall($point); 69 70 if ($this->isAkaten($point)) { 71 $this->akatenResponse(); 72 } 73 74 if ($this->isHeikin($point)) { 75 $this->heikinReponse(); 76 } 77 78 if ($this->isManten($point)) { 79 $this->mantenResponse(); 80 } 81 } 82 83 private function startCall($point) 84 { 85 echo sprintf("%sが採点するぞこら\n%d点か・・\n", self::NAME, $point); 86 } 87 88 private function akatenResponse() 89 { 90 echo "お前赤点だよ"; 91 } 92 private function heikinReponse() 93 { 94 echo "平均だな"; 95 } 96 private function mantenResponse() 97 { 98 echo "満点かーやるやんけ"; 99 } 100 101 private function isAkaten($point) 102 { 103 return $point < 80; 104 } 105 106 private function isHeikin($point) 107 { 108 return $point >= 80 && $point < 100; 109 } 110 111 private function isManten($point) 112 { 113 return $point === 100; 114 } 115} 116 117$yamadaTeacher = new Yamada(); 118echo $yamadaTeacher->saiten(60); 119 120echo "\n\n"; 121 122$koikeTeacher = new Koike(); 123echo $koikeTeacher->saiten(60); 124

出力結果

山田が採点しますね 60点ですか・・ 平均ですね 小池が採点するぞこら 60点か・・ お前赤点だよ

traitを使ってみる

php

1<?php 2 3class Teacher 4{ 5} 6 7trait Teachble 8{ 9 public function saiten($point) 10 { 11 $this->startCall($point); 12 13 if ($this->isAkaten($point)) { 14 $this->akatenResponse(); 15 } 16 17 if ($this->isHeikin($point)) { 18 $this->heikinReponse(); 19 } 20 21 if ($this->isManten($point)) { 22 $this->mantenResponse(); 23 } 24 } 25 26 abstract public function startCall($point); 27 abstract public function isAkaten($point); 28 abstract public function isHeikin($point); 29 abstract public function isManten($point); 30 abstract public function akatenResponse(); 31 abstract public function heikinReponse(); 32 abstract public function mantenResponse(); 33} 34 35class Yamada extends Teacher 36{ 37 use Teachble; 38 39 const NAME = "山田"; 40 41 private function startCall($point) 42 { 43 echo sprintf("%sが採点しますね\n%d点ですか・・\n", self::NAME, $point); 44 } 45 46 private function akatenResponse() 47 { 48 echo "赤点ですね"; 49 } 50 private function heikinReponse() 51 { 52 echo "平均ですね"; 53 } 54 private function mantenResponse() 55 { 56 echo "満点ですね"; 57 } 58 59 private function isAkaten($point) 60 { 61 return $point < 30; 62 } 63 64 private function isHeikin($point) 65 { 66 return $point >= 30 && $point < 100; 67 } 68 69 private function isManten($point) 70 { 71 return $point === 100; 72 } 73} 74 75class Koike extends Teacher 76{ 77 use Teachble; 78 79 const NAME = "小池"; 80 81 private function startCall($point) 82 { 83 echo sprintf("%sが採点するぞこら\n%d点か・・\n", self::NAME, $point); 84 } 85 86 private function akatenResponse() 87 { 88 echo "お前赤点だよ"; 89 } 90 private function heikinReponse() 91 { 92 echo "平均だな"; 93 } 94 private function mantenResponse() 95 { 96 echo "満点かーやるやんけ"; 97 } 98 99 private function isAkaten($point) 100 { 101 return $point < 80; 102 } 103 104 private function isHeikin($point) 105 { 106 return $point >= 80 && $point < 100; 107 } 108 109 private function isManten($point) 110 { 111 return $point === 100; 112 } 113} 114 115$yamadaTeacher = new Yamada(); 116echo $yamadaTeacher->saiten(60); 117 118echo "\n\n"; 119 120$koikeTeacher = new Koike(); 121echo $koikeTeacher->saiten(60);

出力結果

山田が採点しますね 60点ですか・・ 平均ですね 小池が採点するぞこら 60点か・・ お前赤点だよ

質問

このように、traitを使うことで、また先生を増やした時にほぼ内容がまったく同じなsaitenメソッドをコピペする必要がなくなって楽になるかと思いましたが、これってtraitの使い方として正しいのでしょうか・・

sunaczip👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

質問者様の使い方ですが、間違ってはいません。
ただ、お題にあがっているコードでは、既存の「継承」機能で事足りるので、それほどメリットが見られないと思います。

先生をモチーフにして考えると、下記のような形なら理解しやすいのではないでしょうか。

トレイトの考え方が無かった場合

  • 親クラス:「先生」
  • 子クラス:「国語の先生」「数学の先生」「英語の先生」「国語と英語の先生」

「国語と英語の先生」クラスは、「国語の先生」クラスの内容と「英語の先生」クラスの内容を再度記述する必要がある。

トレイトの場合

  • 親クラス:「先生」
  • トレイト:「国語担当」「数学担当」「英語担当」
  • 子クラス:「国語の先生」「数学の先生」「英語の先生」「国語と英語の先生」

「国語と英語の先生」クラスは、「国語担当」と「英語担当」を use すればよい。

そして、今後、「数学と英語の先生」が赴任する際は、「数学担当」と「英語担当」を use したクラスを作成する・・・ということになります。

コードとして表現する場合、下記のような形になります。

PHP

1/* 2 * 親クラス 3 */ 4class 先生 { 5 public function 採点() { 6 } 7} 8 9/* (各科目担当の定義)トレイト */ 10trait 数学担当 { 11 public function 数学の授業() { 12 } 13} 14 15trait 英語担当 { 16 public function 英語の授業() { 17 } 18} 19 20trait 国語担当 { 21 public function 国語の授業() { 22 } 23} 24 25/** 26 * 子クラス 27 */ 28class 国語の先生 extends 先生 { 29 use 国語担当; 30} 31 32class 数学と英語の先生 extends 先生 { 33 use 数学担当; 34 use 英語担当; 35} 36 37// 小池先生 38$koike = new 数学と英語の先生(); 39$koike->数学の授業(); 40$koike->英語の授業(); 41$koike->採点(); 42 43// 山田先生 44$yamada = new 国語の先生(); 45$yamada->国語の授業(); 46$yamada->採点(); 47$yamada->英語の授業(); // エラー 48 49 50/* ------------- 国語と英語の先生が赴任した場合 --------------- */ 51 52class 国語と英語の先生 extends 先生{ 53 use 国語の先生; 54 use 英語の先生; 55} 56 57$newTeacher = new 国語と英語の先生(); 58$newTeacher->国語の授業(); 59$newTeacher->英語の授業(); 60$newTeacher->採点();

投稿2016/02/08 00:31

編集2016/02/08 00:48
usk

総合スコア397

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

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

ryuuinn

2016/02/10 00:09

ありがとうございます! すごいスッキリです! やっぱり、traitって、 `クラスに機能を足す` みたいなイメージですね。 そして、サンプルコードの記述もすごく参考になりましたw 質問するときもそうやって書くと読みやすかったですね・・>< 色々ありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問