※この記事の注意事項
・できるだけ初心者の方が理解しやすいように、細かい説明は省略しております。
・最後まで読み進められるように、多少ユーモアを交えて表現していることがあります。
========================================
もちろん今回もPHPのクラスの話なのですが、abstructと付けることで、特別な親クラスになります。
これをクラスの抽象化と言います。
本当は抽象クラスと継承クラスという言い方が正しいんだけど、色んなクラス名が出てきて混乱するので、ここではすべて親クラス、子クラスに統一してお話ししています。
抽象化したクラスは、普通に実装はできますが、インスタンス化することはできなくなります。newができないってこと。
つまり、自分自身だけでは何もできないクラスになってしまうのです。
その代わりに、子クラスに継承されることを前提としているので、子クラスに命令をすることができます。
どんな命令かというと、このメソッドは子クラスで定義してねと定義することができます。
/** * 自分ひとりではなにもできなくなった親クラス */ abstract class OyaClass { //子クラスに実装を強制するメソッド abstract protected function setName($param); //子クラスに実装を強制するメソッド abstract protected function getName(); //子クラスに実装を強制しない共通メソッド public function printOut() { echo $this->getName()."\n"; } }
ここではsetNameとgetNameを子クラスに強制しています。強制する場合は、親クラスでは実装はできません。
子クラスで継承して実装してみます。
class KodomoClass extends OyaClass { private $name = '子ども'; public function __construct() { # code... } public function setName($param) { $this->name = $param; } public function getName() { return $this->name; } }
強制されたメソッド以外にも、メンバ変数やメソッド、コンストラクタなども普通に実装できます。ただ、強制されたメソッドを実装していないとエラーになります。
呼び出し方は以下のようになります。
//クラスのインスタンス化 $instance = new KodomoClass; //親クラスの共通メソッドを呼び出し $instance->printOut(); //子クラスのメソッドを呼び出し $instance->setName('漢字にした子供'); //子クラスのメソッドを呼び出し echo $instance->getName()."\n";
使い方はいたって普通ですよね。
ではabstructは何がしたいのか?というと、親クラスから子クラスに強制するってこと、但し実装は子クラスでやってくれということ。
それは2つ目の子クラスが出てきた場合も同じです。
abstract class OyaClass { //子クラスに実装を強制するメソッド abstract protected function setName($param); //子クラスに実装を強制するメソッド abstract protected function getName(); //子クラスに実装を強制しない共通メソッド public function printOut() { echo $this->getName()."\n"; } } class KodomoClass1 extends OyaClass { private $name = '子ども'; public function __construct() { # code... } public function setName($param) { $this->name = $param; } public function getName() { return $this->name; } } class KodomoClass2 extends OyaClass { private $value = 1; public function setName($param) { $this->value += $param; } public function getName() { return $this->value; } } //子クラス1 $instance1 = new KodomoClass1; $instance1->setName('漢字にした子供'); echo $instance1->getName()."\n"; //子クラス2 $instance2 = new KodomoClass2; $instance2->setName(100); echo $instance2->getName()."\n";
ここでは親クラスで型指定をしていないので、子クラス1では文字列の名前として実装し、子クラス2では数値の足し算として実装しています。
こういう実装は混乱の原因になるので型指定も行った方がよいですね。
(型指定はPHP7.0から可能になりました。この記事では記載しません。)
注意点なんですが、親クラスで強制したメソッドの名前はもちろんのこと、引数の数や名前なども同一でなくてはなりません。これらをまとめてシグネチャといいます。シグネチャも同一にしてくださいと表現します。
親クラスのsetNameを見ると、アクセス権がprotectedになっています。
子クラスのsetNameを見ると、アクセス権がpublicになっています。
ここも本来の考え方は同一であるべきなのですが、親よりゆるいアクセス権は認められているのです。ですので、子クラスではprotectedとpublicのどちらかで設定することが可能なのです。
親クラスから子クラスへの継承へは強制力があるのですが、孫クラスへは強制力がないんですよね。
まるで現実世界のようですね。
以下は孫クラスではabstractメソッドを実装していませんがエラーにはなりません。
abstract class OyaClass { //子クラスに実装を強制するメソッド abstract protected function echoName($param); } class KodomoClass extends OyaClass { public function echoName($param) { echo $param."\n"; } } class MagoClass extends KodomoClass { public function printOut() { echo "孫クラス"; } } $instance1 = new KodomoClass; $instance1->echoName("子クラス"); $instance2 = new MagoClass; $instance2->printOut();
abstructが付いた親クラスは抽象クラスとなり、子クラスで実装して欲しいメソッドにはabstructを付け、実装は子クラスに任せる!
abstructが付かないメソッドも実装して、共有することができる。
抽象クラスとなった親クラスを継承した子クラスでは、親クラスでabstructが付いているものはすべて実装する必要があり、かつ型やヒント、名前などのシグネチャも同一でなければならない。
子クラスでは、abstructが付いたもの以外でも、自由にメソッドを追加したり実装することができる。
割と優しい親ですよね。僕もそんな親になろうと思いました。
そして孫には甘々です。きっと僕もそうなります。
========================================
▼PHPのオブジェクト指向とデザインパターン記事一覧
- Facade ファサードパターンで窓口をつくる 2017年8月25日 miura
- Strategy ストラテジーパターンで戦略的にクラスを使用する!? 2017年8月17日 miura
- Singleton シングルトンパターンでインスタンスを一つに限定しよう 2017年8月16日 miura
- Factory Method ファクトリーメソッドパターンでインスタンスの生成も任せてしまう 2017年8月15日 miura
- 少しだけ違うコードは TemplateMethod テンプレートメソッドパターンで効率的に書く 2017年8月12日 miura
- trait トレイトは便利な道具箱 2017年8月11日 miura
- interface インターフェイスで入口出口の取り決めを作る 2017年8月10日 miura
- abstruct アブストラクトって呪文みたいじゃない? 2017年8月9日 miura
- staticが付いたらクラスの中に入ってはいるけど別物と考えよう 2017年8月8日 miura
- オブジェクト指向とはなんぞや?クラスとは? 2017年8月7日 miura
この記事へのコメントはありません。