10

最近、多くの人が「後藤」という一言だけを言ったと非難しました。
なぜそんなに厄介な言葉だと思われるのだろうか。
このトピックに関する以前のいくつかの議論を知っていますが、それは私を納得させません-答えのいくつかは、説明しようとさえせずに「悪い」と言っているだけで、PHPやIMOのようなスクリプト言語には関係のない理由をもたらします。

とにかく、私は非常に特別な質問をするつもりです:比較してステートメントをし
ましょう。 私の意見では、どちらも同じことをします。ある条件に基づいてコードの一部の実行を回避することです。 もしそうなら-後藤と同じ欠点がありますか?(もしあれば)? そうでない場合-それは違いです。 gotothrow

throw

次の2つのコードスニペットのコード構造の基本的な概念の違いを理解できる人は、十分な経験がありますか?
これらのコードスニペットに関しては、「理論上」、「一般的」、「ここに素晴らしいXKCDコミックがあります!」ではありません。
なぜ最初のものは素晴らしいと見なされ、後者は最も致命的な罪であると見なされたのですか?

#$a=1;
#$b=2;

/* SNIPPET #1 */

try {
    if (!isset($a)) {
      throw new Exception('$a is not set');
    }
    if (!isset($b)) {
      throw new Exception('$b is not set');
    }
    echo '$a + $b = '.($a + $b)."<br>\n";
} catch (Exception $e) {
    echo 'Caught exception: ', $e->getMessage(), "<br>\n";
}

/* SNIPPET #2 */

if (!isset($a)) { 
  $message = '$a is not set';
  goto end;
}
if (!isset($b)) {
  $message = '$b is not set';
  goto end;
}
echo '$a + $b = '.($a + $b)."<br>\n";

end:
if (!empty($message)) {
  echo 'Caught exception: ', $message, "<br>\n";
}

スパゲッティを作る際にスローがより強力で柔軟であるという事実を私は知っていることに注意してください。それは私にとって主要な違いにはなりません。それは概念ではなく、使用の問題です。

編集
私は多くの人から、最初の例はもっと新しく使うべきだと言われました。
理由:例外は、ビジネスロジックを実装するためではなく、エラーを処理するためにのみ使用する必要があります。
それは賢明に見えます。

したがって、無駄なコードの実行を停止するために残された唯一の方法は、gotoです(while、returnなど、同じ問題ですが実装が難しいいくつかの代替は言うまでもありません)?

4

11 に答える 11

13

スロー/キャッチはgotoよりもはるかに柔軟性があります。例外をスローするコードを呼び出す関数からキャッチできます。さらに、必要なデストラクタは自動的に呼び出されます。

于 2010-07-25T13:59:12.560 に答える
7

逆に質問する必要があると思います。goto例外が状況に完全に適しているのに、なぜ使用するのでしょうか。それが例外です

「なぜ使うのかwhilefor同じくらい簡単に使えるのに機能するのか」と聞いてみてはgotoいかがでしょうか。

于 2010-07-25T13:56:55.740 に答える
5

goto実行パスをコードにハードコードします。一方、例外を使用すると、実行時に実行パスを決定できます。

たとえば、エラー時に例外をスローするデータベースクラスがあるとします。例外を除いて、そのエラーをキャプチャし、エラーページをレンダリングする前に何か他のことを行うことができます(割り当てられたリソースをクリーンアップする、または非トランザクションデータベースタイプを使用する場合は以前の変更を「ロールバック」するなど。gotoを使用した場合は、 gotoがエラーページをレンダリングするため、これを行う機会があります。

コードを再利用可能で柔軟に保つことを忘れないでください。 goto両方のアンチテーゼです...

于 2010-07-25T14:03:03.373 に答える
5

gotoあなたの例では、エラー条件をチェックし、例外を発生させるか、条件が失敗した場合に呼び出すので、事実上違いはありません。あなたの例は、どちらかの構成の必要性を取り除くために再コーディングすることができます。

例外役立つのは、エラー状態がある可能性があるが、次の擬似コードが示すようにそれ自体を処理できないメソッドを呼び出す場合です。

try
{
    $c = add($a, $b);
    echo '$a + $b = '.($c)."<br>\n";
}
catch (Exception $e)
{
    echo 'Caught exception: ', $e->getMessage(), "<br>\n";
}

このaddメソッドはエラーチェックを行います。

if (!isset($a))
{
    throw new Exception('$a is not set');
}
if (!isset($b))
{
    throw new Exception('$b is not set');
}

次に、加算の結果を返します。

これは、メインコードフローがプログラム内の予想されるパスを示していることを意味します。

于 2010-07-25T14:03:08.790 に答える
3

OPが受け入れ可能であると判断したこの質問に対する回答はまだ誰も提供していないので、私は帽子をリングに投げ込みます。

…次の2つのコードスニペットのコード構造の基本的な概念上の違いは?

提供した2つのコードスニペットの間に概念的な違いはまったくありません。どちらの場合も、条件がテストされ、満たされると、処理のためにプログラムの別の部分にメッセージがスローされます。

なぜ最初のものは素晴らしいと見なされ、後者は最も致命的な罪であると見なされたのですか?

次の暴言への扉を開いてくれた榴散弾大佐に感謝します。

<暴言>

すべてのプログラミング構造は、悪用される可能性があります。の独断的な迫害はgoto、PHPの同様のバッシングを思い出させます。PHPは悪いプログラミング慣行につながります。比較対象:後藤はスパゲッティコードにつながります。

簡単に言えばgoto、エドガー・ダイクストラがそう言って、ニクラウス・ヴィルトがそれに承認の印を与えたので、それは「悪」です。;-p

</ rant>

あなたの読書の楽しみのために:http://en.wikipedia.org/wiki/Goto

おそらく、GOTOに対する最も有名な批判は、1968年にエドガー・ダイクストラが書いた「有害と考えられるステートメントへの移行」という手紙です。その手紙の中で、ダイクストラは、プログラム(特にループを含むもの)の分析と検証のタスクを複雑にするため、無制限のGOTOステートメントを高級言語から廃止する必要があると主張しました。別の視点は、ドナルド・クヌースの構造化プログラミングに、go to Statementsで示されています。これは、多くの一般的なプログラミングタスクを分析し、そのうちのいくつかではGOTOが使用するのに最適な言語構造であることがわかります。

続けて、

LinuxカーネルデザイナーでコーダーのLinusTorvaldsやソフトウェアエンジニアで本の著者であるSteveMcConnellなどの一部のプログラマーも、Dijkstraの見解に反対し、GOTOは有用な言語機能であり、プログラムの速度、サイズ、コードの明確さを向上させることができると述べています。比較的賢明なプログラマーによって賢明な方法で使用されます。

そうは言っても、私はコモドールBASIC以来、個人的にGOTOの実用的な使用法を見つけていませんが、それはここにもそこにもありません。:-)

于 2011-10-21T16:39:33.560 に答える
3

gotoこのようなことをするのに十分です:

foreach ($items as $item) {
    if ($item->is_match()) goto match;
}

$item = new Item();

match:
render('find_item.php', $item);

これに対抗して:

$matching_item = null;
foreach ($items as $item) {
    if ($item->is_match()) {
        $matching_item = $item;
        break;
    }
}
if ($matching_item === null) {
    $item = new Item();
}

render('find_item.php', $item);
于 2010-10-14T14:06:35.870 に答える
2

goto例外スタックを作成しないため、throwと比較してパフォーマンスが少し向上する可能性があります。

于 2010-07-25T14:15:37.193 に答える
2

実際には、2つのコードセグメントの違いは、「goto」コードを使用して他のプログラマーに自分自身を説明するためにより多くの時間を費やす必要があることです。

良くも悪くも、ほとんどのプログラマーは、gotoを使用してはならないと信じています。おそらく、これが根拠のないものであり、gotoコードがその関数を実装するための最良の方法であることを証明できます。それでも、同僚や協力している他の人と戦って、彼らにそれを受け入れてもらう必要があります。

自分で作業していて、誰もあなたのコードを見ることができない場合は、好きなものを使用してください。ただし、チームで作業している場合は、抵抗が最も少ないパスが最も賢明な場合があります。

于 2010-07-26T13:26:21.137 に答える
2

「間違っている」のは、gotoだけでなく、さまざまな種類の制御メカニズムを実装できるthrowため、固有の構造がほとんどないことです。gotoこのため、スクリプトプログラマーが代替手段の使用に関心を持つ理由はいくつかあります。

まず、スクリプトが純粋に解釈されたものからバイトコードでコンパイルされたものに移行し始めています。この良い例は、Python、Perl 6、Scala(Lift)、Clojure(Compojure)など、どこにでもあります。PHPでさえバイトコードコンパイラを持っています。構造がほとんどないためgoto、制御メカニズムのコンパイルは実行できません。これは、最近のコンパイラーが一般的に非常に優れているため、パフォーマンスが大幅に低下します。の場合throw、コンパイラは、スローされる例外が一般的ではないと想定し始めることができるため、最適ではない「異常な」制御パスを犠牲にして、「通常の」制御パスを最適化することがよくあります。

本格的なコンパイラーを持っていなくても、プログラマーがより多くの構造を持つ制御メカニズムを使用すると、インタープリターはプログラマーをかなり支援することができます。たとえば、forループブロックはコンパイラー/インタープリターによって字句スコープが設定されるため、プログラマーはこのスコープを使用してコードのチャンクをモジュール化できます。そうしgotoないと、変数の名前空間を汚染することを余儀なくされます。

さらに、ご使用の言語でthrow例外のメソッドを宣言できる場合、コンパイラー/インタープリターは、呼び出しているメソッドで発生する可能性のあるすべての例外を処理していないことを通知できます(throwsJavaでの経験がある場合は、Javaと同様です)。を使用gotoすると、コンパイラーはユーザーが何をしようとしているのかわからないため、コンパイルおよびテスト中には役に立ちません。

Gotoはまた、プログラマーがエラーから回復することを要求します。このようなコード(スニペットから取得および編集されたもの)がある場合を想像してみてください。

if (!isset($a)) { 
  $message = '$a is not set';
  goto errorA;
}
if (!isset($b)) {
  $message = '$b is not set';
  goto errorB;
}
if (!moonInRightPhase) {
   goto errorP
}
echo '$a + $b = '.($a + $b)."<br>\n";

errorA:
// Do something non-trivial and unique to handle $a not being set.
goto afterError

errorP:
// Do something non-trivial and unique to handle moon phase
// This error requires drastic failure of code path:
goto failure

errorB:
// Do something non-trivial and unique to handle $b not being set.
goto afterError

afterError:
// Program continues

return SUCCESS

failure:
return FAILURE

ここでの問題は、プログラマーが正しいことをする必要があるということです。を忘れた場合はgoto afterError、次の例外パスを実行します。メカニズムを使用throwすると、エラーが発生しにくくなります。

最後に、私の個人的な経験gotoから、読みにくいという理由だけでその声明が嫌いになります。some-error、、、という名前の4つまたは5つのラベルが付いたコードを理解しようとしていてfailretryそれらが問題のある/例外的なコードの近くに配置されていない場合、解くのは悪夢になる可能性があります。また、読みにくい場合は、1年前に行ったことを確認しようとするプログラマーでさえ、間違いにつながる可能性があります。

この回答の追記として、私は「間違った」が正しい説明方法であるとは思いませんgoto。それは有名なダイクストラ紙をセンセーショナルにしたことから来たのかもしれません。「パワフル」は、ほとんどすべてのことができることを意味するため、より適切な用語かもしれませんが、最も単純な間違いでさえ、「間違った」を「ひどく間違った」に変えます。ツールは本当に危険なので、禁止すべきではありません。私たちは人々に彼らの危険についてよりよく教育し、彼らに決定させるべきです。

于 2011-04-20T21:58:37.050 に答える
0

GOTOはそれほど嫌いではありませんが、主な問題は特定の「スコープ」に限定されていないことだと思います。他のすべての制御構造では、それがどこから始まりどこで終わるかがわかります。一方、GOTOラベルは、より多くの予測できない場所に配置される可能性があります。もちろんラベルを検索することはできますが、読みやすさが損なわれます。

もちろん、すべてはそれがどのように使用されるかにかかっています。

于 2010-07-26T17:14:43.603 に答える
-3

どちらも使用しないでください。コードの大部分を「while(1)」で囲み、最後にジャンプしたい場所で「break」ステートメントを使用します。

while(1)
{
    if (!isset($a)) { 
      $message = '$a is not set';
      break;
    }
    if (!isset($b)) {
      $message = '$b is not set';
      break;
    }

    echo '$a + $b = '.($a + $b)."<br>\n";
    break;
}

if (!empty($message)) {
  echo 'Caught exception: ', $message, "<br>\n";
}
于 2010-07-26T17:07:12.370 に答える