PHP/入門/関数とは
関数は、プログラムを書く上で非常に重要な概念です。関数を使うことによって、同じ処理を何度も繰り返す必要がなくなり、コードの再利用性が高まります。また、関数は複雑な処理を単純な手順に分割することができ、プログラムの可読性や保守性を向上させます。 PHPにおいても、関数は非常に重要な役割を担っています。PHPには多くの便利な組み込み関数が用意されており、また、自分で関数を定義することもできます。この章では、PHPで関数を使う方法や、関数の定義方法、引数や戻り値の扱い方などを解説します。関数を使いこなすことで、より高度なプログラミングを行うことができるようになるでしょう。
関数定義と呼出し
編集PHPの関数定義の構文は以下の通りです。
- PHPの関数定義の構文
function 関数名(引数1, 引数2, ...) { // 処理内容 return 戻り値; }
function
キーワードで関数定義を開始します。関数名
には任意の名前を付けます。関数名は英数字とアンダースコア(_)の組み合わせで構成されます。また、関数名は大文字小文字を区別しません。()
内に引数を定義します。引数は任意の数だけ定義できます。引数がない場合は、()
だけを記述します。{}
内に処理内容を記述します。return
キーワードを使って、関数から返す値を定義します。return
文がない場合、関数は何も返しません。
以下は、具体的な例です。
- 関数定義と呼出しの例
<?php function greet($name) { echo "Hello, {$name}!", PHP_EOL; } greet("John"); // "Hello, John!" と出力される ?>
- このコードは、引数として受け取った
$name
を使って、「Hello, 名前!」というメッセージを表示する関数greet()
を定義し、その関数を"John"
という引数で呼出しています。 - 具体的には、
greet()
関数に"John"
という文字列を引数として渡し、関数内で"Hello, {$name}!"
という文字列を表示しています。{$name}
は、変数$name
の値を埋め込んだ文字列として扱われます。 - そして、
greet("John");
という呼出しを行うことで、関数greet()
が引数"John"
を受け取り、"Hello, John!"
という文字列を表示する処理が実行されます。結果として、画面に"Hello, John!"
というメッセージが表示されます。 - このように、関数を定義することで、同じような処理を何度も簡単に実行することができます。また、関数に引数を渡すことで、処理の柔軟性が高まり、より汎用的な関数を作ることができます。
- PHP_EOLは、PHPの内部定数であり、OSごとの改行文字列を表します。つまり、Windowsでは"\r\n"、LinuxやmacOSでは"\n"が使用されます。
- この定数は、プログラムを複数のプラットフォームで実行する場合に便利です。改行文字列を明示的に指定することで、プログラムがどのプラットフォームでも同じ出力を生成することができます。
関数の引数と戻値
編集PHPの関数は、0個以上の引数を渡すことができます。引数は関数内で変数として扱われます。引数の値は、関数呼出しの際に渡されます。
- 関数の引数と戻値の例
<?php function add($a, $b) { return $a + $b; } $result = add(3, 5); // $resultには8が代入される ?>
- 上記の例では、
add
という関数を定義しています。この関数は、2つの引数 $a と $b を受け取り、それらを加算した値を返すという処理を行っています。 - そして、
add
関数に引数として 3 と 5 を渡して呼出し、その戻り値を $result 変数に代入しています。
可変長引数
編集また、PHPには可変長引数という機能があります。これは、引数の数が可変である場合に使用することができます。可変長引数は、...
を引数の前に付けて定義します。
- 可変長引数の例
<?php function sum(...$numbers) { $total = 0; foreach ($numbers as $number) { $total += $number; } return $total; } $result1 = sum(1, 2, 3); // $result1には6が代入される $result2 = sum(4, 5, 6, 7); // $result2には22が代入される ?>
- 上記の例では、sum という関数を定義しています。この関数は、可変長引数 $numbers を受け取り、引数に渡された数値をすべて加算してその結果を返すという処理を行っています。
- そして、sum 関数に引数として 1、2、3 を渡して呼出し、その戻り値を $result1 変数に代入し、次に引数として 4、5、6、7 を渡して呼出し、その戻り値を $result2 変数に代入しています。
残余引数
編集残余引数も可変長引数と同様に多数の引数を渡すことができますが、配列として渡されます。また、可変長引数とは異なり、残余引数は引数のリストの途中に配置することができます。
以下は、残余引数を受け入れる関数の例です。
<?php function scores($subject, $student, ...$scores) { $total = 0; foreach ($scores as $score) { $total += $score; } $average = $total / count($scores); echo "{$student} got an average of {$average} in {$subject}."; } scores("Math", "John", 80, 85, 90); //==> John got an average of 85 in Math. ?>
引数のデフォルト値とキーワード引数
編集さらに、PHP 8.0 からは、引数のデフォルト値を設定したり、キーワード引数を使った関数定義もサポートされました。引数にデフォルト値を設定する場合は、引数の後に = を付けてデフォルト値を指定します。また、キーワード引数を使う場合は、引数名を指定して値を渡すことができます。
- 引数のデフォルト値とキーワード引数の例
<?php function greet($name = "World") { echo "Hello, {$name}!", PHP_EOL; } greet(); // "Hello, World!" と出力される greet("John"); // "Hello, John!" と出力される greet(name: "Alice"); // "Hello, JAlice" と出力される ?>
型宣言
編集型宣言は、関数の引数や返り値、そして PHP 7.4.0 以降ではクラスのプロパティに追加することができます。 これらは、呼出し時に指定した型の値であることを保証し、 一致しない場合は TypeError がスローされます。 strict_types を 1 にセットすると、型宣言漏れをエラーにできます。 また、strict_types を有効にすると、関数の返り値の型宣言についても厳密なチェックが行われます。 つまり、返り値が宣言された型と異なる場合は TypeError がスローされます。
以下は、引数と返り値に型宣言を追加した greet() 関数の例です。
- 型宣言の例
<?php declare(strict_types=1); function greet(string $name): string { // return 0; // PHP Fatal error: Uncaught TypeError: greet(): Return value must be of type string, int returned return "Hello, {$name}!"; } echo greet("John"); // "Hello, John!" と出力される // echo greet(123); // PHP Fatal error: Uncaught TypeError: greet(): Argument #1 ($name) must be of type string, int given // echo greet(); // PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function greet(), 0 passed ?>
- このコードは、厳密な型チェックを有効にするために
declare(strict_types=1)
が宣言されている関数greet()
を定義しています。 greet()
関数は、1 つの文字列型の引数$name
を受け取り、戻り値として文字列型の値を返します。このように、関数に対して厳密な型宣言がされているため、関数の引数と戻り値は指定された型と一致しなければなりません。greet()
関数が文字列型ではなく整数型を返す場合にTypeError
がスローされます。greet()
関数に整数型を渡すと、TypeError
がスローされ、エラーメッセージが表示されます。- また、
greet()
関数に引数を渡さずに呼出すと、引数が足りないため、ArgumentCountError
がスローされます。 string
型の引数を渡す必要があります。このように、引数と戻り値の型が厳密に指定されているため、不正な型が渡されると、TypeError
がスローされます。
PHPの関数定義の構文
編集- PHPの関数定義の構文
function 関数名(引数1の型 $引数1の名前 = デフォルト値, 引数2の型 $引数2の名前 = デフォルト値, ...可変長引数) : 戻り値の型 { // 関数の処理 return 戻り値; }
有効な型
編集プリミティブ型のほか、クラスやインターフェースの名前は、型名として認識されます。
以下は、PHPでサポートされる型とサポートされるようになったバージョンの一覧です。
PHPの関数の引数や戻値の型 型 説明 バージョン int 整数 5.0.0 float 浮動小数点数 5.0.0 string 文字列 5.0.0 bool 真偽値 4.2.0 array 配列 4.0.0 object オブジェクト 4.0.0 callable コールバック(関数名やクロージャなど) 5.4.0 iterable イテレータ 7.1.0 self 自分自身のクラス 5.0.0 parent 親クラス 5.0.0 ?int nullまたは整数 7.1.0 ?float nullまたは浮動小数点数 7.1.0 ?string nullまたは文字列 7.1.0 ?bool nullまたは真偽値 7.1.0 ?array nullまたは配列 7.1.0 ?object nullまたはオブジェクト 7.2.0 ClassName クラス名 5.0.0 Interface インターフェース名 5.0.0 array<int> 整数型の配列 7.0.0 array<mixed> 任意の型の配列 7.0.0 array<T> 型Tの配列。Tにはint,stringなどの型名を指定することができます。 7.3.0
注意点として、iterableやarray<T>などは、PHP 7.1.0以降でのみサポートされているため、それ以前のバージョンでは使用できません。 また、array<T>のようなジェネリック型は、厳密な型検査がされるわけではなく、実行時にエラーが発生する可能性があるので注意が必要です。
変数のスコープ
編集PHPには、ローカルスコープ、グローバルスコープ、そして静的スコープの3つのスコープがあります。
ローカルスコープ
編集ローカルスコープは、関数内で宣言された変数が含まれます。この変数は、関数の実行が終了した時点で破棄されます。例えば、次のコードでは、関数 greet()
の中で $name
という変数が宣言されています。
- ローカルスコープの例
<?php function greet() { $name = "John"; echo "Hello, {$name}!"; } greet(); // "Hello, John!" と出力される echo $name; // PHP Warning: Undefined variable $name ?>
- 関数の外から
$name
変数にアクセスすると、Undefined variable
のエラーが発生します。
グローバルスコープ
編集グローバルスコープは、関数の外で宣言された変数が含まれます。この変数は、プログラムの終了まで有効です。例えば、次のコードでは、$name
という変数が関数の外で宣言されています。
- ローカルスコープの例
<?php function greet() { static $count = 0; $count++; echo "Hello, this function has been called {$count} times!", PHP_EOL; } greet(); // "Hello, this function has been called 1 times!" と出力される greet(); // "Hello, this function has been called 2 times!" と出力される greet(); // "Hello, this function has been called 3 times!" と出力される ?>
global
キーワードを使って、関数内でグローバル変数にアクセスすることができます。
静的スコープ
編集静的スコープは、関数内で宣言された変数が含まれますが、その変数は関数の実行が終了しても破棄されず、次回の関数実行時にも値を保持します。例えば、次のコードでは、greet()
関数内で $count
変数が宣言されており、呼出し回数をカウントするために使われます。
- 静的スコープの例
$name = "John"; function greet() { global $name; echo "Hello, {$name}!"; } greet(); // "Hello, John!" と出力される echo $name; // "John" と出力される
static
キーワードを使って、静的変数を宣言することができます。$count
変数は、関数が終了しても破棄されず、次回の関数実行時にも値を保持します。
スーパーグローバル変数
編集PHPには、どこからでもアクセスできるスーパーグローバル変数がいくつかあります。これらは、関数やクラスのスコープを超えて、グローバルにアクセス可能な変数です。
スーパーグローバル変数 変数名 説明 $GLOBALS スクリプト全体で利用可能なグローバル変数の連想配列 $_SERVER サーバー情報(HTTPヘッダ、パス、スクリプトの位置など)の連想配列 $_GET URLパラメータで渡された値の連想配列 $_POST HTTP POSTメソッドで渡された値の連想配列 $_FILES HTTP POSTメソッドでアップロードされたファイルの連想配列 $_COOKIE クライアントから送信されたクッキーの連想配列 $_SESSION セッション変数の連想配列 $_REQUEST HTTP POST、HTTP GET、およびクッキーの値を含む連想配列 $_ENV 環境変数の連想配列
これらの変数は、スクリプトのどこからでもアクセス可能で、グローバルなスコープを持ちます。 また、変数名の前に「$_」がつくのが特徴です。これは、変数名がスーパーグローバルであることを明示するための命名規則です。
マジック定数
編集PHPには、特定の状況下で自動的に設定されるマジック定数と呼ばれる定数があります。これらの定数は、スクリプトのどこからでもアクセスできます。
マジック定数 マジック定数 説明 __LINE__ 現在の行番号 __FILE__ 現在のファイル名(ファイルパスを含む) __DIR__ 現在のファイルのディレクトリ名 __FUNCTION__ 現在の関数名 __CLASS__ 現在のクラス名 __TRAIT__ 現在のトレイト名 __METHOD__ 現在のメソッド名(クラス名も含む) __NAMESPACE__ 現在の名前空間名
- これらのマジック定数は、プログラム実行中に自動的に設定され、その値を取得することができます。
- 例えば、__LINE__は現在の行番号を表し、__FILE__は現在のファイル名を表します。
- また、__FUNCTION__は現在の関数名を表し、__CLASS__は現在のクラス名を表します。
- これらのマジック定数を使うことで、デバッグやログ出力などで便利に利用することができます。
高階関数
編集高階関数とは、引数として別の関数を受け取る関数のことを指します。一般的に、高階関数は、関数を引数として受け取り、その関数を実行することによって機能を拡張するために使用されます。PHPにおいても、高階関数が使用されることがあります。
以下に、PHPにおける高階関数の例を示します。
<?php // map関数 function map($arr, $func) { $result = []; foreach ($arr as $elem) { $result[] = $func($elem); } return $result; } // 配列の要素を2倍にする関数 function double($x) { return $x * 2; } // 配列の各要素を2倍にする $arr = [1, 2, 3, 4]; $arr2 = map($arr, 'double'); // $arr2 = [2, 4, 6, 8] ?>
- 上記の例では、
map
関数が高階関数として定義されています。この関数は、第1引数に配列、第2引数に関数を受け取り、配列の各要素に関数を適用した結果の配列を返します。double
関数は、引数を2倍にする単純な関数で、map
関数によって使用されています。
このように、高階関数は、汎用性が高く、再利用性の高いコードを実現するために有用です。
無名関数
編集無名関数とは、名前を持たずに関数の機能を持つPHPの関数のことです。通常の関数と同様に、引数を受け取り、何らかの処理を行い、戻り値を返すことができます。 無名関数は、コールバック関数やクロージャーとして使用されます。コールバック関数は、ある処理が完了したときに呼出される関数であり、クロージャーは、定義された環境内の変数にアクセスできる無名関数です。 以下は、無名関数の基本的な構文の例です。
$func = function($arg1, $arg2) { // 無名関数の中身 };
無名関数を使用する場合、変数に関数を代入することができます。また、関数の引数に渡したり、コールバック関数やクロージャーとして使用することもできます。
コールバック関数
編集PHPにおいて、コールバック関数とは、ある関数の引数として渡され、その関数内で呼び出される関数のことを指します。つまり、コールバック関数は、関数を引数として渡すことができる高度な機能であり、PHPの強力な機能の一つと言えます。
コールバック関数は、通常は無名関数を使って定義されますが、名前付き関数も渡すことができます。以下は、無名関数を使って、コールバック関数を定義する例です。
<?php function executeCallback($callback) { if (is_callable($callback)) { $callback(); } else { echo "The callback is not callable."; } } executeCallback(function() { echo "This is a callback function."; }); ?>
- 上記の例では、
executeCallback
という関数を定義し、引数として渡された$callback
がcallableであれば、その$callback
を実行する処理が書かれています。 - そして、
executeCallback
を呼び出す際に、無名関数を渡しています。この無名関数がコールバック関数として使用されます。
コールバック関数を使うことで、汎用的な関数を作成することができます。また、PHPには、配列を操作するための便利なコールバック関数が多数用意されており、それらを利用することで、配列を簡単に操作することができます。例えば、array_map
関数は、与えられた関数を、配列の各要素に適用し、新しい配列を返す関数です。以下は、array_map
を使って、配列の各要素を二乗する例です。
- 配列の各要素を二乗する例
<?php $numbers = [1, 2, 3, 4, 5]; $squares = array_map(function($number) { return $number * $number; }, $numbers); print_r($squares); // [1, 4, 9, 16, 25] を出力 ?>
- 上記の例では、
array_map
関数を使って、配列$numbers
の各要素を二乗した新しい配列$squares
を作成しています。 array_map
関数の第一引数には、配列の各要素に適用する関数が、第二引数には、適用する配列が指定されています。- この例では、第一引数として、無名関数を定義しています。この無名関数は、引数として与えられた数値を二乗した結果を返すように定義されています。:
array_map
関数が呼び出されると、無名関数が、配列$numbers
の各要素に対して
クロージャー
編集クロージャー (Closure) は、無名関数を格納するためのオブジェクトであり、関数を定義する時点で外部変数を捕捉し、その変数を関数の中で使うことができるようにします。
クロージャーは、外部変数が割り当てられた後に定義され、その変数にアクセスすることができます。クロージャーが定義されると、その変数はクロージャーによって保持され、クロージャーが解放されるまで維持されます。
以下は、PHPにおけるクロージャーの例です。
- クロージャーの例
<?php function add($a) { return function ($b) use ($a) { return $a + $b; }; } $addFive = add(5); echo $addFive(3); // 8 ?>
- この例では、
add()
関数はクロージャーを返し、そのクロージャーは$a
変数を保持しています。 $addFive
変数にクロージャーを割り当て、引数として3
を渡すことで、$a
の値が5
であるため、5 + 3
の結果である8
が出力されます。
再帰的呼出し
編集再帰的呼出しとは、ある関数が自分自身を呼出すことを指します。この呼出しは、同じ処理を何度も繰り返す必要がある場合や、複雑なアルゴリズムを実装する場合に便利です。
PHPでも、再帰的呼出しをすることができます。以下は、簡単な例として、1から与えられた数までの自然数の和を再帰的に計算する関数です。
- 再帰的呼出しの例
<?php function sum($n) { if ($n === 1) { return 1; } else { return $n + sum($n - 1); } } echo sum(5); // 15 ?>
- このコードは、再帰的呼出しを使って、1から引数の数値までの整数の和を求める関数を定義しています。
- まず、関数
sum
の引数$n
が1と等しい場合、1を返します。これは、再帰呼出しの終了条件となります。 - それ以外の場合、関数
sum
は$n
とsum($n - 1)
を足した値を返します。sum($n - 1)
は、引数$n - 1
を渡して自身を再帰的に呼出しており、これによって$n
が1になるまで再帰的に呼出されます。 - 最終的に
sum(1)
が呼出されると、終了条件によって1が返され、再帰呼出しは終了します。その後、すべての再帰呼出しが返した値が足し合わされ、1から引数の数値までの整数の和が求められます。
再帰的呼出しは、アルゴリズムが再帰的な場合には簡潔なコードにすることができますが、理解やデバッグの難易度を高めることがあるため、注意が必要です。 さらに、再帰的に呼出す関数の処理が大きくなりすぎると、スタックオーバーフローの原因になる場合があります。 また、適切な条件判定や終了処理の実装が必要です。
ジェネレーター関数
編集PHPにおけるジェネレーター関数は、反復可能なオブジェクトを生成するための特殊な関数です。
ジェネレーター関数は、yield
キーワードを使用して値を返し、内部の状態を保持します。
yield
キーワードを使用すると、ジェネレーター関数の実行が一時停止され、呼出し元に値が返されます。
呼出し元は、ジェネレーター関数が再開されるときに、再びジェネレーター関数を呼出すことができます。
- 例
<?php declare(strict_types=1); function gen_square() : iterable { for ($i = 0; $i < 10; $i++) { yield $i * $i; } } foreach (gen_square() as $value) { echo "$value\n"; } var_export(array(...gen_square()));
- 実行結果
0 1 4 9 16 25 36 49 64 81 array ( 0 => 0, 1 => 1, 2 => 4, 3 => 9, 4 => 16, 5 => 25, 6 => 36, 7 => 49, 8 => 64, 9 => 81, )
- このコードは、ジェネレーター関数
gen_square()
を定義しています。この関数は、0から9までの整数の2乗を生成し、それぞれyield
キーワードで返します。そして、foreach
ループを使ってgen_square()
の戻り値を反復処理し、値を出力します。 - また、
array(...gen_square())
を使って、gen_square()
の返すイテレータを配列に展開しています。この記法は PHP 7.4 から導入されたスプレッド演算子を使用しており、配列リテラル内で...
を使用することで、配列を展開することができます。 - 関数の戻り値型として、
iterable
を指定しています。これは、PHP 7.1 から導入された型で、反復処理可能なオブジェクトを表す型です。ジェネレーター関数はiterable
を返すことができます。
ジェネレーターは配列に似ていますが、配列は要素数 × 要素1つあたりのサイズのメモリーフットプリントを消費します。それに対し、ジェネレーターは yield
で返す値は都度計算できるため、メモリ消費が配列に比べて小さくなります。
コードキャラリー
編集まとまった規模で、実用的な目的に叶うコードを読まないと機能の存在理由などの言語設計に思い至りにくいので、コードの断片から少し踏み込んだプログラムを掲載します。
array_*関数の拡張
編集PHPの組込み関数には、array_reduce(),array_map() のように array_ はじまる配列関数群があります。 これらは便利なのですが、配列とハッシュ兼用でJavaScriptやRubyなどから来ると面食らうことがあります。 また、配列の添字がcallback関数にわたらない仕様も移植のときに問題になります。 そこで、上記の問題をクリアした配列専用の関数群を作ってみました。 また、sum() は、カハンの加算アルゴリズムを使い誤差を最小にするようにしています。
- 実装
<?php // phpinfo(); declare(strict_types=1); function reduce(array $ary, callable $code, mixed $result = null): mixed { $i = 0; foreach ($ary as $el) { if ($i == 0 && !isset($result)) { $result = $el; } else { $result = $code($result, $el, $i); } $i++; } return $result; } echo 'reduce([1, 2, 3], fn($s, $x) => $s + $x) --> ', reduce([1, 2, 3], fn($s, $x) => $s + $x), PHP_EOL; echo 'reduce([1, 2, 3], fn($s, $x) => $s + $x, 10) --> ', reduce([1, 2, 3], fn($s, $x) => $s + $x, 10), PHP_EOL; echo 'reduce(["A", "B", "C"], fn($s, $x) => $s . $x) --> ', reduce(["A", "B", "C"], fn($s, $x) => $s . $x), PHP_EOL; echo 'reduce(["A", "B", "C"], fn($s, $x) => [ ...$s, "<$x>"], []) --> ', var_export(reduce(["A", "B", "C"], fn($s, $x) => [...$s , "<$x>"], []), true),PHP_EOL; echo PHP_EOL; function map(array $ary, callable $code): array { $result = []; $i = 0; foreach ($ary as $el) { $result[] = $code($el, $i++); } return $result; } $a1 = [2, 3, 5, 7, 11]; echo '$a1 = [2, 3, 5, 7, 11];', PHP_EOL; echo 'map($a1, fn($x) => $x * $x) --> ', var_export(map($a1, fn($x) => $x * $x), true), PHP_EOL; echo PHP_EOL; function each(array $ary, callable $code): void { $i = 0; foreach ($ary as $el) { $code($el, $i++); } } echo 'each($a1, fn($x, $i) => printf("%d[%d] ", $x, $i)); --> '; each($a1, fn($x, $i) => printf("%d[%d] ", $x, $i)); echo PHP_EOL; echo PHP_EOL; function filter(array $ary, callable $code): array { $result = []; $i = 0; foreach ($ary as $el) { if ($code($el, $i++)) { $result[] = $el; } } return $result; } echo 'filter($a1, fn($x) => $x % 2) --> ', var_export(filter($a1, fn($x) => $x % 2), true), PHP_EOL; echo 'filter($a1, fn($x) => $x < 6) --> ', var_export(filter($a1, fn($x) => $x < 6), true), PHP_EOL; echo PHP_EOL; function sum(array $ary): int|float|null { $sum = null; $i = 0; foreach ($ary as $delta) { if ($i == 0) { $sum = $delta; $c = $delta - $delta; } else { $y = $delta - $c; $t = $sum + $y; $c = ( $t - $sum ) - $y; $sum = $t; } $i++; } return $sum; } $nums = array_fill(0, 10, 0.1); echo '$nums = array_fill(0, 10, 0.1);', PHP_EOL; echo 'reduce($nums, fn($x, $y) => $x + $y) --> ', sprintf("%.53f", reduce($nums, fn($x, $y) => $x + $y)), PHP_EOL; echo 'array_sum($nums) --> ', sprintf("%.53f", array_sum($nums)), PHP_EOL; echo 'sum($nums) --> ', sprintf("%.53f", sum($nums)), PHP_EOL; echo 'sum(range(1, 100)) --> ', sprintf("%d", sum(range(1, 100))), PHP_EOL; echo 'sum([]) --> ',var_export(sum([]), true), PHP_EOL; echo PHP_EOL; function every(array $ary, callable $code): bool { $i = 0; foreach ($ary as $el) { if (!$code($el, $i++)) { return false; } } return true; } echo 'every($a1, fn($x) => $x != 1) --> ', var_export(every($a1, fn($x) => $x != 1), true), PHP_EOL; echo 'every($a1, fn($x) => $x == 2) --> ', var_export(every($a1, fn($x) => $x == 2), true), PHP_EOL; echo PHP_EOL; function some(array $ary, callable $code): bool { $i = 0; foreach ($ary as $el) { if ($code($el, $i++)) { return true; } } return false; } echo 'some($a1, fn($x) => $x != 1) --> ', var_export(some($a1, fn($x) => $x != 1), true), PHP_EOL; echo 'some($a1, fn($x) => $x == 2) --> ', var_export(some($a1, fn($x) => $x == 2), true), PHP_EOL; echo PHP_EOL;
- 実行結果
reduce([1, 2, 3], fn($s, $x) => $s + $x) --> 6 reduce([1, 2, 3], fn($s, $x) => $s + $x, 10) --> 16 reduce(["A", "B", "C"], fn($s, $x) => $s . $x) --> ABC reduce(["A", "B", "C"], fn($s, $x) => [ ...$s, "<$x>"], []) --> array ( 0 => '<A>', 1 => '<B>', 2 => '<C>', ) $a1 = [2, 3, 5, 7, 11]; map($a1, fn($x) => $x * $x) --> array ( 0 => 4, 1 => 9, 2 => 25, 3 => 49, 4 => 121, ) each($a1, fn($x, $i) => printf("%d[%d] ", $x, $i)); --> 2[0] 3[1] 5[2] 7[3] 11[4] filter($a1, fn($x) => $x % 2) --> array ( 0 => 3, 1 => 5, 2 => 7, 3 => 11, ) filter($a1, fn($x) => $x < 6) --> array ( 0 => 2, 1 => 3, 2 => 5, ) $nums = array_fill(0, 10, 0.1); reduce($nums, fn($x, $y) => $x + $y) --> 0.99999999999999988897769753748434595763683319091796875 array_sum($nums) --> 0.99999999999999988897769753748434595763683319091796875 sum($nums) --> 1.00000000000000000000000000000000000000000000000000000 sum(range(1, 100)) --> 5050 sum([]) --> NULL every($a1, fn($x) => $x != 1) --> true every($a1, fn($x) => $x == 2) --> false some($a1, fn($x) => $x != 1) --> true some($a1, fn($x) => $x == 2) --> true
- このコードは、PHPでArrayメソッドを実装したものです。主に、reduce、map、each、filter、sum、every関数を定義しています。
- reduce関数は、配列の要素を走査して、コールバック関数を適用し、最終的な単一の値を返します。また、第3引数に初期値を渡すこともできます。
- map関数は、配列の各要素に対してコールバック関数を適用し、新しい配列を作成して返します。
- each関数は、配列の各要素に対してコールバック関数を適用します。ただし、戻り値はありません。
- filter関数は、配列の要素を走査し、コールバック関数がtrueを返す要素を含む新しい配列を作成して返します。
- sum関数は、数値配列の合計値を返します。2つの浮動小数点数を正確に加算するために、内部で処理を行っています。
- アルゴリズムは、Kahanの加算アルゴリズムと呼ばれる方法を使っています。このアルゴリズムは、浮動小数点数の加算において、誤差を最小限に抑えるために考案されました。
- 具体的には、各要素を順番に加算する際に、現在の誤差を考慮して加算を行い、その誤差を記憶しておきます。次に、次の要素を加算する前に、前回の誤差を引いてから加算を行います。
- これにより、浮動小数点数の誤差を効果的に抑えることができます。
- この関数では、変数
$sum
に合計値を、変数$c
に現在の誤差を保持し、各要素を順番に加算していくことで、正確な合計値を得ています。
- every関数は、配列の各要素に対してコールバック関数を適用し、すべての要素がtrueを返した場合にtrueを返します。それ以外の場合は、falseを返します。
附録
編集チートシート
編集<?php // 関数定義 function 関数名 (引数1, 引数2, ...) { 処理; return 戻り値; } // 関数呼び出し $result = 関数名(引数1, 引数2, ...); // 引数のデフォルト値 function 関数名 (引数1 = 値1, 引数2 = 値2, ...) { 処理; } // 可変長引数 function 関数名 (...$args) { 処理; } // クロージャ $closure = function (引数1, 引数2, ...) { 処理; return 戻り値; }; // 無名関数の即時実行 $result = (function (引数1, 引数2, ...) { 処理; return 戻り値; })(値1, 値2, ...); // 再帰的呼び出し function 関数名 (引数) { if (条件) { return 値; } else { return 関数名(引数を更新); } } // スーパーグローバル変数 $GLOBALS $_SERVER $_GET $_POST $_FILES $_COOKIE $_SESSION $_REQUEST $_ENV // マジック定数 __LINE__ __FILE__ __DIR__ __FUNCTION__ __CLASS__ __TRAIT__ __METHOD__ __NAMESPACE__ // 名前空間 namespace 名前空間名; use 名前空間名\クラス名; クラス名::メソッド名(引数);
以上がPHPの関数に関するチートシートです。
用語集
編集- 関数 (function) : 名前を持ったプログラムの断片で、一連の処理をまとめて、その名前で呼び出すことができる。プログラムの構造化と再利用性を高める。
- 引数 (argument) : 関数に渡される値のこと。関数定義で宣言された引数と同じ数だけ渡す必要がある。
- 戻り値 (return value) : 関数から呼び出し元に返される値のこと。return文で指定された式の値が返り値として扱われる。
- 可変長引数 (variable-length argument) : 引数の数が可変長であることを示す機能。可変長引数を受け取る関数は、引数名の前に「...」を付ける。
- 引数のデフォルト値 (default value of argument) : 引数にデフォルト値を設定することができる。呼び出し時に引数が指定されなかった場合に、デフォルト値が使われる。
- キーワード引数 (keyword argument) : 引数を名前で指定する機能。引数名と値を「引数名 => 値」という形式で渡す。
- 型宣言 (type declaration) : 引数や戻り値の型を宣言することができる。PHP 7からサポートされた機能。
- スコープ (scope) : 変数が定義されている有効範囲のこと。スコープによって変数のアクセス可能範囲が決まる。
- ローカルスコープ (local scope) : 関数内で定義された変数の有効範囲のこと。関数の外からはアクセスできない。
- グローバルスコープ (global scope) : 関数の外で定義された変数の有効範囲のこと。どこからでもアクセスできる。
- 静的スコープ (static scope) : 関数内で定義された静的変数の有効範囲のこと。関数の呼び出し回数に依存せず、値が保持される。
- スーパーグローバル変数 (superglobal variable) : スクリプトのどこからでもアクセスできる特別な変数。$GLOBALS、$_SERVER、$_GET、$_POST、$_FILES、$_COOKIE、$_SESSION、$_REQUEST、$_ENVがある。
- 無名関数 (anonymous function): 名前を持たない関数のこと。変数に代入して使用することができる。
- クロージャ (closure): 関数が変数に代入された場合、その関数はそのまま変数として使用することができ、その変数を引数に取る関数のこと。
- 再帰的呼び出し (recursive call): 関数が自身を呼び出すこと。
- ジェネレーター関数 (generator function): 実行を一時停止し、値を返すことができる関数。