PHPのユーザー定義関数

関数とは、簡単に言うと特定の処理をまとめたものです。関数をうまく利用することで効率的にプログラムを組むことができます。PHPには、多くの関数が予め定義されていますが、開発者自身が独自に関数を定義することもできます。開発者が定義する関数をユーザー定義関数といいます。

関数の定義

関数を定義するには、functionキーワードを使用します。関数名や引数名は、PHPの識別子のルールに従う必要があります。また、関数はグローバルスコープに定義されるため、関数名は定義済みの関数と重複しない名前にする必要があります。なお、引数や戻り値は必要なければ省略可能です。

PHP

<?php
function 関数名($引数名1, $引数名2)
{
  処理;
  return 戻り値;
}
?>

PHPでは、基本的に関数定義より前に関数を呼び出しても問題ありませんが、条件付きで定義される関数に関しては、関数が定義されてから呼び出す必要があります。下記の例では、関数fooに関しては定義前に呼び出すことができますが、関数hogeやbarに関しては定義前に呼び出すとFatal errorとなります。

PHP

<?php
foo(); // 出力:foo
function foo()
{
  echo 'foo', PHP_EOL;
}

$hogeEnable = true;
/*
hoge(); // 出力:Fatal error: Call to undefined function hoge()
*/
if ($hogeEnable) {
  function hoge()
  {
    echo 'hoge', PHP_EOL;
  }
}
hoge(); // 出力:hoge

function setBar()
{
  function bar()
  {
    echo 'bar', PHP_EOL;
  }
}
/*
bar(); // 出力:Fatal error: Call to undefined function bar()
*/
setBar();
bar(); // 出力:bar
?>

関数の引数

デフォルトでは、関数の引数は値渡しとなります。下記の例では、関数内の処理で引数で渡された配列の要素の値を変更していますが、関数実行後に元の配列の値を出力すると変更されていないことが確認できます。

PHP

<?php
function foo($arg)
{
  $arg[0] *= 100;
}
$hoge = array(1);
foo($hoge);
echo $hoge[0], PHP_EOL; // 出力:1
?>

参照渡し

しかし、関数定義の引数の前に&を付けることで参照渡しにすることができます。下記は、先程のコードの引数に&を付けただけですが、出力結果を見ると参照が渡されたことがわかります。

PHP

<?php
function foo(&$arg)
{
  $arg[0] *= 100;
}
$hoge = array(1);
foo($hoge);
echo $hoge[0], PHP_EOL; // 出力:100
?>

デフォルト値

引数には、下記のようにデフォルト値を指定することができます。しかし、デフォルト値を持つ引数の後にデフォルト値を持たない引数を定義することはできません。デフォルト値を指定した引数は、呼び出し時に省略することができます。下記の例では、第2引数が省略された場合、$moneyは’円’となります。

PHP

<?php
function foo($price, $money = '円')
{
  echo $price . $money, PHP_EOL;
}
foo(100); // 出力:100円
foo(1, 'ドル'); // 出力:1ドル
?>

可変長引数

PHPは、可変長引数をサポートしています。引数を可変長にするためには、関数定義では引数を定義しないで、呼び出し時に引数を渡すようにします。そして関数内でfunc_num_args(), func_get_arg(), func_get_args()で渡された引数にアクセスします。

func_num_args()は、渡された引数の数を返します。func_get_arg()は、引数のインデックスを指定することで、引数の要素を返します。その際、インデックスは0からになります。func_get_args()は、渡された引数を配列として返します。

PHP

<?php
function foo()
{
  echo '引数の数 : '. func_num_args(), PHP_EOL; // 出力:引数の数 : 2
  echo '第1引数 : ' . func_get_arg(0), PHP_EOL; // 出力:第1引数 : 1
  echo '第2引数 : ' . func_get_arg(1), PHP_EOL; // 出力:第2引数 : a
  echo '引数の配列 : ', var_dump(func_get_args()), PHP_EOL; // 出力:引数の配列 : array(2) { [0]=> int(1) [1]=> string(1) "a" }
}
foo(1, 'a');
?>

タイプヒンティング

PHPでは、引数の型を指定することはできませんが、タイプヒンティングを使用することで、引数の型を配列や特定のクラスのオブジェクトに制限することができます。タイプヒンティングの指定は、下記のように関数の定義時に引数の前にarrayやクラス名を指定します。

PHP

<?php
function foo(array $arg_1, Hoge $arg_2)
{
  var_dump($arg_1); // 出力:array(2) { [0]=> int(1) [1]=> int(2) }
  var_dump($arg_2); // 出力:object(Hoge)#1 (0) { }
}
$array = array(1, 2);
class Hoge
{
}
$hoge = new Hoge();
foo($array, $hoge);
/*
foo(1, 'a'); // 出力:Catchable fatal error
*/
?>

関数の戻り値(返り値)

関数内でreturn文を使用することにより、呼び出し元に値を返すことができます。通常、returnによる戻り値は、参照ではなく値として返されます。また、returnにより呼び出し元に制御が戻るため、return以降の処理は実行されません。

PHP

<?php
function foo(&$arg)
{
  $arg *= 10;
  return $arg;
  echo 'return以降の処理は行われません。', PHP_EOL;
}
$hoge = 1;
$bar = foo($hoge);
$bar++;
echo '$hoge : ' . $hoge, PHP_EOL; // 出力:$hoge : 10
echo '$bar : ' . $bar, PHP_EOL; // 出力:$bar : 11
?>

戻り値を参照で返したい場合は、関数名の先頭に&を付けます。その際、戻り値を変数に代入する場合は、代入演算子にも&を付ける必要があります。

PHP

<?php
function &foo(&$arg)
{
  $arg *= 10;
  return $arg;
  echo 'return以降の処理は行われません。', PHP_EOL;
}
$hoge = 1;
$bar =& foo($hoge);
$bar++;
echo '$hoge : ' . $hoge, PHP_EOL; // 出力:$hoge : 11
echo '$bar : ' . $bar, PHP_EOL; // 出力:$bar : 11
?>

無名関数

無名関数とは、その名の通り名前のない関数です。無名関数は、下記のように変数に代入して使用したり、コールバック関数として使用します。なお、無名関数はPHP5.3以降で使用可能です。

PHP

<?php
$foo = function($arg)
{
  echo $arg, PHP_EOL;
};
$foo('Hello'); // 出力:Hello
var_dump($foo); // 出力:object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$arg"]=> string(10) "" } }
?>

クロージャ

クロージャを利用することで、関数内で使用できる変数を親スコープから引き継ぐことができます。親スコープの変数を引き継ぐためには、無名関数を定義する際にuse構文で使用する変数を指定します。

下記の例では、$foo()によって返される関数の定義でuse構文を使用し、親スコープの$moneyを指定しています。結果として、内側の関数内から親スコープの$moneyにアクセスできることが確認できます。

PHP

<?php
$foo = function($money)
{
  return function($price) use ($money)
  {
    return $price . $money;
  };
};
$hoge = $foo('円');
$bar = $foo('ドル');
echo $hoge(100), PHP_EOL; // 出力:100円
echo $bar(1), PHP_EOL; // 出力:1ドル
?>

関数の呼び出し

PHPでの基本的な関数の呼び出し方は、これまでの例で見てきたように関数名や無名関数を代入した変数に()を付けて呼び出します。しかし、それ以外にも関数を呼び出す方法がいくつか用意されています。

可変関数

PHPでは、関数名(文字列)の代入された変数に()を付けることにより、関数として呼び出すことができます。これを可変関数といいます。一見、無名関数と同じように呼び出しますが、無名関数は変数に関数自体が代入されているのに対して、可変関数は変数に代入された文字列を識別子として関数を呼び出す点に違いがあります。

PHP

<?php
function foo()
{
  echo 'foo()', PHP_EOL;
}
$hoge = 'foo';
$hoge(); // 出力:foo()
?>

コールバック関数

コールバック関数とは、呼び出した関数の処理で実行されるように登録しておく関数のことです。下記の例では、array_map()関数の引数で’foo’をコールバック関数として渡しています。結果、array_map()の処理で配列の各要素に対してfoo()が実行され、返された新しい配列が$result_arrayに代入されます。

コールバック関数には、関数名を文字列として渡す以外に無名関数、array(インスタンスの参照, ‘メソッド名’)、array(‘クラス名’, ‘staticメソッド名’)、’クラス名::staticメソッド名’も渡すことができます。

PHP

<?php
$array = array(1, 2, 3);
function foo($arg)
{
  return $arg * 100;
}
$result_array = array_map('foo', $array);
var_dump($result_array); // 出力:array(3) { [0]=> int(100) [1]=> int(200) [2]=> int(300) }
?>

call_user_func()

call_user_func()は、第1引数でコールバック関数を渡し、第2引数以降でコールバック関数に渡す引数を指定します。なお、call_user_func()の第2引数以降で参照を渡すことは非推奨(将来廃止予定)のようです。

PHP

<?php
function foo($price, $money)
{
  return $price . $money;
}
$hoge = call_user_func('foo', 2, 'ドル');
echo $hoge, PHP_EOL; // 出力:2ドル
?>

call_user_func_array()

call_user_func_array()は、第1引数でコールバック関数を渡し、第2引数でコールバック関数に渡す引数を配列で指定します。

PHP

<?php
function foo($price, $money)
{
  return $price . $money;
}
$hoge = call_user_func_array('foo', array(2, 'ドル'));
echo $hoge, PHP_EOL; // 出力:2ドル
?>

定義済み関数

PHPには、拡張機能も含めて多くのビルトイン関数が存在します。関数が定義されているかを調べるには、function_exists()を使用します。function_exists()は、引数に文字列で渡した関数が定義されていればtrue、定義されていなければfalseを返します。

PHP

<?php
var_dump(function_exists('strlen')); // 出力:bool(true)
var_dump(function_exists('hoge')); // 出力:bool(false)
?>

また、get_defined_functions()ですべての定義済み関数の関数名を配列で得ることができます。戻り値は連想配列になっており、’user’キーにユーザー定義関数の関数名、’internal’キーにビルトイン関数の関数名が配列で格納されています。

PHP

<?php
// すべての定義済み関数
$defined_functions = get_defined_functions();
// ユーザー定義関数
var_dump($defined_functions['user']);
// PHPのビルトイン関数
var_dump($defined_functions['internal']);
?>