goto文はあるラベルに飛ぶために使われる構文のこと
PHPでもバージョン5.3.0以降でgoto文は使えるようになりました。
ただし自由自在にどこでも飛べるわけではなく、いくつか制約もあります。
そういう訳でPHPでのgotoの使い方と制約について詳しく紹介
このページの目次
goto文の基本的な使い方
gotoの使い方は他の言語で知っている人なら分かると思います。
ラベル label を定義したなら goto label; でその場所まで飛ぶだけ
1 2 3 4 5 |
/** ラベルを定義 */ label: /** ラベルに飛ぶ */ goto label; |
ラベルの場所は goto の前でも後にあっても構いません。
goto文の具体的な使い方ですが、分かりやすいのが次のコード例
1 2 3 4 5 6 7 8 9 10 11 12 |
for($i = 1; $i <= 10; $i++){ for($j = 1; $j <= 10; $j++){ for($k = 1; $k <= 10; $k++){ if($i * $j * $k === 120){ goto endloop; } } } } endloop: print_r("$i $j $k"); |
こういう風に3重以上の深いループを一気に抜けるときに便利です。
ただ当然これはgotoを使わなくても書けるし、gotoの多用はあまりよくありません。
なので多重ループなどどうしても使う必要のある場面だけで使うのが安全
そしてこのgoto文ですがラベルのある場所なら自由自在に飛べるわけではありません。
PHPではコードの可読性を保つためにある2つの制約があります。
PHPでのgoto文の2つの制約
その2つの制約とは次のようなこと
- 関数やメソッドの外には飛べない
- ループやswitchのなかにラベルは置けない
この2つの制約についてコード例と一緒に説明したいと思います。
関数やメソッドの外には飛べない
まず1つめは関数やメソッド内でgotoする場合、
- 外側に置いたラベルにジャンプ
- 別の関数やメソッドにジャンプ
などのように関数やメソッドの外には飛ぶことは不可です。
例えば次のように関数内でその外のラベルに飛ぶのはNG
1 2 3 4 5 6 7 |
function hoge(){ print_r('jump to hogehoge'); goto hogehoge; } hogehoge: print_r('hoge is called'); |
このコードを実行すると次のようなエラーメッセージが出て怒られてしまいます。
1 |
PHP Fatal error: 'goto' to undefined label 'hogehoge' |
関数外のラベルは undefined になるようですね。
また当然次のように他の関数やメソッドに飛ぶのもNG
1 2 3 4 5 6 7 8 9 |
function hoge(){ print_r('jump to piyopiyo'); goto piyopiyo; } function piyo(){ piyopiyo: print_r('jumped to piyopiyo'); } |
こちらも次のようなエラーメッセージが出てしまいます。
1 |
PHP Fatal error: 'goto' to undefined label 'piyopiyo' |
ということでラベルを関数やメソッド内に書く場合はその範囲内でしか使えないことに注意
まあどこにでも飛べてしまうと悪質なコードになるので当然と言えば当然ですね。
ループやswitchの外から内へはラベルは置けない
もう1つの制約はループやswitch文にするラベルの置き方について。
それは 外側=>内側 に飛ぶラベルは置けないこと
※ コメントでのご指摘ありがとうございました。
つまり ループ内部・siwtchブロック内部にラベルを置いて、gotoを使って外側からそのラベルに飛ぶことはできない という意味です。
例えば次のようにforループ内にgotoするのはNG
1 2 3 4 5 6 7 |
goto innerloop; for($i = 0; $i < 10; $i++){ for($j = 0; $j < 10; $j++){ /** ループ内にラベルを置くのはNG! */ innerloop: } } |
これを実行すると次のようなエラーメッセージが表示されます。
1 |
PHP Fatal error: 'goto' into loop or switch statement is disallowed |
for に限らず foreach や while 内にも当然ラベルを置いてはいけません。
また次のようにswitch内にジャンプしてしまうのもNG
1 2 3 4 5 6 7 8 9 10 11 |
goto innerswitch; switch(1){ case 1: break; case 2: /** switch内にラベルを置くのもNG! */ innerswitch: break; case 3: break; } |
このようにループやswitch内にジャンプすることができない点にも注意
ただしif文などループが絡まないステートメントには問題なくジャンプ可能です。
ちなみにJavaScriptでも goto文 は使用可能
蛇足だけど、JavaScriptでもgoto文(?)は使用できます。
▼ JavaScriptでのlabeled文の使い方とかコード例
まあ厳密には goto文 とは違い、色々制限があります。
その点は既存のgoto文(C言語とか)を改良した感じですね。
ここまでのまとめ
ということでPHPのgoto文のまとめ
- 任意のラベルに飛ぶ構文
ラベル label があるとすると goto label; でその場所まで飛べる
- ただし2つの制約あり
1つめ : 関数やメソッドで goto するときはその外に飛ぶことができない
2つめ : ループやswitch内にラベルを置いてジャンプすることも不可
ほとんどgotoを使う機会はないですが、もし使う必要があるなら2つの制約に注意です、
以上PHPでのgoto文の使い方と制約についてでした。
ではでは($・・)/~~~