PHP Manual
/
基礎知識

PHP におけるサイクルとその型

11. 04. 2020

Obsah článku

一般にループは、同じコード部分を繰り返すために使用されます(通常はデータセットに対して)タスクの種類ごとに、異なるタイプのループが適しており、主に意味と構文が異なっています。また、すべての種類のループは互いに変換可能ですが、コードの複雑さや計算時間の点で、常に価値があるとは限らないということも重要なポイントです。

ループの基本的な分け方を要素の種類で表したもの。

  • for`: 繰り返しの回数があらかじめ分かっている、あるいは単純に計算できる一般的なループ。
  • whileuntil-while`: 繰り返し回数が事前に分からない一般的なループ。
  • foreach`: 配列やオブジェクトをブラウズする。
  • 再帰性`: 複雑な問題をより小さな問題の集合に分解すること。

ループの一般的な特性

サイクルは一般的に、マークされたコードの一部を、終了条件が成立する限り何度も繰り返すことで機能します。ループは、終了条件を満たせなかった場合、あるいは break; を呼んで手動で停止させた場合に停止します。

ループを止めるものがなければ、アプリケーションが手動で終了するか、 PHP スクリプトの処理時間制限 (通常は 30 秒) が終了するまで、ループが無限に続くことを防ぐものがないことになります。

重要な用語:

  • Cycle` - コードの特定の部分を繰り返すことができる言語表現です。
  • 反復処理` - ループ本体の特定の1回の実行。
  • 初期化` - ループ実行の開始(最初の反復が始まる前).
  • Increment - 反復変数を 1 つずつインクリメントする。
  • 終了条件` - 反復ごとに検証される条件(検証の場所はループの種類によって異なる)。条件が成立している間、ループが実行される

ループ用

For` は、繰り返しの回数があらかじめわかっている(あるいは簡単に計算できる)場合に有効です。インターバルの直線的なトラバースなどに最適です。

一般的に書かれているのは(3部構成)です。

for (inicializace; výraz; inkrementace) {
// サイクルの本体
}

  • 初期化`: ループの初期状態 (どのような変数が必要か) を定義する。
  • 式`: 条件です。それが有効である限り、ループは実行されます。
  • increment: ループの状態を前のパスから変更する (increment - 1つずつ増やす)。

例えば、0から10までの数字の羅列を出力するような場合です。

for ($i = 0; $i <= 10; $i++) {
echo $i . '<br>。';
}

または、「2」から「100」までの2の倍数。

for ($i = 2; $i <= 100; $i += 2) {
echo $i . '<br>。';
}

forループは、アルファベット、数字の配列、間隔を取得するなど、様々なトリックに有効である。

do-whileループの間

Whileループは、条件が成立している間だけ実行されます。whiledo-while` の違いは、いつ条件が評価されるかということです。

while (výraz) {
// サイクルの本体
}

あるいは。

do {
// サイクルの本体
} while(výraz);

  • while` はまず条件を評価し、それから内部ループを実行します。
  • do-wile`はまず内側のループを処理し、次に条件を評価します。

これは、ループが実行されるかどうか事前に知ることができず、必ず一度は実行されることを保証したい場合に特に有利です(その場合は do-while を使用します)。

変数 $x = 2 に格納されている数値があります。また、変数 $y には、区間 <0; 10> にある数値を、変数 $x にある数値と異なるように生成したい。簡単に言うと、「0」から「10」の間で、「2」ではない乱数を生成する。

この場合、do-whileループを使用すると便利です。また、最初に数字を生成しなければならないので、条件が評価される前に少なくとも1回はループが実行されることを保証したい。

$x = 2;
$y = $x;
do {
$y = rand(0, 10);
} while($x == $y);
echo 'X :' . $x . '<br>。';
echo 'Y:' . $y;

フォーチュン

foreach` は、フィールドやオブジェクトをブラウズするのに最適です。特定の値だけでなく、キーも取得することができる。

特定の値だけを取得したい場合。

foreach ($data as $value) {
// データ処理
}

または、鍵を入手することも可能です。

foreach ($data as $key => $value) {
// データ処理
}

foreach` は、実際のデータ、例えばデータベースの結果や、キーを持つフィールドをブラウズするのに最適です。

$countries = [
'エン' => 'チェコ共和国',
'参照' => 'スロバキア',
];
foreach ($countries as $shortcut => $name) {
echo $shortcut . ':' . $name . '<br>。';
}

リカージョン

再帰は、関数やメソッドが自分自身を呼び出すときに発生します。複雑な問題を、より小さな問題に分解することができる。

再帰の理解は、責任転嫁の考えに基づいているため、初心者には難しいかもしれません。

この関数は、実際には「私はこの問題を解決できないが、解決できる人を知っている」という趣旨のことを言うので、その人に電話をかけ、その人が誰かに電話をかけ、......という具合です。最後のメンバーが呼ばれるまで、問題をカットします。

どんな再帰的アルゴリズムでも、再帰が必要ないところではループを使うように書き換えることができる(逆もまた真なり)ことは確かである。 再帰は良い召使であるが、悪い主人である。ある種の問題をシンプルかつ非常に効率的に解決するのに役立ちますし、サイクルをループさせることは他のことにも有効です。

一般に、再帰は関数やメソッドの新しいインスタンスやコンテキストを常に生成するため、メモリを大量に消費する。しかし、例えば木構造のトラバースなどでは、これが唯一の合理的な解決方法となる。

数字の「5」の階乗を計算する必要がありますが、これは数学で行われている方法です。

5!= 5 * 4 * 3 * 2 * 1

つまり、1`から階乗に興味のある数までの一連の数の連続した掛け算が存在するのです。

再帰的に、これは非常にエレガントに解決することができます。

function factorial(int $n): int
{
if ($n === 0) {
return 1;
}
return $n * factorial($n - 1);
}

あるいは、三項演算子を使ったさらに短い実装もある。

function factorial(int $n): int
{
return $n === 0 ? 1 : $n * factorial($n - 1);
}

同様にサイクルを使用するように書き換えることができます。

function factorial(int $n): int
{
$result = 1;
for ($i = $n; $i > 0; $i--) {
$result *= $i;
}
return $result;
}

サイクルでの書き込みは若干時間がかかりますが、やはりメモリフットプリントは大幅に小さくなります。計算には1つの変数 $result を使用します。この変数では、値を継続的に変更するため、 factorial() のインスタンスを新しく作成する必要はありません。

無限ループの記述は慎重に

ループが無限大になることは、非常に簡単です(終了条件を満たさないことで実現します)。これを考慮して、場合によっては break; を使って自分でループを止めることも必要です。

例えば、6という数字が出るまでダイスを振ります。実装としては、whileループを使いたくなる。

while (true) {
$value = rand(1, 6);
if ($value === 6) {
echo '価値が下がった' . $value;
break;
}
}

while(true) と書くことで、true が常に真になるため、無限に繰り返されることを保証しています。そこで、break;構文でループを止める必要があるのですが、もし値6`が落ちずにループを止められなかったらどうでしょう?

個人的には、常に繰り返し回数をカウントし、ある限界値を超えたら、強制的にループを終了するようにしています。例えば、試行回数が 1000 を超えた場合。その場合、whileではなくforを使い、実行回数をカウントするのが良い。

実行回数を超えた場合は、例外を投げて開発者に知らせるのが礼儀である。

for ($i = 0; $i <= 1000; $i++) {
$value = rand(1, 6);
if ($value === 6) {
echo '価値が下がった' . $value;
break;
}
}
if ($i === 1000) {
throw new \Exception('最大投球回数を超えました。');
}

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
12.
Status:
All systems normal.
2024