2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

〜エンジニア初学者の開発日記〜 三の巻

Posted at

こんにちは、つかさです
今回も現在携わっている開発で学んだことを記事にまとめようと思います!
前回テストパターンについての記事を書きましたが、その中で出てきたextendstraitの違いについてまとめたいと思います!

前提

  • バックエンド
    👉 Laravel
  • フロントエンド
    👉 Inertia.js(Vue3)
  • アーキテクチャ
    👉MVCS

extendsについて

クラスの親子関係を作りたい場合に、子クラス名の横にextendsと親クラスにしたいクラス名を書きます。これを別の言い方で◯◯クラスは✖︎✖︎クラスを継承してるとも言いますね。

・では継承すると何がいいんでしょうか?

  1. 親クラスのプロパティやメソッドを、子クラスで使うことができます。
  2. コンストラクタの継承も可能。

オーバライドとは
親クラスにあるメソッドと同じ名前のメソッドを子クラスで使用した場合に、子クラスのインスタンス内では子クラスにあるメソッドが処理されます。これを親クラスにあるメソッドを上書く意味合いからオーバーライドすると言われます。

class Animal {
    public function makeSound() {
        return "Some generic sound";
    }
}

class Dog extends Animal {
    public function makeSound() {
        return "Bark";
    }
}

$dog = new Dog();
echo $dog->makeSound();  // 出力: "Bark"

traitについて

クラスの機能を再利用するための仕組み。クラスの継承とは違って、複数のクラス間でコードを共有するために使用されます。

  1. 多重継承の代替手段: 複数のクラスで同じ機能を共有できる。
  2. コードの再利用を促進。
trait Logger {
    public function log($message) {
        echo "Log: " . $message;
    }
}

class User {
    use Logger;
}

class Product {
    use Logger;
}

$user = new User();
$user->log("User logged in.");  // 出力: "Log: User logged in."

$product = new Product();
$product->log("Product added.");  // 出力: "Log: Product added."

複数使用

trait A {
    public function methodA() {
        echo "Method A";
    }
}

trait B {
    public function methodB() {
        echo "Method B";
    }
}

class MyClass {
    use A, B;
}

$obj = new MyClass();
$obj->methodA();  // 出力: "Method A"
$obj->methodB();  // 出力: "Method B"
特徴 extends trait
多重使用 × (単一継承のみ) ○ (複数トレイト適用可能)
機能の上書き ○ (オーバーライド可能) ○ (メソッドの上書き可能)
コンストラクタ ○ (親のものを継承) × (トレイトにコンストラクタなし)
使用用途 "is-a" 関係 "has-a" 関係
再利用の適用範囲 1つの継承先 複数のクラス

extends,trait両方使用した場合について

extendsで親クラスの基本機能を継承しつつ、traitで特定の機能(共通処理など)を追加するような実装をする事ができます。

extends+子クラスでtraitを使用

trait Logger {
    public function log($message) {
        echo "[LOG]: " . $message . "\n";
    }
}

class BaseClass {
    public function greet() {
        echo "Hello from BaseClass\n";
    }
}

class ChildClass extends BaseClass {
    use Logger;  // trait を追加

    public function sayGoodbye() {
        echo "Goodbye from ChildClass\n";
    }
}

// インスタンス化
$child = new ChildClass();
$child->greet();       // 出力: Hello from BaseClass
$child->log("Test");   // 出力: [LOG]: Test
$child->sayGoodbye();  // 出力: Goodbye from ChildClass

extends+子クラスでtraitを複数使用

trait Logger {
    public function log($message) {
        echo "[LOG]: " . $message . "\n";
    }
}

trait Notifier {
    public function notify($message) {
        echo "[NOTIFY]: " . $message . "\n";
    }
}

class BaseClass {
    public function greet() {
        echo "Hello from BaseClass\n";
    }
}

class AdvancedClass extends BaseClass {
    use Logger, Notifier;  // 複数のトレイトを使用

    public function process() {
        echo "Processing data...\n";
    }
}

$adv = new AdvancedClass();
$adv->greet();          // 出力: Hello from BaseClass
$adv->log("Logging");   // 出力: [LOG]: Logging
$adv->notify("Alert!"); // 出力: [NOTIFY]: Alert!
$adv->process();        // 出力: Processing data...

extends+親クラスでtraitを使用

trait Logger {
    public function log($message) {
        echo "[LOG]: " . $message . "\n";
    }
}

class ParentClass {
    use Logger;  // 親クラスにトレイトを組み込む

    public function commonMethod() {
        echo "Common method in ParentClass\n";
    }
}

class SubClass extends ParentClass {
    public function customMethod() {
        echo "Custom method in SubClass\n";
    }
}

$instance = new SubClass();
$instance->commonMethod(); // 出力: Common method in ParentClass
$instance->log("Info");    // 出力: [LOG]: Info
$instance->customMethod(); // 出力: Custom method in SubClass

トレイトのメソッドオーバーライド

trait Logger {
    public function log($message) {
        echo "[LOG]: " . $message . "\n";
    }
}

class ParentClass {
    use Logger;
    
    public function log($message) {
        echo "[ParentClass LOG]: " . $message . "\n";
    }
}

class SubClass extends ParentClass {
    public function log($message) {
        echo "[SubClass LOG]: " . $message . "\n";
    }
}

$instance = new SubClass();
$instance->log("Test message"); // 出力: [SubClass LOG]: Test message

SubClassにメソッドがなく、親クラスとtraitクラスでメソッドが競合した場合は、親クラスのメソッドが優先されるのでご注意!

ではtraitクラスのメソッドを使用したい場合はどうすれば良いか?

insteadofまたはasを使用するといいでしょう。

insteadof

class ChildClass extends ParentClass {
    use TraitExample {
        TraitExample::sayHello insteadof ParentClass;
    }
}

$child = new ChildClass();
$child->sayHello();  // 出力: Hello from Trait

ParentClassよりもtraitクラスであるTraitExampleのsayHelloメソッドを優先することを明示的に示す事ができます。

as

class ChildClass extends ParentClass {
    use TraitExample {
        sayHello as sayHelloFromTrait;
    }
}

$child = new ChildClass();
$child->sayHello();           // 出力: Hello from ParentClass
$child->sayHelloFromTrait();  // 出力: Hello from Trait

traitクラスであるTraitExampleのsayHelloメソッド名をasを使用して変更しています。これによりメソッド名の競合を避ける事ができます。

読んでいただきありがとうございました!
これからも自分のペースで記事を更新したり、新たな記事を書いていこうと思うので是非見ていただけたらなと思います!:grin:

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?