[PHP] Reflection - Method編


Study / PHP    作成日付 : 2020/01/31 03:00:00   修正日付 : 2020/01/31 03:00:00

こんにちは。明月です。


前述でReflectionでクラス<を探してインスタンスを生成する方法、インスタンスの中で変数や関数を探す方法まで説明しました。

link - [PHP] Reflection - Class編


今回はReflectionを利用してクラスで関数を探して実行する方法まで調べてみます。

<?php
  class EXClass {
    public function test() {
      return "test";
    }
    public function test1() {
      return "test1";
    }
    public function test2() {
      return "test2";
    }
  }
  // Query Stringパラメータのparamから値を受取る。
  $param = @$_GET["param"];
  // ReflectionでEXClassを探す。
  $r = new ReflectionClass('EXClass'); 
  // インスタンスを生成する。
  $obj = $r->newInstance();
  // paramパラメータによってtest関数や、test1関数を呼出す。
  $m = $r->getMethod("test".$param);
  // 関数を実行する。(パラメータが無いので、初めのパラメータに実行するインスタンスだけ渡す)
  $data = $m->invoke($obj);
?>
<!DOCTYPE html>
<html>
<head><title>title</title></head>
<body>
  <?=$data?>
</body>
</html>




上の結果をみればQuery Stringのパラメータによって呼出す関数を違うし結果も別で表示されます。

もし、Reflectionがなければ下記とおりに作成したと思います。

$obj = new EXClass();
$data = "";
// Query String paramを受取る。
$param = @$_GET["param"];
// パラメータデータによって呼出す関数を分ける。
if($param == "1") {
	$data = $obj->test1();
} else if($param == "2") {
	$data = $obj->test2();
} else {
	$data = $obj->test();
}

ここでEXClassのクラスの関数が仕様によって増えると考えば「if ~ else」も増えますよ。上の場合は簡単な例なので差をそんなに体感されないですが、拡張的に考えたらもっと複雑なプログラムならすごく複雑なロジックになるでしょう。


Reflection機能でこの関数を動的に呼出すだけではないです。関数がpublicではないアクセス修飾子も呼出すことができます。

<?php
  class EXClass {
    public function test1() {
      return "test";
    }
    private function test2() {
      return "test1";
    }
    protected function test3() {
      return "test2";
    }
  }
  // Reflectionでクラスを探す。
  $r = new ReflectionClass('EXClass'); 
  // インスタンスを生成する。
  $obj = $r->newInstance();
  // インスタンスから「test1」、「test2」、「test3」のメソッドを取得する。
  for($i=1; $i <= 3; $i++) {
    $m = $r->getMethod("test".$i);
    // private、protectedの場合、外部で呼出すができるように設定する。
    $m->setAccessible(true);
    // 関数をインスタンスから呼出す。
    $data[] = $m->invoke($obj);  
  }
?>	
<!DOCTYPE html>	
<html>	
<head>	
<title>title</title>	
</head>	
<body>	
  <?=$data[0]?><br />	
  <?=$data[1]?><br />	
  <?=$data[2]?><br />	
</body>	
</html>


上の例をみれば「test2」と「test3」関数はpublicではなく、privateやprotectedに設定されています。

そうすると基本的にクラス外部では呼出すことができません。でも、Reflectionの「setAccessible」関数を利用してアクセスができるように設定して呼出しました。

<?php
  class EXClass {
    public function test($data, $data1, $data2){
      return "test";
    }
  }
  $r = new ReflectionClass('EXClass'); 
  $obj = $r->newInstance();
  $m = $r->getMethod("test");
  // test関数のパラメータ内訳を出力
  var_dump($m->getParameters());
?>
<!DOCTYPE html>
<html>
<head><title>title</title></head>
<body></body>
</html>


phpの場合はクラスのメソッドのオーバーロード(同じメソッド名にパラメータのタイプと個数で関数を区別すること)がありません。

それで特にReflectionでメソッドを検索する時にパラメータのタイプや個数の情報はいらないです。Invoke関数を呼び出す時にパラメータの数が一致しないとエラーが発生するため、パラメータの検証が必要になる場合があります。

phpの場合は別に変数の型がないので、変数名と個数で検証処理をすれば良いと思います。


link - https://www.php.net/manual/en/class.reflectionmethod.php

最新投稿