のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

<php>get_object_varsを共通のスーパークラスのメソッドに実装するときの注意

概要

PHP8においてインスタンスの情報を取得するメソッドにget_object_varsがあり、これを使えば引数に渡したインスタンスのもつアクセス可能なプロパティについてArray型で出力してくれる。

これはDTOのようなプロパティ主体で構成されるクラスなんかの共通処理として実装しておけば色々楽になりそうだったので、抽象クラスにget_object_vars($this)を戻り値として返すようなpublicなメソッドを定義した。(オーバライドせずそのまま使用する用途)

問題

継承先のクラスではprivateのプロパティは「アクセス不能」とみなされ取得できない。

誤解いただきたくないのは、上記のようにインスタンス内部で引数を$thisとして当該メソッドをラップしたメソッドを定義して継承元クラスのインスタンスでは 通常のgetterメソッドと同様にprivateだろうが当然アクセスできる。

<?php
  class Test1{
    public function pp(){
        var_dump(get_object_vars($this));
    }
  }
  
  class Test2 extends Test1{
    public $v1='a';
    protected $v2='b';
    private $v3='c';
  }
  $t=new Test2;
  $t->pp();
> array(2) {
  ["v1"]=>
  string(1) "a"
  ["v2"]=>
  string(1) "b"
}

調べるとこれはPHP5で入った変更のようで、継承先のプロパティがprivateであった場合は継承元で定義したget_object_vars()はアクセスできなくなったようだ。

php.adamharvey.name

対策

いまのところ思いつくのは以下2つ

  • protectedにする。
  • 各クラスに直接定義を実装する。

前者が良さそう、個人的にはできるだけプロパティはprivateにしておきたい(でないとOOPの意味が薄くなる)ので。