オーバーロード

オーバーロードとは、引数の後世の違いによって同じ名前のメソッドを分けて呼び出すテクニックです。オーバーライドと似ていますが異なる処理を実行するメソッドが呼ばれるという点が違います。PHPにおけるオーバーロードは、プロパティやメソッドを動的に作成するための手法です。オーバーロードが起動するのは、宣言されていないプロパティやメソッドを操作しようとした時です。

マジックメソッド

PHPには名前とパラメーター、戻り値と呼び出しのタイミングだけが決められたメソッドとして、マジックメソッドというものがあります。外枠だけが設定されている中身がないメソッドです。__construct()や__destruct()もマジックメソッドであり、処理は開発者自身で決めます。
どんなマジックメソッドがあるかを説明と同時に紹介していきます。

オーバーロードで未定義のプロパティの追加と取得をする

マジックメソッドの中に__set()、__isset()、__unset()、__get()、__call()、__callStatic()があり、これらはオーバーロードを行うためのメソッドです。特定の処理がクラスまたはインスタンスに対して行われた時のデフォルトの挙動を上書きします。未定義のプロパティやメソッドが参照された場合はエラーが発生しますが、これらのようなメソッドで上書きするのです。

どういう時にどんな使い方をするかコードを記述しながら覚えましょう。
未定義のプロパティを取得するタイミングで呼ばれる__set()と設定するタイミングで呼ばれる__get()を実装してみますので下記コードを参照してください。

<?php
class Sample {
  private $vals = array();//新たに定義されるプロパティを格納する配列
  public function show(){
    print '<pre>';
    print_r($this->vals);
    print '</pre>';
  }

  public function __set($name, $val){ //$nameは操作しようとしたプロパティの名前
    print "{$name}=>{$val}".'<br>';
    $this->vals[$name] = $val;//未定義のプロパティを配列に格納
  }

  public function __get($name){//$nameは操作しようとしたプロパティの名前
    print "{$name}の値を取得" .' <br>';
    return $this->vals[$name];
  }
}
?>

未定義のプロパティを動的に作成します。

<html>
<head>
<meta charset="utf-8">
<title>オーバーロード</title>
</head>
<body>
  <?php
    require_once "Sample.php";
    $sample = new Sample();
    $sample->user = '佐藤';
    var_dump(isset($sample->user));
    print '<br>';
    unset($sample->user);
    var_dump($sample->user);
  ?>
</body>
</html>

では、magicmethod.phpを表示してみましょう。

__set()によって名前とidがセットされ、__get()によって名前とidが取得され、$valsに格納されたプロパティ名と値が表示されましたね。Sampleクラスにはuserもidも定義されていませんが、このようにオーバーロードを使えば、クラスを作成する時点で定義するプロパティがわからない場合の対処ができるのです。

オーバーロードで未定義のプロパティの確認と削除をする

今度は__isset()で未定義のプロパティの確認、__unset()で未定義のプロパティの削除を行いますが、同時に覚えておかないといけない関数も一緒に紹介します。
__isset()はisset()、empty()を未定義のプロパティに対して実行した場合起動します。
__unset()はunset()を未定義のプロパティに対して実行した場合に起動します。

isset()

isset($val)という風に記述し、$valが変数として宣言されていて且つNULLでなければTRUEを返します。

empty()

empty($val)という風に記述し、$valが空である、つまり変数が存在しない場合や変数の値がFALSEに等しい場合にTRUEを返し、それ以外はFALSEを返します。

unset()

unset($val)という風に記述し、指定した変数の割り当てを解除、破棄します。

では、__isset()と__unset()を実装してみます。

<?php
class Sample {
  private $vals = array();//新たに定義されるプロパティを格納する配列
  public function show(){
    print '<pre>';
    print_r($this->vals);
    print '</pre>';
  }

  public function __set($name, $val){
    print "{$name}=>{$val}".'<br>';
    $this->vals[$name] = $val;//未定義のプロパティを配列に格納
  }

  public function __get($name){
    if(isset($this->vals[$name])){
      print "{$name}の値を取得" .' <br>';
      return $this->vals[$name];
    } else {
      print("{$name}は削除されたか定義されていません。").'<br>';
    }
  }

  public function __isset($name){
    return isset($this->vals[$name]);
  }

  public function __unset($name){
    unset($this->vals[$name]);
  }
}
?>

magicmethod.phpも修正します。

<html>
<head>
<meta charset="utf-8">
<title>オーバーロード</title>
</head>
<body>
  <?php
    require_once "Sample.php";
    $sample = new Sample();
    $sample->user = '佐藤';
    var_dump(isset($sample->user));
    print '<br>';
    unset($sample->user);
    var_dump($sample->user);
  ?>
</body>
</html>

未定義であるプロパティにvar_dump()を使用するとエラーとなるので、__get()も少し修正していることに注意してください。では表示して、それぞれ対処できているか確認しましょう。

オーバーロードで未定義のメソッドを処理する

オーバーロードはプロパティだけでなくメソッドにも使えます。

__call()はアクセスができないメソッドを実行した時に起動します。
__callStatic()はアクセスができない静的メソッドを実行した時に起動します。

例によって使用方法はコードを記述しながら説明していきます。まずは呼び出し側から。

<html>
<head>
<meta charset="utf-8">
<title>オーバーロード</title>
</head>
<body>
  <?php
    require_once "Sample.php";
    $sample = new Sample();
    $sample->user('佐藤');//引数有りで未定義のメソッドをよんで設定
    print $sample->user();//引数無しでメソッドをよんで取得
  ?>
</body>
</html>
<?php
class Sample {
  private $vals = array();//新たに定義されるプロパティを格納する配列
  public function show(){
    print '<pre>';
    print_r($this->vals);
    print '</pre>';
  }

  public function __set($name, $val){
    print "{$name}=>{$val}".'<br>';
    $this->vals[$name] = $val;//未定義のプロパティを配列に格納
  }

  public function __get($name){
    if(isset($this->vals[$name])){
      print "{$name}の値を取得" .' <br>';
      return $this->vals[$name];
    } else {
      print("{$name}は削除されたか定義されていません。").'<br>';
    }
  }

  public function __isset($name){
    return isset($this->vals[$name]);
  }

  public function __unset($name){
    unset($this->vals[$name]);
  }

  public function __call($name, $val){
    if(count($val) === 0){
      return $this->vals[$name];
    }else{
      $this->vals[$name] = $val[0];
    }
  }
}
?>

magicmethod.phpを呼び出すと未定義のメソッドuser()が実行され、名前が表示されましたね。

このように未定義のプロパティやメソッドが呼び出されることを考慮してマジックメソッドを用いて対処しておくとエラーを回避できたり開発に不具合が出にくくなりますね。

コメント

タイトルとURLをコピーしました