PHP 7.2リリース&PHPのアクセス修飾子、アクセサメソッド、カプセル化、コンストラクタWeb業界で働くためのPHP入門(14)(2/3 ページ)

» 2018年02月08日 05時00分 公開

アクセス修飾子とアクセサメソッド

 ここまでクラスについて書いてきましたが、説明していないことがあります。それは「public」です。次に、これについて解説します。

プロパティを隠す

 リスト1では、プロパティに格納する値をsetData()メソッドでまとめてもらえるようになりました。一方で、実行部分から下記のようにプロパティに直接データを格納できます。

$taro->name = "じろう";

 プロパティに直接データを格納できるのは一見便利なように見えますが、実は危ないことです。なぜなら、不正な値を入れられてもチェックができないからです。例えば、TestScoreAdvクラス内のメソッドは「$mathは数値である」ことを前提としてコードを記述しています。実行部分で下記のようなコードを記述したら、その後のメソッド処理は全てエラーとなります。

$taro->math = "数学";

 これを防ぐには、プロパティをクラスの外から隠す必要があります。その方法を簡単なサンプルで見てみましょう。まずはリスト3のPrivatePropertiesクラスを作成してください。

<?php
class PrivateProperties
{
    //数値プロパティ。
    private $num;
 
    //プロパティ$numに値を格納するメソッド。
    public function setNum(int $num): void
    {
        $this->num = $num;
    }
    
    //プロパティ$numの値を取得するメソッド。
    public function getNum(): int
    {
        return $this->num;
    }
}
リスト3 phplesson/chap14/PrivateProperties.php

 今までプロパティの前に付いていたpublicの代わりに、$numには「private」が付いています。このプロパティにデータを入れようとしたらどうなるのでしょうか。privateという記述から想像しながらリスト4のusePrivateProperties.phpを作成し、実行してください。

<?php
require_once("PrivateProperties.php");
 
//PrivatePropertiesインスタンスを生成。
$privateP = new PrivateProperties();
//セッタを使ってプロパティ$numに35を格納。
$privateP->setNum(35);
//ゲッタを使ってプロパティ$numの値を取得し、$ansに格納。
$ans = $privateP->getNum();
//$ansを表示。
print("privateP内のnumの値: ".$ans);
//プロパティに直接値を代入してみようとする。
$privateP->num = 56;
リスト4 phplesson/chap14/usePrivateProperties.php

 実行結果は下記のようにエラーになります。

privateP内のnumの値: 35
Fatal error: Uncaught Error: Cannot access private property PrivateProperties::$num in C:\xampp\htdocs\phplesson\chap14\usePrivateProperties.php:13 Stack trace: #0 {main} thrown in C:\xampp\htdocs\phplesson\chap14\usePrivateProperties.php on line 13
リスト4の実行結果

 11行目までは、ちゃんと処理され表示されています。一方で、13行目でエラーとなっています。

 13行目の処理は、まさにprivateと記述したプロパティnumにデータを格納しようとしている処理であり、プロパティにアクセスできないことを意味します。実際にエラーメッセージは、そのような内容となっています。これで、無事プロパティを隠すことができました。

アクセス修飾子「public」と「private」

 今までクラスの各メンバの最初にpublicと記述していましたが、privateと記述することも可能です。publicやprivateは、メンバへのアクセスを制限するための記述であることから、「アクセス修飾子」と呼ばれています。この2種のアクセス修飾子の違いをまとめると下記のようになります。

  • private:クラス内からのみアクセス可能なメンバ
  • public:クラス外からもアクセス可能なメンバ
図1 privateとpublicの関係

 ここで注意したいのは、privateとpublicは全てのメンバに記述可能なので、この違いはプロパティだけではなくメソッドにも適用できるということです。

アクセサメソッド

 上記のようにプロパティのアクセス修飾子をprivateにすると、不正なデータは外部から格納できなくなり安全ですが、そのプロパティに対して外部からデータを入出力できるようにする必要があります。

 リスト3のPrivatePropertiesクラスでは、setNum()が「データの格納」、getNum()が「データの読み出し」の役割を担っています。これらのメソッドはpublicが付いているので、クラス外からもアクセス可能です。

 実際、リスト4の7行目でsetNum()を使って$privateP内の$numに「35」という値を格納しています。また、9行目でgetNum()を使って$privateP内の$numの値を読み出し、その値を11行目で表示しています。ここまでは正常に処理されています。

図2 リスト4の処理内容

 このようにプロパティに値を格納するメソッドを「セッタ」、読み出すメソッドを「ゲッタ」と言い、両方を併せて「アクセサ」「アクセサメソッド」と言います。

セッタの形

 セッタはプロパティに値を格納するのが主目的のメソッドです。そのため、メソッドの引数はプロパティと同種のもの(通常は引数名も同じにします)を用意し、リスト3の10行目のようにその引数をプロパティに代入する式を記述します。またメソッド名も、「どのプロパティのセッタであるか」を明確にするために、「set+プロパティ名」として、キャメル記法で記述します。

 構文としてまとめると、下記のようになります。

構文 セッタ

public function setプロパティ名(プロパティの型 プロパティと同名の引数): void

{

  $this->プロパティ = 引数;

}


ゲッタの形

 ゲッタも同様に考えることができます。これはプロパティの値を読み出すのが主目的のメソッドなので、引数は不要です。処理内容としては、プロパティを返します。メソッド名も、「getプロパティ名」として、キャメル記法で記述します。

 これも構文としてまとめておきます。

構文 ゲッタ

public function getプロパティ名(プロパティと同名の引数): プロパティの型

{

  return $this->プロパティ;

}


 もちろん、アクセサメソッドは上記内容が基本ですが、それ以上の処理を含めても問題ありません。例えばセッタでは、不正な値が格納できないようなチェック処理を入れても問題ありません。正の数しか受け取らないプロパティなら、下記のように「そのセッタの引数に正の数以外が渡されたらメッセージを表示する」ような処理を入れることもできます。

public function setNum(int $num): void
{
    if($num <= 0) {
        //ここにメッセージを表示するように記述
    }
    else {
        $this->num = $num;
    }
}

 またゲッタでは、プロパティの値を整形した上で返すものを用意することもできます。例えばプロパティが日付データの場合、「2017年12月24日」のように整形した文字列を返す処理も用意できます。

コラム「メソッド引数の型」

 リスト4の$privatePのsetNum()を利用して値を格納する際、例えば下記のようにすると、エラーとなります。

$privateP->setNum("じろう");

 これは、このsetNum()メソッドを定義しているリスト3の8行目で、引数として下記のように記述しているのが原因です。

int $num

 PHPはデータ型を意識しなくてもコーディングできる言語ですが、このような引数や戻り値にデータ型を記述しておくと、実行時にチェックしてくれる機能が備わっています。プロパティそのものにはデータ型を指定できないので、前述のように想定外の型のデータを格納されてしまう可能性があります。その点でも、アクセサメソッド経由でデータをやりとりする方が安全です。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。