「PHP/入門/関数とは」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
→‎再帰的呼出し: 関数は、自分の定義の中に自分を含めることができます。
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎コードキャラリー: まとまった規模で、実用的な目的に叶うコードを読まないと機能の存在理由などの言語設計に思い至りにくいので、コードの断片から少し踏み込んだプログラムを掲載します。 →‎array_*関数の拡張: PHPの組込み関数には、array_reduce(),array_map() のように array_ はじまる配列関数群があります。 これらは便利なのですが、配列とハッシュ兼用でJavaScriptやRubyなどから来ると面食らうことがあります。 また、配列の添字がcallback関数にわたらない仕様も移植のときに問題になります。 そこで、上記の問題をクリアした配列専用の関数群を作ってみました。 また、sum() は、カハンの加算アルゴリズムを使い誤差を最小にするようにしています。
タグ: 2017年版ソースエディター
420 行
関数は、自分の定義の中に自分を含めることができます。
 
;例:<syntaxhighlight lang=php line highlight=6 line highlight="9,17,22">
<?php
declare(strict_types=1);
461 行
:再帰的呼出しは、終了条件を間違えると「無限再帰」に陥ってしまい、資源(この場合はスタック)を喰いつくすまで帰ってきません。
:アルゴリズムが再帰的な場合、再帰的呼出しを行う関数として実装するとコードは短くなりますが、PHPの処理系はtailrecのような最適化は行わないので、関数呼出しのオーバーヘッドが再帰の他に課金され、資源にも優しくないので、再帰で実装したあと回帰テストを書き、ループで実装しテストを通ることを確認するのがベターでしょう。
 
== コードキャラリー ==
まとまった規模で、実用的な目的に叶うコードを読まないと機能の存在理由などの言語設計に思い至りにくいので、コードの断片から少し踏み込んだプログラムを掲載します。
 
=== array_*関数の拡張 ===
PHPの組込み関数には、array_reduce(),array_map() のように array_ はじまる配列関数群があります。
これらは便利なのですが、配列とハッシュ兼用でJavaScriptやRubyなどから来ると面食らうことがあります。
また、配列の添字がcallback関数にわたらない仕様も移植のときに問題になります。
そこで、上記の問題をクリアした配列専用の関数群を作ってみました。
また、sum() は、カハンの加算アルゴリズムを使い誤差を最小にするようにしています。
 
;実装:<syntaxhighlight lang=php line>
<?php
// phpinfo();
declare(strict_types=1);
 
$a1 = [2, 3, 5, 7, 11];
function reduce(array $ary, callable $code): mixed {
$result = 0;
$i = 0;
foreach ($ary as $el) {
if ($i == 0) {
$result = $el;
} else {
$result = $code($result, $el, $i);
}
$i++;
}
return $result;
}
echo reduce([1, 2, 3], fn($s, $x) => $s + $x), PHP_EOL;
echo reduce(["A", "B", "C"], fn($s, $x) => $s . $x), PHP_EOL;
echo PHP_EOL;
 
function map(array $ary, callable $code): array {
$result = [];
$i = 0;
foreach ($ary as $el) {
array_push($result, $code($el, $i++));
}
return $result;
}
echo implode(",", map($a1, fn($x) => $x * $x)), PHP_EOL;
echo PHP_EOL;
 
function each(array $ary, callable $code): void {
$i = 0;
foreach ($ary as $el) {
$code($el, $i++);
}
}
each($a1, fn($x, $i) => printf("%d[%d]\n", $x, $i));
 
function filter(array $ary, callable $code): array {
$result = [];
$i = 0;
foreach ($ary as $el) {
if ($code($el, $i++)) {
array_push($result, $el);
}
}
return $result;
}
echo implode(",", filter($a1, fn($x) => $x % 2)), PHP_EOL;
echo PHP_EOL;
 
function sum(array $ary): int|float {
$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 sprintf("%.53f", reduce($nums, fn($x, $y) => $x + $y)), PHP_EOL;
echo sprintf("%.53f", array_sum($nums)), PHP_EOL;
echo sprintf("%.53f", sum($nums)), PHP_EOL;
echo sprintf("%d", sum(range(1, 100))), PHP_EOL;
echo PHP_EOL;
 
function every(array $ary, callable $code): bool {
$i = 0;
foreach ($ary as $el) {
if (!$code($el, $i++)) {
return 0 != 0;
}
}
return 0 == 0;
}
var_dump(every($a1, fn($x) => $x != 1));
var_dump(every($a1, fn($x) => $x == 2));
echo PHP_EOL;
 
function some(array $ary, callable $code): bool {
$i = 0;
foreach ($ary as $el) {
if ($code($el, $i++)) {
return 0 == 0;
}
}
return 0 != 0;
}
var_dump(some($a1, fn($x) => $x != 1));
var_dump(some($a1, fn($x) => $x == 2));
echo PHP_EOL;
 
?>
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
6
ABC
 
4,9,25,49,121
 
2[0]
3[1]
5[2]
7[3]
11[4]
3,5,7,11
 
0.99999999999999988897769753748434595763683319091796875
0.99999999999999988897769753748434595763683319091796875
1.00000000000000000000000000000000000000000000000000000
5050
 
bool(true)
bool(false)
 
bool(true)
bool(true)
 
</syntaxhighlight>
 
[[Category:PHP|にゆうもん かんすうとは]]