関数の定義(function)
関数はひとまとまりの処理に名前を付けて再利用できるようにする仕組みです。『PHP』では『function』キーワードで関数を定義し、引数のデフォルト値・可変長引数・型宣言などを組み合わせて安全で読みやすいコードを書けます。
構文
// 基本的な関数定義
function 関数名(引数1, 引数2) {
// 処理
return 戻り値;
}
// デフォルト値付き引数
function 関数名($param = デフォルト値) {
// $param が省略された場合はデフォルト値が使われます
}
// 型宣言(引数型・戻り値型)
function 関数名(型 $param): 戻り値型 {
// ...
}
// 可変長引数(スプレッド構文)
function 関数名(...$args) {
// $args は配列として受け取ります
}
構文・機能一覧
| 構文・機能 | 概要 |
|---|---|
| function | 関数を定義するキーワードです。定義した関数はファイル内のどこからでも呼び出せます。 |
| return | 関数の処理を終了して呼び出し元に値を返します。値を省略すると『null』を返します。 |
| デフォルト値 | 引数を省略した際に使われる値を『=』で指定します。デフォルト値を持つ引数は必ず引数リストの末尾に置く必要があります。 |
| 型宣言(引数) | 引数名の前に型名を書くことで、渡せる値の型を制限できます。型が一致しない場合はエラーになります。 |
| 戻り値型宣言 | 引数リストの閉じ括弧の後に『: 型名』を書くことで、戻り値の型を宣言できます。 |
| 可変長引数(...) | 引数名の前に『...』を付けると、任意の数の引数を配列としてまとめて受け取れます。 |
| declare(strict_types=1) | ファイルの先頭に書くと厳格な型チェックが有効になります。型が一致しない場合は暗黙の型変換が行われず、即座にエラーになります。 |
主な型宣言の種類
| 型名 | 概要 |
|---|---|
| int | 整数型です。 |
| float | 浮動小数点数型です。 |
| string | 文字列型です。 |
| bool | 論理値型(true / false)です。 |
| array | 配列型です。 |
| ?型名 | null 許容型です。指定した型または null を受け付けます。例:『?string』は文字列または null です。 |
| void | 戻り値型にのみ使用できます。関数が値を返さないことを宣言します。 |
| mixed | 任意の型を受け付けます。型を限定しない場合に使用します。 |
サンプルコード
function_basic.php
<?php
// 基本的な関数定義と呼び出しです
// エヴァンゲリオンのパイロット名とエヴァ号機番号を組み合わせた文字列を返します
function formatPilot(string $pilotName, int $unitNumber): string {
return $pilotName . "(エヴァンゲリオン第" . $unitNumber . "号機)";
}
echo formatPilot("碇シンジ", 1) . "\n";
echo formatPilot("綾波レイ", 0) . "\n";
echo formatPilot("惣流・アスカ・ラングレー", 2) . "\n";
実行すると次のように出力されます。
php function_basic.php 碇シンジ(エヴァンゲリオン第1号機) 綾波レイ(エヴァンゲリオン第0号機) 惣流・アスカ・ラングレー(エヴァンゲリオン第2号機)
function_default.php
<?php
// デフォルト値付き引数の例です
// 同期率の引数を省略した場合、デフォルト値の 0.0 が使われます
function reportSync(string $pilotName, float $syncRate = 0.0): string {
if ($syncRate === 0.0) {
return $pilotName . ": 同期率未測定";
}
return $pilotName . ": 同期率 " . $syncRate . "%";
}
// 第2引数を渡した場合
echo reportSync("碇シンジ", 141.7) . "\n";
// 第2引数を省略した場合(デフォルト値 0.0 が使われます)
echo reportSync("鈴原トウジ") . "\n";
実行すると次のように出力されます。
php function_default.php 碇シンジ: 同期率 141.7% 鈴原トウジ: 同期率未測定
function_variadic.php
<?php
// 可変長引数(...)の例です
// 任意の数のパイロット名を受け取り、出撃命令を表示します
function orderLaunch(string $commander, string ...$pilots): void {
echo $commander . " から出撃命令:\n";
foreach ($pilots as $pilot) {
echo " - " . $pilot . " 出撃せよ\n";
}
}
// パイロットを1名だけ指定した場合
orderLaunch("葛城ミサト", "碇シンジ");
echo "\n";
// パイロットを複数指定した場合
orderLaunch("葛城ミサト", "碇シンジ", "綾波レイ", "惣流・アスカ・ラングレー");
実行すると次のように出力されます。
php function_variadic.php 葛城ミサト から出撃命令: - 碇シンジ 出撃せよ 葛城ミサト から出撃命令: - 碇シンジ 出撃せよ - 綾波レイ 出撃せよ - 惣流・アスカ・ラングレー 出撃せよ
function_strict_types.php
<?php
// strict_types=1 を宣言すると厳格な型チェックが有効になります
// 型が一致しない場合は暗黙変換されずにエラーになります
declare(strict_types=1);
function calcDamage(int $baseAttack, float $multiplier): float {
return $baseAttack * $multiplier;
}
// 正しい型で呼び出した場合
$damage = calcDamage(3000, 1.5);
echo "ダメージ: " . $damage . "\n"; // 4500 と出力されます
// strict_types=1 がない場合、文字列 "3000" は整数に自動変換されます
// strict_types=1 がある場合は TypeError になります
// $damage = calcDamage("3000", 1.5); // TypeError: Argument #1 must be of type int
実行すると次のように出力されます。
php function_strict_types.php ダメージ: 4500
function_recursive.php
<?php
// 再帰関数の例です
// 関数が自分自身を呼び出すことで繰り返し処理を実現します
// 使徒の「コアへのダメージ倍率」を段階的に計算する階乗を例にします
function factorial(int $n): int {
// 再帰の終了条件(ベースケース)です
// これがないと無限ループになるため必ず用意します
if ($n <= 1) {
return 1;
}
// 自分自身を呼び出して計算を繰り返します(再帰呼び出し)
return $n * factorial($n - 1);
}
// factorial(5) = 5 * 4 * 3 * 2 * 1 = 120
echo "5! = " . factorial(5) . "\n";
echo "10! = " . factorial(10) . "\n";
// フィボナッチ数列も再帰で書けます
function fibonacci(int $n): int {
if ($n <= 1) {
return $n;
}
return fibonacci($n - 1) + fibonacci($n - 2);
}
echo "フィボナッチ数列(第10項): " . fibonacci(10) . "\n";
実行すると次のように出力されます。
php function_recursive.php 5! = 120 10! = 3628800 フィボナッチ数列(第10項): 55
よくあるミス
デフォルト値なしの引数をデフォルト値ありの引数より後ろに置く
デフォルト値なしの必須引数をデフォルト値ありの引数より後ろに定義すると、PHPが警告またはエラーを出します。デフォルト値ありの引数は必ず引数リストの末尾にまとめます。
ng_func_default.php
<?php
// デフォルト値なしの $unitNumber がデフォルト値ありの $title より後ろになっている
function formatPilot(string $pilotName, string $title = "パイロット", int $unitNumber): string {
return $pilotName . "(" . $title . " / 第" . $unitNumber . "号機)";
}
echo formatPilot("碇シンジ", "エヴァ初号機パイロット", 1) . "\n";
実行すると次のように出力されます。
php ng_func_default.php Deprecated: Optional parameter $title declared before required parameter $unitNumber in ng_func_default.php on line 3 碇シンジ(エヴァ初号機パイロット / 第1号機)
デフォルト値なしの引数を前に、デフォルト値ありの引数を後ろにまとめます。
ok_func_default.php
<?php
// 必須引数を前に、デフォルト値ありの引数を後ろにまとめる
function formatPilot(string $pilotName, int $unitNumber, string $title = "パイロット"): string {
return $pilotName . "(" . $title . " / 第" . $unitNumber . "号機)";
}
echo formatPilot("碇シンジ", 1) . "\n";
echo formatPilot("綾波レイ", 0, "零号機パイロット") . "\n";
実行すると次のように出力されます。
php ok_func_default.php 碇シンジ(パイロット / 第1号機) 綾波レイ(零号機パイロット / 第0号機)
再帰関数に終了条件を書かない
再帰関数に終了条件(ベースケース)がないと、関数が自分自身を無限に呼び出し続けてメモリが枯渇します。
ng_func_recursive.php
<?php
// ベースケースがないため無限再帰になる
function countdown(int $n): void {
echo $n . "\n";
countdown($n - 1); // 0 以下になっても止まらない
}
countdown(3);
実行すると次のように出力されます。
php ng_func_recursive.php 3 2 1 0 -1 ...(Fatal error: Maximum function nesting level of '512' reached まで続く)
再帰を止める終了条件を関数の先頭に書きます。
ok_func_recursive.php
<?php
function countdown(int $n): void {
// 終了条件: n が 0 以下になったら再帰を止める
if ($n <= 0) {
echo "発進!\n";
return;
}
echo $n . "\n";
countdown($n - 1);
}
countdown(3);
実行すると次のように出力されます。
php ok_func_recursive.php 3 2 1 発進!
strict_types=1 なしで型宣言に頼る
型宣言があっても『declare(strict_types=1)』がない場合、PHPは暗黙的に型変換を行います。文字列 "3000" を int 型の引数に渡してもエラーにならず、予期しない計算結果になることがあります。
ng_func_stricttypes.php
<?php
// strict_types=1 なし: 文字列が暗黙的に int に変換される
function calcDamage(int $baseAttack, float $multiplier): float {
return $baseAttack * $multiplier;
}
$damage = calcDamage("3000", 1.5); // 文字列でも通ってしまう
echo "ダメージ: " . $damage . "\n";
実行すると次のように出力されます。
php ng_func_stricttypes.php ダメージ: 4500
ファイルの先頭に declare(strict_types=1) を書くと型が一致しない場合に TypeError が発生し、バグを早期発見できます。
ok_func_stricttypes.php
<?php
declare(strict_types=1);
function calcDamage(int $baseAttack, float $multiplier): float {
return $baseAttack * $multiplier;
}
$damage = calcDamage(3000, 1.5); // 正しい型で渡す
echo "ダメージ: " . $damage . "\n";
実行すると次のように出力されます。
php ok_func_stricttypes.php ダメージ: 4500
概要
関数を定義する際は『function』キーワードの後に関数名・引数リスト・処理ブロックを書きます。引数にはデフォルト値を設定でき、呼び出し時に省略された場合に使われます。デフォルト値を持つ引数は、持たない引数よりも必ず後ろに置く必要があります。順序を誤るとエラーになるため注意してください。
引数名の前に型名を書くと型宣言になります。ファイル先頭に『declare(strict_types=1)』を記述すると厳格モードになり、型が一致しない引数を渡した場合に暗黙の型変換が行われず即座にエラーになります。strict_types を有効にすることで、意図しない型変換によるバグを早期に発見できます。戻り値型は引数リストの後ろに『: 型名』で宣言でき、値を返さない関数には『void』を使います。
再帰関数は自分自身を呼び出す関数で、階乗やフィボナッチ数列など数学的な処理を簡潔に書けます。再帰を使う場合は必ず終了条件(ベースケース)を設けてください。終了条件がないと無限ループになりメモリが枯渇します。無名関数(クロージャ)については『Closure / 無名関数』、クラスのメソッド定義については『class』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。