2回に渡り、PHPのクラスについて基本的な部分を学びました。クラスという設計図を作成することであとはインスタンスを作成すると、似たような実体を複数作成することができました。今回はクラスのもう少し踏み込んだ機能までご紹介します。

PHPのクラス その3

3年以上前に更新されました。情報が古い可能性があります。
更新日 : 2019年03月26日

2回に渡り、PHPのクラスPHPのクラス その2として、クラスの基本的な部分を学びました。クラスという設計図を作成することであとはインスタンスを作成すると、似たような実体を複数作成することができました。

今回はクラスのもう少し踏み込んだ機能までご紹介します。

今までのクラスの問題点

PHPのクラスで作成したモンスタークラスにはいくつか問題があります。バグにはならず、動作はしますが、少し制限がなさすぎるという問題があります。どういうことかをクラスの最初の記事で使用したコードを利用してご説明します。

<?php
// モンスターの設計図(モンスタークラス)
class Monster {

	// モンスターの名前変数
	var $name;
	// モンスターのヒットポイント変数
	var $hitPoint;
	// モンスターの攻撃力変数
	var $attackPoint;
	// モンスターの防御力変数
	var $defensePoint;

	// コンストラクタ
	function __construct($name, $hitPoint, $attackPoint, $defensePoint) {
		// $thisはインスタンス自身を示します
		$this->name = $name;
		$this->hitPoint = $hitPoint;
		$this->attackPoint = $attackPoint;
		$this->defensePoint = $defensePoint;
	}

	// 攻撃する処理
	// 最後にインスタンスで決められた攻撃力を返却します
	function attack() {
		echo $this->name . "は相手のモンスターに" . $this->attackPoint . "ポイントの攻撃を与える!<br>";
		return $this->attackPoint;
	}

	// 防御する処理
	// 引数に敵の攻撃力を入力します
	function defense($enemyAttackPoint) {
		$damage = $enemyAttackPoint - $this->defensePoint;

		$this->hitPoint -= $damage;
		echo $this->name . "は相手のモンスターから" . $damage . "ダメージ受けた!<br>";
		echo $this->name . "の現在のヒットポイントは" . $this->hitPoint . "です。<br>";
	}
}

これが前回のモンスタークラスです。実際にこのクラスを利用していたのが以下のコードです。

<?php
$dragon = new Monster("ドラゴン", 200, 20, 10);
// こちらにはドラゴンより弱い鬼を作ってみました
$oni = new Monster("鬼", 100, 15, 5);

// 鬼の防御とドラゴンの攻撃
$oni->defense($dragon->attack());
echo "<br>";
// ドラゴンの防御と鬼の攻撃
$dragon->defense($oni->attack());

実際には1つのファイルで収めましたが、クラスのインスタンス作成、クラスに用意されている攻撃メソッド(関数)と防御メソッド(関数)を利用して攻防させました。
この時、メソッドを利用する際に$dragon->attack()という形でメソッドを利用しましたが、実は$dragon->nameと記述すると、ドラゴンという名前が利用できます。

このように参照するのは問題ありませんが、$dragon->name = "ゾンビ"と、代入演算子を利用して名前を変更できてしまいます。他に攻撃力や防御力も変更することができてしまいます。

開発者が複数人いた場合を考えてみましょう。モンスタークラスを作成後、別の開発者がモンスタークラスを利用してインスタンスを作成したとします。クラスの作成者は、一度作ったモンスター(名前などの初期値を代入済みのインスタンス)の名前などは変更しないつもりで作成しました。

ところが、現在のクラスの状況だと、インスタンス作成後にもかかわらず、変更できてしまうので、別の開発者は勝手に攻撃力の数値を小さくしてしまう可能性などが考えられます。

この程度のコード量であれば、話し合って解決することができますが、実際のプロジェクトでは何十ファイル、何万行にもなるプログラムを作成する場合があります。その際に、書き換えてはいけないデータを他の開発者が書き換えてしまう可能性があります。

このような場合、エラーのでないバグのように扱われ、プログラムが止まらずに動くのに、動作がおかしいという状況に陥りやすくなります。

アクセス修飾子

先程の問題点は、以下のようなものでした。

  • モンスタークラスを作成した開発者は、モンスタークラスを一度インスタンス化させたら、名前・ヒットポイント・攻撃力・防御力は外部から変更させたくない。
  • 別の開発者が、モンスタークラスを利用しドラゴンという名前のモンスターをインスタンス化したが、途中で名前を変えたくなって、外部から変更できてしまった。

今回のモンスタークラスは外部から変更できないという機能が正しい場合、今のままのコードでは問題があります。

そこで、今回学ぶアクセス修飾子が活躍します。まさに今回のような外部から勝手に値を変更されたり、外部から使用されるべきでないメソッドが合った場合に利用されます。

アクセス修飾子の種類

PHPのアクセス修飾子は3種類あります。以下が一覧です。

記述意味
public (var)自分のクラス内部・継承されたクラス・インスタンスのどれからでもアクセス可能な変数または関数
protected自分のクラス内部・継承されたクラスからアクセス可能な変数または関数
private自分のクラス内部からのみアクセス可能な変数または関数

varを今まで利用してきましたが、こちらはpublicと同じ動作をします。PHPの公式ではvarはなるべく使用せず、アクセス修飾子を適切に付けましょうと推奨されています。

protectedでは継承されたクラスであれば参照や代入などのアクセスが可能です。インスタンスからはアクセスできません。エラーでストップします。

privateでは自分のクラス内部からのみ利用可能です。継承された派生クラス・インスタンスからはアクセスできません。エラーでストップします。

アクセスしてはいけない変数や関数が存在した場合には、エラーで止まらずに、間違えている部分がわかりづらいより、エラーで停止した方が親切でいいはずです。どこの記述が間違えているか一目瞭然になるので。

また、省略すると基本的にpublic扱いになります。それでもpublicと記述してあげた方が他の開発者がコードを読む際は親切になるかと思います。もちろん必須ではありませんが。

このアクセス修飾子はメンバー変数だけではなく、メソッドにも利用可能です。具体的な使い方は下記の内容で見ていきましょう。

アクセス修飾子付きで改良

PHPのクラスで作成したモンスタークラスをアクセス修飾子付きで改良したものが以下になります。

<?php

// モンスターの設計図(モンスタークラス)
class Monster {

	// モンスターの名前変数
	private $name;
	// モンスターのヒットポイント変数
	private $hitPoint;
	// モンスターの攻撃力変数
	private $attackPoint;
	// モンスターの防御力変数
	private $defensePoint;

	// コンストラクタ
	public function __construct($name, $hitPoint, $attackPoint, $defensePoint) {
		// $thisはインスタンス自身を示します
		$this->name = $name;
		$this->hitPoint = $hitPoint;
		$this->attackPoint = $attackPoint;
		$this->defensePoint = $defensePoint;
	}

	// 攻撃する処理
	// 最後にインスタンスで決められた攻撃力を返却します
	public function attack() {
		echo $this->name . "は相手のモンスターに" . $this->attackPoint . "ポイントの攻撃を与える!<br>";
		return $this->attackPoint;
	}

	// 防御する処理
	// 引数に敵の攻撃力を入力します
	public function defense($enemyAttackPoint) {
		$damage = $enemyAttackPoint - $this->defensePoint;

		$this->hitPoint -= $damage;
		echo $this->name . "は相手のモンスターから" . $damage . "ダメージ受けた!<br>";
		echo $this->name . "の現在のヒットポイントは" . $this->hitPoint . "です。<br>";
	}
}

メンバー変数はすべてprivateとしました。こうすることでインスタンスからはアクセスが不可能になりコンストラクタで引数として初期値を渡す以外は、値を変更することができなくなります。

その他攻撃や防御のメソッドではpublicとし、インスタンスからこの処理を実行させることになります。メソッドでもprivateなどを利用することができますが、プライベートなメソッドは、内部のみで利用される場合に使われます。

今回は攻撃も防御も外部(インスタンス)から利用してもらうのが正しいのでpublicで問題ありません。

まとめ

今回はクラスのアクセス修飾子について学んでいきました。アクセス修飾子を適切に利用することによって、インスタンスなどから勝手に変更されるべきではないメンバー変数やメソッドの利用を防ぐことができました。

前回のPHPのクラス その2では、アクセス修飾子を利用して抽象クラスを作成していました。

また、今回の記事でPHPのクラスの基本はほぼ網羅できます。その他機能などは基本から逸脱するため、別の記事で少しづつご説明していきます。