導入
「犬」も「猫」も「動物」という共通点があり、名前を持つ・鳴くといった共通の振る舞いがあります。似たクラスを1つずつゼロから書くのではなく、共通部分を1か所にまとめて再利用したい――これを解決する3つの仕組みが、継承・インターフェース・traitです。
説明
継承(extends) は、あるクラスの機能を引き継いだ新しいクラスを作る仕組みです。元のクラスを親クラス、引き継いだクラスを子クラスと呼びます。
<?php
class Animal {
public string $name;
public function __construct(string $name) {
$this->name = $name;
}
public function speak(): string {
return "{$this->name}は鳴きます";
}
}
class Dog extends Animal {
// 親のメソッドを上書き(オーバーライド)する
public function speak(): string {
return "{$this->name}はワンと鳴きます";
}
}
$dog = new Dog("ポチ");
echo $dog->speak(), "\n"; // ポチはワンと鳴きます
Dog は Animal を継承しているので、__construct() を書かなくても $name を受け取って new Dog("ポチ") ができます。speak() を Dog 側でも定義すると、親のものを**上書き(オーバーライド)**できます。親のメソッドをそのまま呼びたいときは parent::speak() と書けます。
classDiagram
Animal <|-- Dog
Animal <|-- Cat
class Animal {
+string name
+speak() string
}
class Dog {
+speak() string
}
class Cat {
+speak() string
}
インターフェース(interface / implements) は、「このクラスは必ずこのメソッドを持つ」という**約束(契約)**だけを決める仕組みです。処理の中身は持たず、形だけを定義します。
<?php
interface Payable {
public function pay(): string;
}
class CreditCard implements Payable {
public function pay(): string {
return "クレジットカードで支払いました";
}
}
class CashPayment implements Payable {
public function pay(): string {
return "現金で支払いました";
}
}
function checkout(Payable $method): void {
// Payable を実装していれば、中身がどのクラスでも同じように呼び出せる
echo $method->pay(), "\n";
}
checkout(new CreditCard());
checkout(new CashPayment());
checkout() は「Payable を実装したものなら何でもよい」という前提で書けます。継承は「1つの親」しか持てませんが、implements は複数のインターフェースを同時に実装できます。
trait は、継承関係とは関係なく、複数のクラスにメソッドの実装そのものを混ぜ込む仕組みです。trait で定義し、クラスの中で use トレイト名; します。
<?php
trait Greetable {
public function greet(): string {
return "こんにちは、{$this->name}です";
}
}
class Staff {
use Greetable;
public string $name;
public function __construct(string $name) {
$this->name = $name;
}
}
$s = new Staff("田中");
echo $s->greet(), "\n"; // こんにちは、田中です
継承関係にない Staff にも、use Greetable; だけで greet() メソッドが使えるようになります。「継承関係を作るほどではないが、複数クラスで処理を共有したい」ときに便利です。
やってみよう
Animal を継承した Bird クラスを作って speak() をオーバーライドしてみましょう。Payable を実装する3つ目のクラス(例:BankTransfer)を作って checkout() に渡してみるのもよい練習です。
演習
上の Animal クラスを継承した Cat クラスを作り、speak() をオーバーライドして "{名前}はニャーと鳴きます" を返すようにしてください。$cat = new Cat("タマ"); を作り、speak() の結果を表示しましょう。
ヒント1を見る
class Cat extends Animal { public function speak(): string { return "{$this->name}はニャーと鳴きます"; } }
ヒント2を見る
$cat = new Cat("タマ"); echo $cat->speak(), "\n";