Menu
Coddy logo textTech

トレイトにおける抽象メソッド

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 54/91。

トレイトはすぐに使えるメソッドを提供できますが、trait を使用する class に特定の機能を Implement させる必要がある場合もあります。このような場合に、トレイトの abstract methods が役立ちます。これは、使用する class が満たさなければならない契約を定義します。

トレイトが抽象メソッドを宣言している場合、そのトレイトを使用するクラスはそのメソッドを実装する必要があります:

<?php
trait Notifiable {
    abstract public function getEmail(): string;
    
    public function sendNotification(string $message): void {
        echo "Sending to " . $this->getEmail() . ": $message";
    }
}

class User {
    use Notifiable;
    
    public function __construct(private string $email) {}
    
    public function getEmail(): string {
        return $this->email;
    }
}

$user = new User("john@example.com");
$user->sendNotification("Welcome!");

出力:

Sending to john@example.com: Welcome!

トレイトは sendNotification() メソッドを提供しますが、getEmail() が class によって実装されることを前提としています。これにより、トレイトが共通のロジックを処理し、class 固有の詳細を実装する class に委任する、強力なパターンが生まれます。

class がトレイトを使用しているにもかかわらず abstract method を実装していない場合、PHP は致命的なエラーを発生させます。これにより、トレイトは特定の method の存在に安全に依存でき、コードの予測可能性と保守性が向上します。

challenge icon

チャレンジ

簡単

異なる product タイプがそれぞれ異なる方法で最終価格を calculate しながら、abstract method を持つ trait を通じて共通の discount ロジックを共有する pricing system を構築しましょう。

コードを3つのファイルに整理します。

  • Discountable.php: discount 機能を提供する Discountable という trait を Create します。この trait には次の要素が必要です。
    • この trait を使用するクラスが Implement しなければならない abstract method getBasePrice(): float
    • base price に discount percentage を applying した後の price を calculate して返す method applyDiscount(int $percent)
    • 2 decimal places の formatted string "Final price: $[discounted_price]" を返す method getFinalPrice(int $percent)
    この trait は discount の計算をすべて処理しますが、base price が何であるかは各クラスに委ねます。
  • Product.php: Discountable trait を使用する Product class を Create します。trait file を Include します。constructor promotion を使用して、private $name (string) と private $price (float) を定義します。required な getBasePrice() method を Implement し、product の price を返します。
  • main.php: Product file を Include します。3つの inputs、つまり product name、price、discount percentage を受け取ります。Product instance を Create し、次の2行を Print します。
    • 2 decimal places の "Base: $[price]" として formatted した base price
    • discount percentage を指定して getFinalPrice() を calling した result

この pattern は強力です。Discountable trait は、getBasePrice() を Implement する限り、products、services、subscriptions など、あらゆる class で使用できるからです。trait が共有される discount ロジックを提供し、各 class が base price の取得元を定義します。

自分で試してみよう

<?php

require_once 'Product.php';

// 入力を読み取る
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));

// TODO: 名前と価格で Product インスタンスを作成する

// TODO: 基本価格を "Base: $[price]" の形式で小数点以下2桁で出力する

// TODO: 割引率を指定して getFinalPrice() を呼び出した結果を出力する

?>
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: PHPオンラインコンパイラ