【PHP】オーバーロード - PHPは可変長引数リストで類似実装する

【PHP】オーバーロード - PHPは可変長引数リストで類似実装する

多くのプログラミング言語にはオーバーロードと呼ぶ仕組みがあります。

オーバーロードはプログラムに柔軟性・拡張性を生み出すために使いますが、PHPはオーバーロードをサポートしていません。

そのため、PHPプログラムにおいてオーバーロードの仕組みを使いたい場合は、『可変長引数リスト』で同等の処理を実現します。

ここでは、PHPにおける可変長引数リストを使ったオーバーロードの類似実装について解説します。

検証環境

オーバーロード

オーバーロードは“クラスに引数の型・数が異なる同名のメソッドを複数定義すること”です。

オーバーロードを使うことで、引数によって処理を分けることがことができます。

PHPのオーバーロード

オーバーロードの仕組みをサポートするプログラミング言語は多数ありますが、PHPはサポートしていません。

そのため、PHPでオーバーロードに類似した仕組みを実現するには可変長引数リストを利用します。

可変長引数リスト

可変長引数リストは“引数を配列として受け取る仕組み”です。

関数やメソッドの仮引数で使うことができ、呼び出しで渡した実引数を配列として受け取ります。

そのため、引数の数は固定されず、任意の数だけ渡すことができます。

基本構文

function メソッド名( ...$可変長引数リスト名 ) {
    処理
    return 戻り値;
}

可変長引数リストは関数またはメソッドの仮引数として使い、ドット3つ(...)に変数を繋げて記述します。

サンプル

<?php

___ih_hl_start
function addition( ...$numbers ) {
    $total = 0;
    
    foreach( $numbers as $number ) {
        $total += $number;
    }
    
    return $total;
}
___ih_hl_end

___ih_hl_start
$result1 = addition(1,2,3);
___ih_hl_end
echo $result1 . "\n";

___ih_hl_start
$result2 = addition(11,22,33,44,55,66,77,88);
___ih_hl_end
echo $result2 . "\n";

___ih_hl_start
$result3 = addition(99);
___ih_hl_end
echo $result3 . "\n";

?>
$ php sample.php
6
396
99

addition関数は可変長引数リスト(配列)の合計値を返す関数です。

13、16、19行目でaddition関数を呼び出していますが、それぞれ実引数の数が異なります。

通常の引数を用いた場合は、引数の数は固定となってしまいますが、可変長引数リストは引数を配列に格納するため、引数の数に制限されない処理に対応できます。

類似実装

可変長引数リストを使ったオーバーロードの類似実装で、最も一般的な方法はif文を合わせて使う方法です。

<?php

// 人間クラス
class Person {
    
    // 名前
    public $name;
    
    // あいさつ
    ___ih_hl_start
    public function greeting( ...$meta ) {
        
        if( isset($meta[0]) ) {
            if( 6 <= $meta[0] && $meta[0] < 11 ) {
                echo "Good morning!\n";
            } else if( 11 <= $meta[0] && $meta[0] < 16 ) {
                echo "Good afternoon!\n";
            } else {
                echo "Good evening!\n";
            }
        }
        
        if( isset($meta[1]) ) {
            echo "The weather is " . $meta[1] . " today.\n";
        }
        
        echo "My name is ". $this->name . ".\n";
    }
    ___ih_hl_end
    
}

$person = new Person();
$person->name = 'TANAKA';


___ih_hl_start
$person->greeting();
___ih_hl_end
echo "-------------------------\n";
___ih_hl_start
$person->greeting(12);
___ih_hl_end
echo "-------------------------\n";
___ih_hl_start
$person->greeting(12, 'sunny');
___ih_hl_end

?>
$ php sample.php
My name is TANAKA.
-------------------------
Good afternoon!
My name is TANAKA.
-------------------------
Good afternoon!
The weather is sunny today.
My name is TANAKA.

10〜27行目のgreetingメソッドは可変長引数リストを使ったオーバーロードの類似実装です。

isset関数はPHPの標準関数で、配列の任意のキー(インデックス)の存在有無を確認できます。

$meta(配列)のインデックスが0番目と1番目の有無をisset関数で確認し、存在する場合は処理を実行することで、引数の個数によって処理を変えています。

実際に35、37、39行行目のgreetingメソッドの呼び出しは、引数の個数を変えていますが、各個数に対応した処理が実行されます。

この動作・処理の流れはオーバーロードと同等であるため、PHPでは可変長引数リストを利用して、オーバーロードの類似実装を行いますが、PHPがサポートしない=多用は控えるべきと考えられますので、最低限の利用にすることを推奨します。

演習問題

問題1

次の実行結果になる会計クラスを扱うプログラムを作成してください。
なお、下記条件を満たすものとします。

  • 会計クラス(Bill)を作成する
  • 会計クラスはcalcメソッドを持ち、引数で与えられた複数料金の合計金額を出力する
  • calcメソッドの引数は可変長引数リストとする
  • calcメソッドに与えられた引数が3つ以上の場合、合計金額を5%割引する
  • calcメソッドを2回呼び出し、各呼び出しの引数は次の通りとする
    1回目 : 1000, 2300
    2回目 : 1000, 2300, 3500
合計金額 : 3300円
合計金額 : 6460円

問題2

次の実行結果になる自己紹介クラスを扱うプログラムを作成してください。
なお、下記条件を満たすものとします。

  • 自己紹介クラス(SelfIntroduction)を作成する
  • 自己紹介クラスはexecuteメソッドを持ち、引数で与えられた値を元に自己紹介を出力する
  • executeメソッドの引数は可変長引数リストとし、各引数は次の通りとする
    第1引数 : 名前
    第2引数 : 年齢
    第3引数 : 趣味
  • 実行結果になるようにexecuteメソッドを使用する
名前 : Watanabe You
年齢 : 16
趣味 : Training