PHP クラス編② 静的メンバ・継承の仕組み

前回の記事では、クラスの基本やコンストラクタについて整理しました。

今回はその応用として、「静的メンバ」と「継承」について取り上げます。

静的メンバは、インスタンスを生成せずに使える便利な仕組みで、効率的なコードを書くうえで役立ちます。

また、継承を使えば、既存のクラスの機能を引き継ぎつつ、新しい機能を追加することができます。

基礎を踏まえたうえで、オブジェクト指向の仕組みにもう少し踏み込んでみます。

目次

カプセル化・静的メンバ

カプセル化

カプセル化とは、オブジェクトの中のデータを隠蔽し、意図しない変更や不整合を防ぐための仕組みです。

隠されたプロパティにアクセスするには、「アクセスメソッド」と呼ばれる専用のメソッドを使います。

アクセスメソッドには、値を設定するセッター(setter)と、値を取得するゲッター(getter)があり、プロパティ名に合わせて命名します。

// プロパティ $name に対応
setName() // セッター
getName() // ゲッター

// プロパティ $age に対応
setAge()
getAge()

以下、簡単なサンプルです。

class Person {
  private $name;

  // セッター
  function setName($name) {
    $this->name = $name;
  }
  // ゲッター
  function getName() {
    return $this->name;
  }
}

// インスタンスの生成
$p = new Person();
$p->setName("山田太郎");
echo "名前:{$p->getName()}";

実行結果

名前:山田太郎

静的メンバ

インスタンスを生成して使うメソッドやプロパティのことを「インスタンスメンバ」と言います。

一方で、インスタンスを作らずに使えるのが「静的メンバ(クラスメンバ)」です。

静的メンバの定義は、メンバの先頭にstatic修飾子をつけるだけです。

class Car {
  private $serial = 0; // 製造番号(インスタンスプロパティ)
  private static $carNumber = 0; // 生産台数(静的プロパティ)
  // コンストラクタ
  function __construct() {
    self::$carNumber++; // 静的メンバの値をインクリメント
    $this->serial = self::$carNumber; // idを決める
  }
  // 自動車の製造番号の表示(インスタンスメソッド)
  function showSerial() {
    echo "  製造番号:{$this->serial}<br>";
  }
  // 自動車の生産台数を求める(静的メソッド)
  static function showCarNumber() {
    $number = self::$carNumber;
    echo "生産台数:{$number}<br>";
  }
}

// 自動車の生産台数の表示
Car::showCarNumber();
// 1台目の自動車の生成
$car1 = new Car();
$car1->showSerial();
// 自動車の生産台数の表示
Car::showCarNumber();
// 3台目までの自動車の生成
$car2 = new Car();
$car2->showSerial();
$car3 = new Car();
$car3->showSerial();
// 自動車の生産台数の表示
Car::showCarNumber();

実行結果

生産台数:0
  製造番号:1
生産台数:1
  製造番号:2
  製造番号:3
生産台数:3

クラス内から静的メンバを使う(self::)

クラス内から静的メンバを呼び出す場合、先頭にself::を付けます。

function __construct() {
  self::$carNumber++; // 静的メンバの値をインクリメント
  $this->serial = self::$carNumber; // idを決める
}

クラス外から静的メンバを使う(クラス名::)

クラス外から静的メンバを使うときは、「クラス名::メンバ名」という形式で呼び出します。

// 静的メソッドの呼び出し
Car::showCarNumber();

ポイントまとめ

スクロールできます
比較項目静的メンバ(static)インスタンスメンバ
属する先クラス自体各インスタンス(オブジェクト)
存在数クラスに対して1つだけインスタンスごとにそれぞれ持つ
アクセス方法(内)self::を使う$this->を使う
アクセス方法(外)クラス名::を使う$インスタンス名->を使う
newが必要か不要(インスタンスなしでOK)必要(インスタンスが必要)
共有されるか全インスタンスで共有される各インスタンスで別々に保持

継承

継承とは、あるクラス(親)をもとにして、別のクラス(子)を作る仕組みです。

子クラスは、親クラスのプロパティやメソッドをそのまま使うことができます。

// 親クラス
class Vehicle {
  protected $speed = 0;

  public function drive() {
    echo "時速{$this->speed}kmで走っています<br>";
  }
}

// 子クラス
class Car extends Vehicle {
  public $color;

  public function setSpeed($value) {
    $this->speed = $value; // ← OK: protectedなので子クラスでもアクセス可
  }

  public function showColor() {
    echo "この車の色は{$this->color}です<br>";
  }
}

// 使用例
$car = new Car();
$car->color = "赤";
$car->setSpeed(80);  // 子クラス経由でspeedを設定

$car->drive();       // 親クラスのメソッド
$car->showColor();   // 子クラスのメソッド

実行結果

時速80kmで走っています
この車の色は赤です

解説

protectedが付いたメンバは、クラス内もしくは子クラスからは利用することができます。

また、extendsを使うことで、子クラスは親クラスのプロパティやメソッドを継承できます。

class 子クラス名 extends 親クラス名 {
  ...
}

応用:抽象クラスとオーバーライド

抽象クラスは、共通の設計をまとめつつ、子クラスに必ず実装してほしい処理を定めるための仕組みです。

オーバーライドは、親クラスのメソッドの振る舞いを子クラスで変更(上書き)することを指します。

これらを使うことで、より柔軟で拡張性の高いプログラムが書けるようになります。

  • 抽象クラス = 親クラスの“ひな型”だけを決めておき、子クラスに中身をまかせる
  • オーバーライド = 親クラスのメソッドを子クラスで上書き(変更)する
// 抽象クラスの定義(インスタンスは作れない)
abstract class Animal {
  // 抽象メソッド(子クラスで必ず実装する必要がある)
  abstract public function makeSound();

  // 具象メソッド(共通の処理)
  public function sleep() {
    echo "眠っています<br>";
  }
}

// 子クラスで抽象メソッドを実装
class Dog extends Animal {
  public function makeSound() {
    echo "ワンワン!<br>";
  }
}

class Cat extends Animal {
  // メソッドのオーバーライド(親クラスのsleepを変更)
  public function sleep() {
    echo "丸くなって眠っています<br>";
  }

  public function makeSound() {
    echo "ニャー<br>";
  }
}

// 使用例
$dog = new Dog();
$dog->makeSound();  // ワンワン!
$dog->sleep();      // 眠っています

$cat = new Cat();
$cat->makeSound();  // ニャー
$cat->sleep();      // 丸くなって眠っています(オーバーライド)

抽象クラスの解説

// 抽象クラスの書式
abstract class クラス名 {
  ...
  abstract アクセス修飾子 function 抽象メソッド(引数);
  ...
}

抽象クラスは、クラス名とメソッドの前にabstract修飾子を付けて定義します。

抽象メソッドには処理を記述しないため、必ず子クラスで実装(オーバーライド)しなければなりません。

そのため、抽象クラスは直接インスタンス化できない仕組みになっています。

オーバーライドの解説

class Animal {
  public function sleep() {
    echo "眠っています<br>";
  }
}

class Cat extends Animal {
  // オーバーライド:親クラスのsleepメソッドを上書き
  public function sleep() {
    echo "丸くなって眠っています<br>";
  }
}

オーバーライドとは、子クラスで親クラスにあるメソッドと同じ名前・引数・戻り値の型を持つメソッドを定義し、元の処理を上書きすることです。

抽象クラスでは、このオーバーライドの仕組みを使って、抽象メソッドの具体的な処理を子クラスに実装させます。

クラスの応用まとめ

静的メンバは、インスタンスを作らずに使えるため、共通処理や定数の管理に便利です。

一方、継承を使えば、共通する処理を親クラスにまとめることで、コードの重複を避け、保守性を高めることができます。

どちらもオブジェクト指向を活かした設計に欠かせない要素なので、場面に応じてうまく使い分けていきたいところです。

おすすめWEBスクール

WEB制作やWEBデザインを学びたいなら、SNSでも話題の「デイトラ」がおすすめ!
どのコースも10万円前後と業界最安値で、副業や転職に向けて十分なスキルを身につけることができます。

役に立ったら他の方にシェア

お気軽にコメントどうぞ

コメントする

目次