ch08 8章中 8章目

ch08 — final クラス / final メソッド

スライドで見る

この章を AI と学ぶ

💬 AI に聞く質問例 3 件
  1. 「ch08 — final クラス / final メソッド」のつまずきやすいポイントを、初学者向けに3つ教えてください

    ChatGPT Claude Gemini

  2. 「ch08 — final クラス / final メソッド」について、自分の手で試せる練習問題を3つ出してください (難易度を上げながら)

    ChatGPT Claude Gemini

  3. 「ch08 — final クラス / final メソッド」を学んだ後、次に学ぶと良いトピックは何ですか?理由も教えてください

    ChatGPT Claude Gemini

概要

final 修飾子は 「これ以上の拡張を禁止する」 ための宣言で、クラスに付ければ extends できなくなり、メソッドに付ければそのメソッドのオーバーライドができなくなる。final class Config { ... } と書けば誰も Config を継承して挙動を差し替えられず、final public function save() と書けば子クラスが save() を上書きすることを防げる。「ここは変えてほしくない」と意図を コードで明示 できるのが final の役割になる。

なぜ拡張を禁止したいのかというと、Liskov 置換原則 (LSP) が守られない継承を未然に防ぐためだ。継承は強力だが、子クラスが親の前提を壊すように書かれると「親型として扱える」性質が崩れ、呼び出し側で予期しない動作になる。クラスを公開する側が「このクラスは継承を想定していない」と判断したなら、final class にしておくことで誤った継承を防げる。

実務的には すべての公開クラスを最初から final にして、必要になったときだけ外す という方針もよく採られる。クラスを継承可能にすると、後で内部実装を変えにくくなる (子クラスが内部メソッドに依存しているかもしれない) ので、迷ったら拡張を閉じる側に倒すという考え方だ。継承よりもインターフェース + コンポジションで拡張点を作る、というモダンな設計とも相性がよい。

学習目標

  • final class継承を禁止 する
  • final function はそのメソッドの オーバーライドを禁止 する
  • 「これ以上拡張させない」と意図を明示できる

ドリル

no 内容
01 final class を作って単一インスタンスを生成・出力する

解説スライド 全 6 枚

右の ボタン キー(またはスワイプ)で次のスライドに進めます。 下の「縦表示」を開くと全スライドを一気に読めます。

  1. final クラス / final メソッド

    Lesson 9 / Chapter 8

  2. 継承されると困るクラスがある

    <?php
    class Logger {
        public function log(string $msg) {
            echo "[LOG] $msg\n";
        }
    }
    
    class BadLogger extends Logger {
        public function log(string $msg) {
            // パスワードを画面に出してしまう実装に変えられてしまった!
            echo "[LEAK] $msg\n";
        }
    }
    • 継承できると、第三者にどんな振る舞いに変えられるか分からない
    • セキュリティ上、改造を禁じたいときがある
  3. final class で継承を禁止

    <?php
    final class Logger {
        public function log(string $msg) {
            echo "[LOG] $msg\n";
        }
    }
    
    class BadLogger extends Logger {   // ❌ Fatal error
    }
    • class の前に final を付ける
    • このクラスを継承しようとした瞬間にエラー
    • 「これは設計が完成しているので、改造禁止」という意思表示
  4. final メソッドはオーバーライドを禁止

    <?php
    class Logger {
        final public function log(string $msg) {
            echo "[LOG] $msg\n";
        }
    }
    
    class TimedLogger extends Logger {
        public function log(string $msg) {   // ❌ Fatal error
            echo "...\n";
        }
    }
    • クラス自体は継承できる
    • でも 特定のメソッドだけ はオーバーライドさせない
    • 「ここの動きは絶対変えるな」という保護
  5. 使い分け

    やりたいこと
    final class クラスごと拡張不可にする
    final function クラスは継承可、でもこのメソッドだけ変えさせない

    「外部に公開する設計済みクラス」「金額計算など壊されたら困る処理」に有効。

  6. このチャプターでできるようになること

    final class で継承を禁止できる ✅ final function でオーバーライドを禁止できる ✅ 「拡張されたら困る箇所」に意図を明示できる

    → ドリルへ

1 / 6
📜 スライドを全部一気に読む(縦表示)

Lesson 9 / Chapter 8


継承されると困るクラスがある

<?php
class Logger {
    public function log(string $msg) {
        echo "[LOG] $msg\n";
    }
}

class BadLogger extends Logger {
    public function log(string $msg) {
        // パスワードを画面に出してしまう実装に変えられてしまった!
        echo "[LEAK] $msg\n";
    }
}
  • 継承できると、第三者にどんな振る舞いに変えられるか分からない
  • セキュリティ上、改造を禁じたいときがある

final class で継承を禁止

<?php
final class Logger {
    public function log(string $msg) {
        echo "[LOG] $msg\n";
    }
}

class BadLogger extends Logger {   // ❌ Fatal error
}
  • class の前に final を付ける
  • このクラスを継承しようとした瞬間にエラー
  • 「これは設計が完成しているので、改造禁止」という意思表示

final メソッドはオーバーライドを禁止

<?php
class Logger {
    final public function log(string $msg) {
        echo "[LOG] $msg\n";
    }
}

class TimedLogger extends Logger {
    public function log(string $msg) {   // ❌ Fatal error
        echo "...\n";
    }
}
  • クラス自体は継承できる
  • でも 特定のメソッドだけ はオーバーライドさせない
  • 「ここの動きは絶対変えるな」という保護

使い分け

やりたいこと
final class クラスごと拡張不可にする
final function クラスは継承可、でもこのメソッドだけ変えさせない

「外部に公開する設計済みクラス」「金額計算など壊されたら困る処理」に有効。


このチャプターでできるようになること

final class で継承を禁止できる ✅ final function でオーバーライドを禁止できる ✅ 「拡張されたら困る箇所」に意図を明示できる

→ ドリルへ

この章で取り組む 演習問題の流れ (1ステップ)
  1. 01 ドリル 01 — final class でインスタンスを作る README.md starter.php answer.php

演習問題の詳細

この章の演習問題の内容を読めます。実際に手元で解くには教材リポジトリを clone してください。

ドリル 01 — final class でインスタンスを作る

問題

Logger クラスを final を付けて定義してください。

  • メソッド log(string $msg)"[LOG] {msg}" を 1 行出力する

Logger のインスタンスを作って、log("started") を呼んでください。

期待される出力:

[LOG] started

メモ

  • final class を継承しようとすると Fatal error になります
  • このドリルでは「final を付けても インスタンス化と通常メソッド呼び出しは普通にできる」ことを確認します

ヒント

  • final class Logger { ... }
  • $l = new Logger();
  • $l->log("started");

🧪 ブラウザで試す

スライドのコードを写経して ▶ 実行、自分で書いて 📝 採点 で答え合わせ。初回のみ PHP ランタイム読込で数秒かかります。

PHP ランタイム未読込

          

        

演習問題(1問)

  1. ドリル 01 — final class でインスタンスを作る

    README.md starter.php answer.php

サイト内で問題文・雛形・解答例を確認できます。実際に手元で解くには教材リポジトリを clone してください。

完了にすると進捗に反映されます