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

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎ジェネレター: ジェネレター関数は、値を返す代わりに、yieldで必要なだけの値を生成することを除けば、通常の関数と同じように見えます。 yieldを含む関数はすべてジェネレター関数です。 ジェネレター関数が呼び出されると、繰返し実行可能なオブジェクト(iterable型のオブジェクト)が返されます。 そのオブジェクトに対して反復処理を行うと (たとえば foreach ループで)、 PHP は値が必要になるたびにオブジェクトの反復処理用メソッドをコールし、 ジェネレターが値を返した時点でその状態を保存して、次の値が必要になったときに再開できるようにします。 生成する値がなくなったら、ジェネレターは単に終了し、呼出し元のコードは配列の値がなくなったときと同じように続行できます。
タグ: 2017年版ソースエディター
420 行
関数は、自分の定義の中に自分を含めることができます。
 
;[https://paiza.io/projects/6l_BcluymbeRujHGTJiIuw?language=php ]:<syntaxhighlight lang=php line highlight="9,17,22">
<?php
declare(strict_types=1);
448 行
echo 'comma3(ipow(10, 9)) --> ', comma3(ipow(10, 9)), PHP_EOL;
echo 'comma3(ipow(2, 32)) --> ', comma3(ipow(2, 32)), PHP_EOL;
 
?>
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
460 ⟶ 458行目:
:2つの関数とも定義が再帰的なので、再帰的呼び出しで実装しています。
:再帰的呼出しは、終了条件を間違えると「無限再帰」に陥ってしまい、資源(この場合はスタック)を喰いつくすまで帰ってきません。
:アルゴリズムが再帰的な場合、再帰的呼出しを行う関数として実装するとコードは短くなりますが、PHPの処理系はtailrecのような最適化は行わないので、関数呼出しのオーバーヘッドが再帰のたびに課金され、資源にも優しくないので、再帰で実装したあと回帰テストを書き、ループで実装しテストを通ることを確認するのがベターでしょう。
 
=== ジェネレター ===
ジェネレター関数は、値を返す代わりに、<code>yield</code>で必要なだけの値を生成することを除けば、通常の関数と同じように見えます。
<code>yield</code>を含む関数はすべてジェネレター関数です。
 
ジェネレター関数が呼び出されると、繰返し実行可能なオブジェクト(<code>iterable</code>型のオブジェクト)が返されます。
そのオブジェクトに対して反復処理を行うと (たとえば foreach ループで)、 PHP は値が必要になるたびにオブジェクトの反復処理用メソッドをコールし、 ジェネレターが値を返した時点でその状態を保存して、次の値が必要になったときに再開できるようにします。
 
生成する値がなくなったら、ジェネレターは単に終了し、呼出し元のコードは配列の値がなくなったときと同じように続行できます。
 
;[https://paiza.io/projects/qQA7qDf386VLLzuUsbkEEg?language=php 例]:<syntaxhighlight lang=php line highlight=6>
<?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()));
</syntaxhighlight>
;実行結果:<syntaxhighlight lang=text>
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,
)
</syntaxhighlight>
 
ジェネレターは配列に似ていますが、配列は 要素数 × 要素1つあたりのサイズ のメモリーフットプリントを消費します。それに対しジェネレターは、<code>yield</code> で返す値は都度計算できるのでメモリー消費は配列に比べ小さくなります。
 
== コードキャラリー ==