PHPオブジェクト指向基礎
継承
継承とは
クラスには継承という仕組みが存在します。
継承とは、既に存在するあるクラスを元に、それを更に拡張したクラスを作る仕組みです。
継承の仕方は以下のような感じです。
<?php class クラス名 extends 親クラス名 { } ?>
通常のクラスと違い、クラス名の後に「extends 継承元のクラス名」を付け加えます。
当然、継承元のクラスは既に存在する必要があります。
継承してクラスを作ると、そのクラスは継承元のクラスのメンバを全て引き継ぎます。
ただし、修飾子がprivateのメンバは引き継がれません。
privateはあくまでクラス内でのみ参照可能なことを表します。
そのためにprotectedという修飾子が存在します。
protectedはそのクラス、および継承先のクラスでのみ参照可能な事を表す修飾子です。
なので、継承を想定したクラスでは、非公開メンバは「protected」にしましょう。
継承の利用
継承の例を見てみましょう。
<?php class Product { protected $name; // 商品名 protected $price; // 価格 // コンストラクタ public function __construct($name) { $this->name = $name; } // 価格を取得 public function getPrice() { return $this->price; } // 価格を設定 public function setPrice($price) { $this->price = $price; } } class FoodProduct extends Product { } ?>
Productクラスを継承してFoodProductクラスを作る例です。
例のように中身が空の継承クラスを作ると、継承元のクラスとは名前が違うだけのコピーのようなものとなります。
しかし何も書かないでは何の意味もないので、何かメンバを追加しましょう。
<?php class Product { (略) } class FoodProduct extends Product { private $expire; // 賞味期限日数 public function setExpire($expire) { $this->expire = $expire; } public function getExpire() { return $this->expire; } } ?>
Productクラスには商品名と価格のフィールドが存在し、価格用のセッタとゲッタが存在します。
Productクラスを継承したFoodProductクラスですが、
食品なので賞味期限フィールドとそのゲッタ・セッタを設けます。
見た目上、FoodProductにはexpireしか存在しないように見えますが、Productクラスを継承しているため、nameやpriceなどもFoodProductのメンバとなります。
<?php $food = new FoodProduct('肉'); $food->setPrice(100); echo '価格を' . $food->getPrice() . '円に設定しました。
'; $food->setExpire(30); echo '賞味期限を' . $food->getExpire() . '日に設定しました。
'; ?>
価格を100円に設定しました。 賞味期限を30日に設定しました。
FoodProductクラスにはsetExpireとgetExpireメソッドしか記述していませんが、setPriceメソッドやgetPriceメソッドもちゃんと実行できています。
このようにクラスの継承では元々存在するクラスに対して追加機能を持たせた新しいクラスを作る事が出来ます。上の例で言うとProductの機能は全て持った上で新しい機能を持たせたFoodProductというクラスを作成しました。
使われ方としては、似ているけど少し違うというような複数のクラスを作りたい時や、基本的な共通処理だけ記述した基礎クラスを作っておき、実際に使用する各クラスはその基礎クラスを継承する、というような使い方です。
継承による保守性の確保
継承の根底にある考え方も「同じ処理は二度書かない」ではないかと思います。
仮に上の例でFoodProductを作るときに、Productを継承するのではなく、コピー&ペーストでProductクラスをコピーした後、クラス名を変えてメソッドを追加するというような手法を取ると結果的には同じになりますが、もしProductクラスに仕様変更があった場合、全く同じプログラム修正をProductクラスとFoodProductクラスの両方に適用しなければならないことになります。
そういったことを避けるためにも継承を利用するのです。
基本、クラスの作成にコピー&ペーストはするべきではないと考えます。
逆の考え方で、元々は何も意識していなかったある二つのクラスで、よく見ると共通な部分が結構ある事に気づいた、というような場合、積極的にこの共通部分を抽出して別クラスとし、これを継承する形にしていくべきです。
オブジェクト指向では継承が便利という事はよく言われますが、便利機能というよりは、保守性の向上の為という意識を持てば、自然と継承という発送が出てくるのではないかと思います。

カプセル化

