🐘

PHP入門 ~オブジェクト指向編~

5 min read

クラス

クラスとはプログラムの処理をまとめたオブジェクトのことであり、よく設計図に例えられる。
クラスを定義する際には以下のように定義する。

class クラス名 { }

クラスから作成されたオブジェクトのことを「インスタンス」といい、インスタンスを作成するためには「new」を使用する。
インスタンスを作成する前にクラスが定義せれている必要がある。

$instance = new クラス名;

オブジェクト指向のアプリケーションを作成する場合にはクラスごとにPHPのファイルを作成することが多いが、必要なクラスを読み込むための記述が冗長になってしまう。
これを避けるために「spl_autoload_register()」関数を使うことが推奨される。

クラスの中で定義されたメンバ変数は「プロパティ」、関数は「メソッド」という。
プロパティには初期値を設定することができるが、初期値は必ず定数値でなければならない。
またプロパティの定義に方宣言を含めることができる。

クラスのメソッドから静的ではないプロパティへアクセスする際には「->(オブジェクト演算子)」を使う必要がある。静的なプロパティへのアクセスの場合には「::(ダブルコロン)」を使用する。

値が変更できない定数をクラス内に定義することが可能で、このクラス定数はインスタンス単位ではなくクラス単位で割り当てられる。

class SimpleClass
{
    // プロパティの宣言
    public $var = 'a default value';
    public int $id;
    // メソッドの宣言
    public function displayVar() {
        echo $this->var;
    }
    const CONSTANT = 'constant value';
    
    function showConstant() {
        echo self::CONSTANT;
  }
}

メソッドがオブジェクトのコンテキストからコールされる場合は、 疑似変数 $this が利用可能である。

プロパティを設定する際にはアクセス権を設定する。

  • public
    「public」で定義されたプロパティはどこからでもアクセスができる。
  • private
    「private」で定義されたプロパティはそのクラス内でのみアクセスできる。
  • protected
    「protected」で定義されたプロパティはそのクラス内と継承したクラス内、親クラスからアクセスできる。

メソッドも「public」「private」「protected」のアクセス権を設定できる。

PHP7以降では定数にも「public」「private」「protected」のアクセス権を設定できる。

クラスのプロパティとメソッドはそれぞれ別の「名前空間」に存在するため同じ名前のプロパティとメソッドを共存させることができる。

class Hogehoge {
    public $bar = "property";

    public function bar() {
        return "method";
    }
}
$obj = new Hogehoge();
echo $obj->bar;   // property
echo $obj->bar(); // method

つまり基本的にプロパティには無名関数を代入できない


継承

継承とはクラスの宣言時に「extends」というキーワードを記入することで、他のクラスの定数・メソッド・プロパティなどを引き継ぐことをいう。

class Mogemoge extends Hogehoge {
    // 親クラスのメソッドを再定義(オーバーライド)
    public function bar() {
        return "extended method";
    }
}

継承元のクラスを「親クラス」、継承先のクラスを「子クラス」という。
ただし多重継承はできず、クラスが継承できるベースクラスは1つのみである。

継承された定数やメソッド、プロパティをオーバーライドするには親クラスで定義されているのと同じ名前でそれを再宣言する。
ただしメソッドが「final」で定義されている場合にはオーバーライドできない。
オーバーライドされた元のメソッドや静的なプロパティにアクセスするには「parent::」で参照する。

オーバーライドする際、子クラスは親クラスに対して互換性がなければならない。
引数の初期値を子クラスのメソッドで設定したり、必須項目ではない引数を追加したりする分には互換性は失われないが、引数を削除したり必須項目の引数を増やしたりすると互換性が失われる。

class Base{
    public function foo(int $a = 5) {
        echo "Valid\n";
    }
}
class Extend_1 extends Base{
    function foo()  // 引数の削除
    {
        parent::foo(1);
    }
}
class Extend_2 extends Base{
    function foo(int $a = 5, $b)  // 必須引数の追加
    {
        parent::foo(1);
    }
}

コンストラクタ・デストラクタ

コンストラクタ

コンストラクタとはメソッドの一種であり、コンストラクタメソッドを含むクラスから新たにオブジェクトが生成されるたびにこのメソッドがコールされる。

つまり、対象のオブジェクトを使用する前に必要な初期化を行える

コンストラクタは一つのクラスにつき一つのみサポートされる。

class IncludeConstructClass {
    protected int $x;
    protected int $y;

    public function __construct(int $x, int $y = 0) {
        $this->x = $x;
        $this->y = $y;
    }
}

デストラクタ

デストラクタはオブジェクトが参照されなくなったときに実行されるメソッドである。

スクリプトの最後の行まで実行が終わったタイミングや作成したインスタンスに「null」が代入されたり、「unset」関数が実行された場合にデストラクタメソッドが実行される。

class IncludeDestructClass 
{
    function __construct() {
        print "In constructor\n";
    }

    function __destruct() {
        print "Destroying " . __CLASS__ . "\n";
    }
}

「__construct」や「destruct」のように「」から始まるメソッドのことを「マジックメソッド」といい普通のメソッドとは異なり、特殊な状況に対応したメソッドである。

メソッド 実行される状況
__construct() インスタンスが生成されるとき
__destruct() インスタンスが破棄されるとき
__call() アクセス不能な非staticメソッドを実行しようとしたとき
__callStatic() アクセス不能なstaticメソッドを実行しようとしたとき
__get() アクセス不能なプロパティからデータを読み込もうとしたとき
__set() アクセス不能なプロパティにデータを格納しようとしたとき
__isset() アクセス不能なプロパティに対してisset()、あるいは、empty()を実行しようとしたとき
__unset() アクセス不能なプロパティに対してunset()を実行しようとしたとき
__sleep() インスタンスに対してserialize()を実行したとき
__wakeup() インスタンスに対してunserialize()を実行したとき
__srialize() クラスが__serialize()を持ちシリアル化する前
__unsrialize()
__toString() インスタンスを文字列に変換しなければならないとき
__invoke() インスタンスを関数のように実行しようとしたとき
__set_state() インスタンスに対してvar_export()を実行しようとしたときこのメソッドはstatic
__clone() cloneキーワードを使ってインスタンスのクローン生成を実行したとき
__debugInfo() なし

nullsafe演算子

PHP8.0.0以降のPHPでは「nullsafe演算子(?->)」を使ってプロパティやメソッドにアクセスすることができる。
nullsafe演算子を使うことによって、アクセスしようとしたオブジェクトがnullの時に例外がスローされるのではなくnullが返される。
nullsafe演算子を使うことによって「is_null()」でいちいちラップをする必要がなくなりコードがすっきりするというメリットがある。

// PHP 8.0.0以降は「nullsafe演算子」が使える
$result = $repository?->getUser(5)?->name;

// PHP 8.0.0未満の場合「is_null()」でラップする必要がある
if (is_null($repository)) {
    $result = null;
} else {
    $user = $repository->getUser(5);
    if (is_null($user)) {
        $result = null;
    } else {
        $result = $user->name;
    }
}
// どちらも同じ意味の処理

PHP8以降の話なので余裕がある人のみ覚えておくと尚可

Discussion

ログインするとコメントできます