PHP - OOP - 5. アクセサメソッド

ここまでのプログラムで $number プロパティに private キーワードを付与することで、プロパティへの直接的な値の代入を禁止することができました。次に、開発の現場でよく使うアプローチとしてアクセサメソッドという手法を紹介します。

アクセサメソッドの定義

図の矢印の方向に注目してください。private$myProperty プロパティにアクセスするために2つのメソッドを追加しています。

  • setMyProperty メソッド
    • $myProperty プロパティに値を代入する
  • getMyProperty メソッド
    • $myProperty プロパティの値を取得する

外部からアクセスできないプロパティに対して、プロパティに対して値を代入するメソッドと値を取得する2つのメソッドを定義しています。これら2つのメソッドのことをアクセサメソッド(Getter/Setterメソッド)などと呼びます。

以前に作成している MyClass.php ファイルにアクセサメソッドを定義してみましょう。

<?php
class MyClass
{
    private $myProperty;

    public function myMethod($x)
    {
        echo $this->myProperty . " " . $x . PHP_EOL;
    }

    public function setMyProperty($myProperty)
    {
        $this->myProperty = $myProperty;
    }

    public function getMyProperty()
    {
        return $this->myProperty;
    }    
}

ここでは $myProperty プロパティに対して setMyProperty メソッドと getMyProperty メソッドの2つをアクセサメソッドとして定義しています。

アクセサメソッドは名前の付け方を工夫します。2つのメソッドが setプロパティ名getプロパティ名 となっている点に注目してください。アクセサメソッドはこのようにアクセス対象となるプロパティに対して値を設定する(setする)メソッドと値を取得する(getする)メソッドとして定義します。

次に呼び出し元のプログラム( my_class_runner.php )からアクセサメソッドを利用する様子を確認してみましょう。

<?php
require_once("MyClass.php");

$myClass = new MyClass();

# $myClass->myProperty = "Hello"; #=> Fatal error

$myClass->setMyProperty("Hello");
echo $myClass->getMyProperty(); # => Hello

以前のようにプロパティへの直接的なアクセスは禁止されていますが、アクセサメソッドを経由して、インスタンスの持つプロパティにアクセスできているのがわかります。

PHPプログラムの開発(アクセサメソッド)

計算機プログラムの例題に戻りましょう。ここでは簡単な計算機クラス( SimpleCalc クラス)に定義済みの $number プロパティについて、アクセサメソッドを定義します。

計算機クラス( SimpleCalc クラス)に以下のようにメソッドを追加します。

<?php
class SimpleCalc
{
    private $number;

    public function setNumber($number)
    {
        $this->number = $number;
    }

    public function getNumber()
    {
        return $this->number;
    }

    public function add($x)
    {
        $this->number = $this->number + $x;
    }

    public function show()
    {
        echo $this->number . PHP_EOL;
    }
}

ここでは private$number プロパティにアクセスするための getNumbersetNumber と2つのメソッドを定義しています。 getNumber メソッドは $number プロパティの値を戻り値で返し、 setNumber メソッドは $number プロパティに引数で受け取った値を保存します。このようなプロパティにアクセスするためのメソッドをアクセサメソッド(あるいはGetter/Setterメソッド)などと呼びます。

続いて実行プログラム( calc_runner.php )の中から実際にアクセサメソッドを呼び出してみましょう。

<?php
require_once("SimpleCalc.php");

$calc = new SimpleCalc();

// $calc->number = 10;
$calc->setNumber(10);

$calc->add(20);
$calc->add(30);
$calc->show();
echo $calc->getNumber() . PHP_EOL;

これまでは $calc->number = 10 のようにプロパティに直接値を代入していましたが、ここでは $calc->setNumber(10) メソッドを呼び出すことで $number プロパティに値を代入するようにしています。同様に $number プロパティの値を取得したい場合も $calc->getNumber() のようにアクセサメソッドを呼び出すようにします。

それではターミナルからプログラムを実行してみましょう。

$ php calc_runner.php
60
60

実行結果から $calc->show() メソッドによる出力と $calc->getNumber() メソッドの戻り値の出力を確認できます。

参考:カプセル化

このようにプロパティのアクセス権を private として外部からの直接的なアクセスを禁止し、メソッド呼び出しを通じて間接的にプロパティを制御することをカプセル化と呼びます。

今回の計算機プログラムにおいては、アクセサメソッドを提供することにあまりメリットが感じられなかったかもしれません。しかしアクセサメソッドを経由してプロパティにアクセスすることで、次のようなプログラミングも可能となります。

    public function setNumber($number)
    {
        if (is_numeric($number)) {
            $this->number = $number;
        }
    }

ここでは setNumber メソッドに if 文による引数のチェックを追加しています。 is_numeric 関数は引数の値が、数字または数値形式の文字列であるかを調べて論理値を返却します。このように実装することで、外部のプログラムから $number プロパティに代入する値を数字(あるいは数値形式の文字列)に限定できます。このようなアクセサメソッドを提供することでプロパティへの不正な値の代入を禁止できます。

またアクセサメソッドは必ずしもGetter、Setterの2つを一緒に定義する必要はありません。プロパティへの値を代入するSetterメソッドだけを定義する場合や、値を取得するGetterメソッドだけを定義する場合もあります。

まとめ

  • アクセサメソッドとは private なプロパティなど外部からアクセスできないプロパティを操作するメソッド
  • プロパティの値を取得するGetterメソッドとプロパティに値を代入するSetterメソッドの2つで構成される
  • Getter/Setterメソッドと呼ぶこともある