GOTO

    Оказывается у создателей документации по PHP есть чувство юмора. Случайно наткнулся на иллюстрацию для одного из операторов в PHP 5.3. Оригинал под катом.

    image


    image

    Copyrights http://xkcd.ru & http://xkcd.com.

    Комментарии 157

      +5
      Neal Stephenson thinks it's cute to name his labels 'dengo'
        +4
        Goto Dengo :)
        Криптономикон — это очень хорошая книга :)
          –2
          Нил Стивенсон — это очень клевый автор.
            0
            Раз уж про Нила, то Криптономикон действительно так крут? Просто Лавина мне показалась полной фигнёй.
              0
              Это принципиально разные книжки. На мой взгляд Криптономикон гораздо интереснее. К тому же он жизненнее и в его основе лежат вполне конкретные исторические персонажи.

              Но на вкус и цвет…
        +3
        Неплохо было бы также дать линк на оригинал: xkcd
          0
          А так же на перевод :)
            0
            Добавил и то и то.
          • НЛО прилетело и опубликовало эту надпись здесь
          • НЛО прилетело и опубликовало эту надпись здесь
              +5
              jz и аналоги — это не goto, это if

              goto — это только jmp и (внимание!) call. Отличие последней в том, что по возможен возврат на точку, откуда тебя послали.

              А для высокоуровневых языков, goto — это действительно плохо, особенно если учесть, что возможны множественные точки выхода у функций.
              • НЛО прилетело и опубликовало эту надпись здесь
                  0
                  Goto у языков разные. Во многих (PHP в их числе) на уровень ниже (внутрь функции, цикла) переходить нельзя.
                    0
                    Тогда он вообще теряет смысл.
                    +3
                    если писать на чистом C (особенно для какой нибудь мелкой железки) то удобно оформлять функцию в виде

                    int foo()
                    {
                      FILE f = NULL;
                      int result = 0 ;
                      f = fopen("somefile.txt", "r");
                      if ( ! f ) {
                        perror("fopen");
                        goto exit;
                      }
                      
                      if ( rand() > 5 ) {
                        result = 1;
                        goto exit;
                      }

                      if ( rand() > 10 ) {
                        result = 2;
                        goto exit;
                      }

                      result = 3

                    exit:
                      if (f)
                        fclose(f);

                      return result;
                    }


                    имхо это читабельней чем городить кучу вложенных ifов
                      +1
                      Чистый С по современным меркам — язык низкого уровня.
                        +3
                        Конечно правильнов С использовать goto в таких случаях, ведь изначально С был задуман как красивый ассемблер.
                          +2
                          if (! f ) {
                          perror(«fopen»);
                          }
                          else if ( rand() > 5 ) {
                          result = 1;
                          }
                          else if ( rand() > 10 ) {
                          result = 2;
                          }
                          else {
                          result = 3
                          }

                          не красиво?
                            +5
                            в предыдущем было все же читабельнее за счет того, что видно было — сразу идем на выход.
                            0
                            на ЯВУ такое реализуется через try… finally, причем гораздо понятнее реализуется
                              +2
                              просто в С нет исключений :)
                                –1
                                Можно и без кучи if-ов и без goto ;)

                                1. int foo()
                                2. {
                                3.   FILE f = NULL;
                                4.   int result = ;
                                5.   f = fopen("somefile.txt", "r");
                                6.  
                                7.   do {
                                8.     if ( ! f ) {
                                9.       perror("fopen");
                                10.       break;
                                11.     }
                                12.  
                                13.     if ( rand() > 5 ) {
                                14.       result = 1;
                                15.       break;
                                16.     }
                                17.  
                                18.     if ( rand() > 10 ) {
                                19.       result = 2;
                                20.       break;
                                21.     }
                                22.  
                                23.     result = 3
                                24.  
                                25.   } while (false);
                                26.  
                                27.   if (f)
                                28.     fclose(f);
                                29.  
                                30.   return result;
                                31. }
                                  0
                                  я показал в примере очень простую функцию, если же функция сложная, с кучей вложенных while/for/switch то данный трюк не проходит
                                    +2
                                    >если же функция сложная, с кучей вложенных while/for/switch то....

                                    … она требует рефакторинга ;)
                                • НЛО прилетело и опубликовало эту надпись здесь
                                • НЛО прилетело и опубликовало эту надпись здесь
                                  –2
                                  Если имеется обширный опыт программирования, то можно пожалуйста увидеть код, который с goto, будет выглядеть, красиво и лаконично. И в который не надо будет всматриваться десять минут?
                                    +1
                                    <?php
                                    begin:
                                      echo $i++;
                                    goto begin;


                                    * This source code was highlighted with Source Code Highlighter.
                                      –1
                                      Смешно. А что-нибудь реальное?
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                          0
                                          А причем тут асм, если речь в данном топике о php?
                                            +28
                                            И часто вы php-код компилируете?
                                              +1
                                              Не поверите — каждый раз перед выполнением :)
                                              Если кэш опкода не подключен, конечно.
                                                0
                                                Бывает и по тысячи раз в день выходит. Да и при чем тут компиляция пыха и goto?
                                            –6
                                            for(int i = 0; i < arrayLength; ++i)
                                            {
                                                if (array[i] == 5) goto FOUND;
                                            }
                                            // doing somthing
                                            return false;
                                            FOUND:
                                            // doing somthing else
                                            return true;
                                            
                                              –3
                                              Конечно же, в жтом сулчае можно было обойтись флажком, например. В операторе гоуту нет ничего плохого, если использовать его с головой а не пихать везде подряд. И, опять же, если он такой плохой, почему этот оператор есть почти во всех языках?
                                                +4
                                                в этом случае даже без флага можно, т.к. у вас return все равно
                                                for(int i = 0; i < arrayLength; ++i) 
                                                {
                                                    if (array[i] == 5) {//found
                                                        // doing somthing else
                                                        return true;
                                                    }
                                                }
                                                //not found
                                                // doing somthing
                                                return false;
                                                
                                                  +2
                                                  Я лишь привел пример поиска. Ситуации, когда goto делает куд читабельнее и красивее есть. И поиск — это одина из вероятных ситуаций.

                                                  if (condition)
                                                  {
                                                     goto CANCEL;
                                                  }
                                                  // some code here
                                                  if (another_condition)
                                                  {
                                                      goto CANCEL;
                                                  }
                                                  // some another code here
                                                  return true;
                                                  
                                                  CANCEL:
                                                  // some cleanup code
                                                  return false;
                                                  


                                                  Сейчас вы наверное скажете, что можно разбивать на подфункции и т.п. Да можно. Но иногда возникают ситуации, когда другие решения являются менее красивыми. Конечно, можно лепить флажки, кучи условных уровней, десятки доп функций и т.п.

                                                  Нет ничего плохого в том, чтоб грамотно использовать goto. Я не сую его во все щели и мало того, в python, на котором я очень люблю писат оператора goto нет.
                                                    +4
                                                    >Но иногда возникают ситуации, когда другие решения являются менее красивыми.
                                                    Спасибо, поржал. Попросили привести реальный код, когда это оправдано, вы привели говнокод, сказали, что это говнокод и сказали, что есть ситуации. Вас снова попросили. Вы снова привели говнокод и снова сказали, что есть ситауции. Так приведите же, наконец, саму ситуацию, а не говнокод и надпись, что ситуация есть!
                                                      +1
                                                      Рад, что мне удалось поднять вам настроение.
                                                      0
                                                      Если нигде не ошибся, то вроде тоже самое будет:
                                                      if (!condition) {
                                                      // some code here
                                                      if (!another_condition) {
                                                      //some another code here
                                                      return true;
                                                      }
                                                      }
                                                      //some cleanup code
                                                      return false;
                                                        +1
                                                        Ой сорри:
                                                        if (!condition) {
                                                            // some code here
                                                            if (!another_condition) {
                                                                //some another code
                                                                return true;
                                                            }
                                                        }
                                                        //some cleanup code here
                                                        return false;
                                                        
                                                          0
                                                          теперь пердположим, что кондишенов пять

                                                          if (!condition) 
                                                          {
                                                              // some code here
                                                              if (!another_condition) 
                                                              {
                                                                  //some another code
                                                                  if (!another_condition) 
                                                                  {
                                                                      //some another code 
                                                                      if (!another_condition) 
                                                                      {
                                                                          //some another code 
                                                                          if (!another_condition) 
                                                                          {
                                                                              //some another code 
                                                                              return true;
                                                                          }
                                                                      }
                                                                  }
                                                              }
                                                          }
                                                          //some cleanup code here
                                                          return false;
                                                          


                                                          так?
                                                            0
                                                            Формально — да.
                                                            Только это все абстрактные куски кода.
                                                              0
                                                              Привидите реальный пример где у вас тру возвращается только при верности 5 условий, на каждое условие вы выполняете код, а клин делаете не зависимо от сочетания условий.
                                                              Я почти уверен, что в таком случае надо рефакторить.
                                                                0
                                                                Что-то у меня с русским не то =)
                                                                  +2
                                                                  Вы когда нить писали на чистом С? Знаете, там нет исключений.

                                                                  А теперь представьте себе код, который вызывает подряд n функций, каждая из которых может вернуть ошибку. Если возникла ошибка — мы прерываем выполнение кода и делаем какую-нить очистку.

                                                                  В результате у нас код выглядит приблизительно вот так:
                                                                  //malloc чего-нить
                                                                  do
                                                                  {
                                                                  if(func1())
                                                                  break;

                                                                  if(func2())
                                                                  break;

                                                                  if(func3())
                                                                  break;

                                                                  if(func4())
                                                                  break;

                                                                  }while(0)
                                                                  //free чего-нить
                                                                  Используется do{}while(0) только из-за предубежденности против goto. Хотя данная конструкция ничем не лучше (а может даже хуже) чем goto.

                                                                  Это почти реальный код для микроконтроллера. Логика парсинга пакетов и проведения платежей на POS-терминале.
                                                                  Размер памяти кода ограничен, размер оперативной памяти ограничен.

                                                                  Ваши предложения по рефакторингу?
                                                                    0
                                                                    В данном случае я не вижу особой разницы между goto и do-while, если честно.
                                                                    Однако, я соглашусь, что goto, модет быть полезен, НО там где не хватает других средств языка.
                                                                    В основном это будут низкоуровневые вещи (об асме ниже уже вспомнили).
                                                                    +4
                                                                    Вот пример из linux:

                                                                    int p54_read_eeprom(struct ieee80211_hw *dev)
                                                                    {
                                                                            struct p54_common *priv = dev->priv;
                                                                            struct p54_eeprom_lm86 *eeprom_hdr;
                                                                            struct sk_buff *skb;
                                                                            size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
                                                                            int ret = -ENOMEM;
                                                                            void *eeprom = NULL;
                                                                    
                                                                            maxblocksize = EEPROM_READBACK_LEN;
                                                                            if (priv->fw_var >= 0x509)
                                                                                    maxblocksize -= 0xc;
                                                                            else
                                                                                    maxblocksize -= 0x4;
                                                                    
                                                                            skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
                                                                                                maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
                                                                                                GFP_KERNEL);
                                                                            if (!skb)
                                                                                    goto free;
                                                                            priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
                                                                            if (!priv->eeprom)
                                                                                    goto free;
                                                                            eeprom = kzalloc(eeprom_size, GFP_KERNEL);
                                                                            if (!eeprom)
                                                                                    goto free;
                                                                    ...
                                                                    еще пол экрана кода
                                                                    ...
                                                                            ret = p54_parse_eeprom(dev, eeprom, offset);
                                                                    free:
                                                                            kfree(priv->eeprom);
                                                                            priv->eeprom = NULL;
                                                                            p54_free_skb(dev, skb);
                                                                            kfree(eeprom);
                                                                    
                                                                            return ret;
                                                                    }
                                                                    
                                                                      0
                                                                      согласен, ответил чуть выше.
                                                                      –2
                                                                      Вот кусок кода под действием предрассудков goto

                                                                      function _functiob( Url: PAnsiChar; var OutBuf: PAnsiChar ): Boolean;
                                                                      const
                                                                      UrlExpr: PAnsiChar = '(http://)?([^/]+)(.+)';
                                                                      HeaderTpl: PAnsiChar = 'GET ${3} HTTP/1.0'#13#10'Host: ${2}'#13#10'Connection: Close'#13#10#13#10;
                                                                      var
                                                                      S: TSocket;
                                                                      R: HRegExp;
                                                                      Cnt: Integer;
                                                                      Buf: PAnsiChar;
                                                                      BufLen, ResLen: Cardinal;
                                                                      begin
                                                                      OutBuf := Nil;
                                                                      Result := False;
                                                                      if ( Url = nil ) or ( RegComp ( UrlExpr, R ) <> RE_OK ) then
                                                                      Exit;
                                                                      S := INVALID_SOCKET;

                                                                      try
                                                                      if not RegExec( R, Url ) then
                                                                      Exit;
                                                                      Buf := RegMatchStr( R, 2 );
                                                                      if (Buf = nil) then Exit;
                                                                      S := CreateSocketAndConnect( Buf );
                                                                      StrDispose( buf );
                                                                      if ( S = INVALID_SOCKET ) then
                                                                      Exit;

                                                                      Buf := StrNew(Url);
                                                                      BufLen := StrLen(Buf);
                                                                      RegReplace(UrlExpr, HeaderTpl, Buf, BufLen, 1);
                                                                      if (not SendSocketData(S, Buf, BufLen)) then
                                                                      Exit;

                                                                      ResLen := 0;
                                                                      OutBuf := Nil;
                                                                      BufLen := StrBufSize(Buf);
                                                                      repeat
                                                                      Cnt := Recv( S, Buf^, BufLen, 0 );
                                                                      if Cnt > 0 then
                                                                      CollectBuf(Buf^, OutBuf, ResLen, Cnt);
                                                                      until (Cnt <= 0);

                                                                      If (GetHTTPAnsvNFromHeader(OutBuf) <> 200) then
                                                                      Exit;

                                                                      BufLen := GetHeaderSize( OutBuf );
                                                                      if (BufLen = 0) then Exit;

                                                                      Dec ( ResLen, BufLen );
                                                                      Move ( OutBuf[BufLen], OutBuf^, ResLen );

                                                                      StrRealloc(OutBuf, ResLen + 1);
                                                                      OutBuf[ResLen] := #0;
                                                                      Result := True;
                                                                      finally
                                                                      if (Buf <> Nil) then StrDispose(Buf);
                                                                      if (not Result) and ( OutBuf <> Nil ) then
                                                                      begin
                                                                      StrDispose(OutBuf);
                                                                      OutBuf := Nil;
                                                                      end;
                                                                      if (S <> INVALID_SOCKET) then
                                                                      CloseSocket( S );
                                                                      RegFree( R );
                                                                      end;
                                                                      end;

                                                                      Try..Finally+ Exit внутри блока вместо goto.
                                                                      +1
                                                                      if(!condition && !another_condition && !another_condition && !another_condition) {
                                                                        return true;
                                                                      } else {
                                                                        return false;
                                                                      }
                                                                      


                                                                      А может так? :)
                                                                        0
                                                                        только там еще есть

                                                                        // some code here

                                                                          +1
                                                                          Да, комментарии-то я и упустил… однако если внутри каждого условия код — то то как они выглядят в коде имхо вполне оправданно, по уровню вложенности можно легко понять при каких конкретно условиях выполнится конкретный кусок кода, это имхо визуально гораздо более наглядно, а в случае с goto придется просматривать каждую строку досконально, потому как помимо

                                                                          if(condition) {
                                                                            // кусок кода, который зависит от условия
                                                                            // и вызывает преждевременную остановку программы
                                                                            goto CANCEL;
                                                                          }
                                                                          

                                                                          может быть и

                                                                          if(condition) {
                                                                            // кусок кода, который зависит от условия
                                                                            // но не вызывает преждевременную остановку программы
                                                                          }
                                                                          
                                                                            0
                                                                            Все верно. Я просто не исключаю случаи, когда оператор goto становится полезным, мало того, я иногда его использую.

                                                                            Мне не по душе крики о том, что использование оператора goto — это удел красноглазиков. Это и пытался донести.
                                                                          0
                                                                          тогда уж лучше сделать что-то вроде:
                                                                          if(checkConditions()) {
                                                                          } else {
                                                                          }

                                                                          а в чек кондишнс можно уже и написать что-то вроде
                                                                          return checkFirstCondotion() && checkSecondCondition() && ...;

                                                                          потому как иногда условия могут и по несольку строчек быть.
                                                                    +1
                                                                    особые извращенцы в страхе goto пишут так (и считают это хорошим стилем):
                                                                    do {
                                                                    if (condition)
                                                                    break;

                                                                    // some code here
                                                                    if (another_condition)
                                                                    break;

                                                                    // some another code here
                                                                    return true;

                                                                    } while (0);

                                                                    // some cleanup code
                                                                    return false;

                                                                    Вот по-моему уж лучше goto.
                                                                      0
                                                                      >особые извращенцы в страхе goto пишут так (и считают это хорошим стилем):

                                                                      Вот по-моему уж лучше goto.


                                                                      Вы не поверите, но это не просто «считается» — это и есть хороший стиль, и мифический «страх goto» тут не при чём.
                                                                      Когда читаешь код, то при использовании конструкции «do {...} while(0);» найти «точку выхода» гораздо легче, потому что она в заранее известном месте: в конце блока. При использовании goto выход может оказаться где угодно.
                                                                        0
                                                                        Простите, а как же семантика?

                                                                        Любой, кто видит конструкцию «do {...», начинает сначала вдумываться зачем тут нужен цикл, и только потом, в конце, обнаруживает "} while(0);". Это может сильно путать.

                                                                        Иными словами, do… while предназначено для другого, а именно — для циклов с постусловием. И с точки зрения семантики для других целей эта конструкция не применима.
                                                                          0
                                                                          Если выбирать между 100%-верной и правильной семантикой с одной стороны и читабельностью кода с другой стороны — лично я выберу второе.

                                                                          Можно сколь угодно долго теоретизировать над семантикой, но в «полевом» применении код с «do {...} while(0);» читается и сопровождается намного легче — это факт.

                                                                          А уж если рассуждать с точки зрения семантики и возводить всё в абсолют, то конструкция for(;;) тоже неприменима: оператор for предназначен для другого, а именно — для цикла с первичной инициализацией, условием и выполнением оператора после каждой итерации. А для бесконечного цикла надо использовать while(true). Верно? ;)
                                                                            0
                                                                            > лично я выберу второе.

                                                                            я не знаю ни одного примера, когда следование правилам семантики вредит читаемости кода. и наоборот, отступление от семантического порядка — всегда вредит.

                                                                            >читается и сопровождается намного легче — это факт

                                                                            все же — не факт. сильно запутывает, когда для решения одних задач используются конструкции, предназначенные для других задач (то есть когда нарушается семантика, не спроста же она придумана).

                                                                            > А для бесконечного цикла надо использовать while(true). Верно?

                                                                            while(true) действительно несколько более предпочтительно. гикам нравится использовать for(;;) только потому, что это на несколько символов короче.

                                                                            но нужно помнить, что с точки зрения семантики while(true) — все равно не идеально, так как это цикл с предусловием, которого в случае вечного цикла получается что нет.

                                                                            то есть с точки зрения семантики было бы логично ввести специальную конструкцию для вечных циклов, скажем, loop {… }.

                                                                            но этого нет и не будет, потому что, помимо всего прочего, в идеале, вечных циклов в реальных программных продуктах вообще не должно быть (тема для нового холивара?), но это уже другая тема…
                                                                              0
                                                                              >я не знаю ни одного примера, когда следование правилам семантики вредит читаемости кода. и наоборот, отступление от семантического порядка — всегда вредит.

                                                                              Т.е. текущий пример с goto Вам не нравится?

                                                                              Вы отойдите от теории и спуститесь на землю: вот читаю я чей-то код, тут мне попадается «goto some_label;» — и где я её должен искать? Запускать поиск? Скроллить и пытаться поймать глазами? И хрен с ним, что неудобно искать — зато, панимашь, семантически верно, да?
                                                                              А вот если стоит do {...} while(false), то я знаю наверняка, куда мы попадём после break: в конец блока, который видно даже невооружённым беглым взглядом, кинутым по диагонали. Будете спорить?

                                                                              Может быть, всё же стоит убавить градус категоричности в своих заявлениях?
                                                                                0
                                                                                >> А вот если стоит do {...} while(false), то я знаю наверняка, куда мы попадём после break: в конец блока, который видно даже невооружённым беглым взглядом, кинутым по диагонали.

                                                                                Как метка так и конец блока могут как быть так и не быть в пределах досягаемости беглого взгляда. Метка хороша тем, что это не какая-то безликая скобочка и ее можно найти поиском. И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.
                                                                                  0
                                                                                  >Как метка так и конец блока могут как быть так и не быть в пределах досягаемости беглого взгляда.

                                                                                  При скролле глаз цепляется за изменение уровня вложенности куда легче, чем за текстовую метку.

                                                                                  >И она не уйдет со своего места, если кто-нибудь захочет поместить внутрь do {} while(0) вложенный цикл, по случаю охватывающий и ваш break.

                                                                                  Вдруг откуда ни возьмись случайно взялся вложенный цикл? :)
                                                                                  Ну извините, тут мне действительно нечего возразить…

                                                                                  В общем, я свои аргументы привёл, а уж решать, весомые они или нет — личное дело каждого.
                                                            +2
                                                            for(;;)
                                                            {
                                                            echo $i++;
                                                            }
                                                              +2
                                                              while(1)
                                                              {
                                                              echo $i++
                                                              }

                                                                0
                                                                вопрос стилевых предпочтений.

                                                                я предпочитаю кодировать infinite loop как for(;;).
                                                                  +2
                                                                  while(1) это классический пример бесконечного цикла

                                                                  Хотя кому как больше нравится ;)
                                                                    0
                                                                    Такая конструкция в некоторых языках вызывает warning, поэтому обычно пишут все-таки for (;;) { }
                                                                    –1
                                                                    И часто Вам приходится кодировать infinite loop?:)
                                                                      0
                                                                      Как ни странно, но приходилось. =) Давно это было и не правда. Даже не помню зачем.
                                                                        0
                                                                        проверить таймаут скрипта :)
                                                                          0
                                                                          приём системных сообщений в win проге или принимающего секета.
                                                                        +1
                                                                        Для демонов различного рода достаточно обычный код.
                                                                          0
                                                                          Спасибо. Я сам не додумался чего-то. Возможно для вечно работающих сервисов — самое оно.
                                                                          Хотя звучит как-то все равно коряво. Ведь должны же быть какие-то возможность остановки. Т.е. нужно в цикл этот передать событие, которые остановит этот цикл.
                                                                          Думаю, что для этого конструкция for(;;) врядли подойдет — вот while(boolen) как-то красивее смотрится…
                                                                      +3
                                                                      for (;; print($i++)) {}
                                                                        +3
                                                                        for (int y=0;;printf("%d", ++y));
                                                                        или
                                                                        for (int y=0;printf("%d", ++y););
                                                                          0
                                                                          я фигею, дорогая редакция:)
                                                                          0
                                                                          тогда уж
                                                                          for (;; print($i++)) ;

                                                                          но нафик-нафик такие «оптимизации» )))
                                                                        +3
                                                                        while(print $i++);
                                                                      –1
                                                                      Классика:

                                                                      for(int i = 0; i < M; ++i)
                                                                      for(int j = 0; j < N; ++j)
                                                                      {
                                                                      do_something();
                                                                      if(some_condition())
                                                                      goto exit;
                                                                      }
                                                                      exit:;

                                                                      Попробуйте написать это лаконично и красиво БЕЗ goto.
                                                                        +1
                                                                        меня Ваш и все выше примеры подталкивают, что спор не про goto, а про ООП и процедуры, что попахивает холиваром :)

                                                                        в вашем случае вместо goto exit — return; потому что код внутри метода.
                                                                        понадобился goto внутри одного метода? — рефакторинг.
                                                                          +1
                                                                          Я вот что думаю: никто же не говорит, что break (AKA exit for) — это плохо. Есть такое понятие (чисто концептуально): выход из цикла. Так уж сложилось, что традиционные языки вроде С++ поддерживают выход из цикла только на один уровень вверх (ниже пишут, что в Javascript и РНР можно и на два уровня).

                                                                          Возможно, здесь можно выделить метод, сделать рефакторинг и т.п., но не будем заставлять телегу бежать впереди лошади. Предположим, у меня есть алгоритм с циклом посередине. Я не хочу рефакторинга, пусть будет в одной процедуре. Из цикла выходим с помощью break. Теперь у меня есть вложенный цикл. По сути это то же самое — цикл + выход из него. Здесь нужно делать реорганизацию кода лишь из-за того, что язык не позволяет выйти из вложенного цикла?! :)
                                                                            +1
                                                                            Вы правильный вопрос задали, как я выше написал — мы на грани холивара. :)
                                                                            return из inline функций, тоже можно расценивать как goto :)

                                                                            break — это, фактически, тот же goto, с этим я согласен и потому стараюсь им не пользоваться. во всяком случае, каждый раз, когда мне приходит в голову использовать break я оцениваю код — не пришло ли время рефакторинга.

                                                                            на самом деле, я считаю, что вопрос использовать goto или нет — в основном (но не только), удобство работы в команде, т.е. читаемость Вашего кода другими разработчиками, без Вашего участия. если не использовать «goto vpizdu», т.е. не всегда очевидно куда :), возможно такие конструкции бывают понятны и уместны, но, как видно из практики вообще и из этого топика в частности, большинство разработчиков goto воспринимают негативно.

                                                                            ps: например, мне за ~8 лет работы ни разу не пришлось/захотелось написать goto, хотя, возможно, это мои предрассудки.
                                                                              0
                                                                              Да, холивар — штука опасная :) В принципе, конечно, главное — читабельность. В конце концов, если Вам не нравится goto, сделаете рефакторинг, но код с выходом за пределы двойного цикла тоже понятен сразу — и даже если Вы сами его не пишете, другого поймёте.

                                                                              А методологии… ээх, в большинстве учебников по С++ сейчас пишут: нигде и никогда не используйте препроцессор! При этом открываешь boost, и видишь, что половина его написана на чистом препроцессоре :)
                                                                                0
                                                                                в ситуации с выходом из двойного цикла, я подозреваю, проблема в двойном цикле, хотя, опять же, возможно, я просто не сталкивался с нужной для такого решения задачей.
                                                                          +1
                                                                          Не знаю, красиво это, или некрасиво, я в таких случаях всегда выставляю флаг. Его еще можно как-нибудь понятно назвать.
                                                                            0
                                                                            Ну так приведите код — подозреваю, будет неприятная бодяга с двумя break-ами.
                                                                              0
                                                                              Что-то типа такого:
                                                                              exit_flag = False
                                                                              while(!exit_flag) {
                                                                                  while(!exit_flag) {
                                                                                   ....
                                                                                   exit_flag = True;
                                                                                   break;
                                                                                   ....
                                                                                  }
                                                                              }
                                                                              
                                                                                0
                                                                                Да, но у вас пропал цикл с перебором i и j. Если их добавить, получится куда грустнее и объемнее.
                                                                                  0
                                                                                  Вообще-то я всегда ставил строчку:

                                                                                  for(...
                                                                                      if(!exit_flag) { break; }
                                                                                  


                                                                                  Но вот буквально сейчас подумал, что ведь наверное можно и так:

                                                                                  exit_flag = False;
                                                                                  for(i=0;i++;i<10 && !exit_flag) {
                                                                                    if(!exit_flag) { break; }
                                                                                    for(j=0;j++;j<10 && !exit_flag) {
                                                                                      ...
                                                                                      exit_flag = True;
                                                                                      ...
                                                                                    }
                                                                                   }
                                                                                  
                                                                                    +1
                                                                                    Ну что ж, здесь я сдаюсь. Чудес не бывает. Приведённый Вами код и есть лучшее, что можно сделать без goto. Но красивее и лаконичнее ли он моего? На мой взгляд — нет. Мне кажется, goto для выхода из двойного цикла читается лучше этого варианта с флагом. А главное (!) зачем? Только ради того, чтобы избавиться от «неправильного» оператора.
                                                                                      0
                                                                                      Да я не спорю, просто делюсь опытом. Для меня, мой метод — это стандарт. Работает во всех почти во языках.

                                                                                      А goto я не применяю. В сложных случаях я всегда применяю флаги с читабельными названиями.

                                                                                      Цель — максимально повысить читабельность кода. На мой взгляд в последнем примере хорошо то, что в строке for сразу и в одном месте видны все условия, по которым производится выход из этого цикла.
                                                                                      0
                                                                                      Приношу извинения. Забыл убрать строчку с if(), в предыдущем сообщении следует читать:

                                                                                      exit_flag = False;
                                                                                      for(i=0;i++;i<10 && !exit_flag) {
                                                                                        for(j=0;j++;j<10 && !exit_flag) {
                                                                                          ...
                                                                                          exit_flag = True;
                                                                                          ...
                                                                                        }
                                                                                       }
                                                                                      
                                                                                        0
                                                                                        А если внутри первого цикла есть какой-то код, выполняющийся после тела второго цикла, то в случае «моментального выпрыгивания» он не выполнится, а в Вашем случае — выполнится ;)
                                                                                          0
                                                                                          Конечно, только это ни хорошо и ни плохо. Это должен предусмотреть программист.
                                                                                  0
                                                                                  Добавил: Причем break нужен только тогда, если хотим, чтобы операторы после выставления флага не выполнялись. Обычно можно совсем без брейков.
                                                                                0
                                                                                break 2
                                                                                  +1
                                                                                  очевидно, что меньшая часть языков поддерживает такое.
                                                                                    0
                                                                                    мы с Вами в блоге PHP, верно?
                                                                                  +1
                                                                                  Если бы вы знали язык на котором пишете, то наверняка бы вспомнили, что есть такая чтука как break, которой можно указать сколько цикцлов или структур switch, из которых надо выйти:

                                                                                  for($i = 0; $i < 10; $i++) {
                                                                                      for($j = 0; $j < 10; $j++) {
                                                                                          $result = $i*10 + $j;
                                                                                          var_dump($result);
                                                                                          if($result == rand(0, 99)) {
                                                                                              break 2;
                                                                                          }
                                                                                      }
                                                                                  }
                                                                                  
                                                                                  


                                                                                  Почитайте доки, они полезны.
                                                                                    +1
                                                                                    Я не пишу на РНР — мне кажется, данная ветка обсуждения уже слегка выходит за пределы конкретных языков. Да, в РНР можно так, но мало где ещё можно.
                                                                                      –1
                                                                                      Не вижу чем это лучше GOTO при выходе из двойного цикла? А если тройной и т.п.? Когда читаю ваш код, я буду отсчитывать два цикла назад, искать конец блока внешнего цикла. Здесь конечно всё очевидно, но бывает куда больше строк кода в обоих циклах, что можно сильно запутаться. А тут раз и условие, переходим в метку и читаем код дальше. Согласен, что этот пример куда лучше чем с флагами, но всё-же.
                                                                                    0
                                                                                    Полуркай linux kernel
                                                                                  +18
                                                                                  Странно, что на динозавре нет наездника-нациста.
                                                                                    –3
                                                                                    В asm без goto будет тяжело ;)

                                                                                    А для PHP — это зло
                                                                                      –2
                                                                                      Что же тогда сказать о PHP-GTK?
                                                                                        +8
                                                                                        кошмар
                                                                                      –13
                                                                                      А я за goto. Фильтровать быдлокодеров.
                                                                                      Открыл код, увидел goto, послал нах. Если конечно знаешь, как сделать без goto.
                                                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                                                          +23
                                                                                          возможно, предложение не согласовано :))
                                                                                          (с) Майкрософт Ворд
                                                                                            0
                                                                                            человек пошутил, а вы его заминусовали:) лично мне его сарказм понравился:)
                                                                                              0
                                                                                              человек пошутил, а вы его заминусовали:) лично мне его сарказм понравился:)
                                                                                                0
                                                                                                сорри за второй коммент — видимо из-за связи!
                                                                                              +1
                                                                                              Помню где-то раздобыли часть исходников виндовса, в которых я нашел строку «goto vpeezdoo»
                                                                                                +12

                                                                                                if((ArrCharDead[i].keyindex == index) && (ArrCharDead[i].numdead == ActiveDead))
                                                                                                goto vpizdu;


                                                                                                исходники
                                                                                                  0
                                                                                                  это шутка? чья?
                                                                                                0
                                                                                                <+cyth> loonysalmon, here is the rule, if you have to ask about goto, forget it exists

                                                                                                © ##php @ irc.freenode.net, только что
                                                                                                  +7
                                                                                                  Для выхода из нескольких вложенных циклов считаю вполне допустимым использовать goto.
                                                                                                    +10
                                                                                                    О, догматики уже минусов понаставили :-)
                                                                                                    Использование goto для выхода из нескольких вложенных циклов — нормальная практика.
                                                                                                    stackoverflow.com/questions/324831/breaking-out-of-a-nested-loop

                                                                                                    Нельзя догматично отвергать goto. Этот оператор есть во всех языках, где он нужен.
                                                                                                    Надо просто понимать, в каких (редких) случаях стоит его использовать.
                                                                                                    Дональд Кнут целую большую статью написал по этому поводу. Догматикам советую почитать на досуге для развития способности критически мыслить: http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf (PDF).
                                                                                                      +6
                                                                                                      Эм… Возможно, что я не понял вашей великой мысли… Но нельзя ли в вашем примере, переписанном на PHP (ведь мы сейчас о нем говорим, да?), просто использовать циферки, соответствующие вложенности? Навроде этого:

                                                                                                      while(true) {
                                                                                                      while(true) {
                                                                                                      break 2;
                                                                                                      }
                                                                                                      }

                                                                                                      А вообще по теме — кто захочет написать код, в котором невозможно разобраться, у того это получится и без goto :-)
                                                                                                        +2
                                                                                                        Ну тут уже дискуссия не только про PHP пошла.
                                                                                                        А про break «levels» в PHP не знал, каюсь :-) Ибо не использую PHP практически.
                                                                                                          0
                                                                                                          break 2 это ещё большее зло, чем goto наружу цикла. Программист не обязян уметь считать уровни вложенности, к тому же при рефакторинге их количество может измениться.

                                                                                                          Более-менее правильно сделано в жаваскрипте:
                                                                                                          top:
                                                                                                          while(true) {
                                                                                                            while(true) {
                                                                                                              break top;
                                                                                                            }
                                                                                                          }
                                                                                                          
                                                                                                            –3
                                                                                                            программист «не обязан»… ну-ну =)
                                                                                                              –2
                                                                                                              продолжая мысль о необязательности уметь считать уровни вложенности — «Программист не обязан знать чего делает его код» =))
                                                                                                              +1
                                                                                                              Подумалось… Вот именно в такой ситуации, break N ещё более великое зло, чем goto.

                                                                                                              Объясняю: если указан goto somewhere, то вне зависимости от дальнейших модификаций кода, goto somewhere будет выходить именно на somewhere, а не куда-то ещё.

                                                                                                              А вот break N в случае добавления/убирания циклов будет выкидывать не туда, куда надо, и такую ошибку очень легко допустить, особенно если код циклов достаточно большой, а не три строчки как в вышеприведённых примерах.

                                                                                                              Так что в плане дальнейшей поддержки кода goto выглядит привлекательнее, чем break N.

                                                                                                              Хотя лично сам goto в php никогда не использовал и не имел даже такого побуждения. Как-то код всегда рефакторился в удобочитаемый вид без подобных выкрутасов.
                                                                                                          +2
                                                                                                          в php есть goto? :-)
                                                                                                            0
                                                                                                            5.3
                                                                                                              0
                                                                                                              Зачем они его добавили, они мотивировали? :)
                                                                                                                +3
                                                                                                                Видимо у них есть отличный план. Чего только стоит их предыдущий перл про выбор названия для "::" (двойного двоеточия):
                                                                                                                «Paamayim Nekudotayim» на первый взгляд может показаться странным словосочетанием для обозначения двойного двоеточия. Однако, во время создания Zend Engine версии 0.5 (который входил в PHP3), Andi и Zeev выбрали именно это обозначение. «Paamayim Nekudotayim» действительно значит «двойное двоеточие». На иврите. Просто это обозначение не менялось ни разу в течение всего времени разработки PHP.
                                                                                                                  0
                                                                                                                  Ответ на картинке… Очень полезная вещь в редких случаях. Ну не переписывать же весь код на самом деле?
                                                                                                              +2
                                                                                                              Не чоень понятно, при чём тут вообще PHP и создатели его документации :)
                                                                                                                +1
                                                                                                                это все питонисты и рубисты завидуют, у них то goto нет!
                                                                                                              –4
                                                                                                              боян
                                                                                                                –4
                                                                                                                Покормить тролля?
                                                                                                                +1
                                                                                                                Вспомнился случай с первого курса:
                                                                                                                Нам читали С. Чувак намутил прогу, а там GOTO. Препод говорит: плохой стиль, перепеши — тогда я приму. А он в программировании null (как и преподша вообщем). Он взял и табом позаганял метки за пределы экрана, и к преподше… Зачет.
                                                                                                                ЗЫ. Преподшу поменяли только год назад, это через 6 лет после того случая. Весь факультет знал, что она тупая.
                                                                                                                  +1
                                                                                                                  =D У нас многие так угарали =) всё что мешало загоняли далеко…
                                                                                                                    +1
                                                                                                                    метод последовательных табуляций
                                                                                                                  +1
                                                                                                                  Ну вот, зачем сказали, что он там теперь есть? Я расстроен.
                                                                                                                    +1
                                                                                                                    В чём причина вашего расстройства? Вас не печалит, что goto есть в Си?
                                                                                                                      0
                                                                                                                      В Си меня все устраивает, даже больше, чем.
                                                                                                                      А вот от ПХПпистов не ожидал… злого break и так хватало…
                                                                                                                    0
                                                                                                                    Что-то мне уже давно не приходилось видится с goto, с тех пор как освоил ООП и структурное программирование. Да и необходимости даже не было.

                                                                                                                    P.S. Как никак, без goto уже обхожусь 3 года. Вспоминаю страшные программы однокурсников по паскалю, где этих goto было не счесть.
                                                                                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                                                                                        +2
                                                                                                                        Эх, молодость, ZX Spectrum :)
                                                                                                                        0
                                                                                                                        Holy war never changes…
                                                                                                                          +4
                                                                                                                          Вот хаете тут, а никто даже не посмотрел или не упомянул, что goto в PHP имеет следующие ограничения:

                                                                                                                          1). Нельзя выпрыгнуть за пределы цикла и case'ов.
                                                                                                                          2). Возвращатся НЕЛЬЗЯ, т.е. перейти на метку можно только вперёд по потоку выполнения программы. Т.е. бесконечные циклы с помощью goto — забудте.
                                                                                                                            +1
                                                                                                                            1) Тогда смысла в нем вообще нет — из двойного цикла не выйти. Только добавит в код макарон.
                                                                                                                              0
                                                                                                                              А выход есть — через break(2) ;)
                                                                                                                            –1
                                                                                                                            GOTO снова в моде :-)
                                                                                                                            Все новое — хорошо забытое старое.
                                                                                                                              +2
                                                                                                                              Исходники ядра linux не хило нашпингованы оперетором goto
                                                                                                                                +1
                                                                                                                                О-о, холивар такой холивар :)
                                                                                                                                  +3
                                                                                                                                  Оператор вызова злого раптора [x]
                                                                                                                                    +2
                                                                                                                                    В php достаточно языковых конструкций для того чтобы полностью исключить использование оператора goto, и все слюнопускательства по поводу «а вот в ассемблере, а вот в си, а вот в...» — пустая болтология, вот пусть в языках где единственная возможность выйти из вложенного цикла — это goto — его и вводят, благо в php такая возможность есть и без goto, а еще функции/методы, исключения и иже с ними, которые все вместе с лихвой покрывают необходимость в goto.
                                                                                                                                      +2
                                                                                                                                      Плюс один. Зато у говнокодеров появится ещё больше возможностей испортить код, а у критиков — попенять на то, что php-шники не умеют нормально программировать.

                                                                                                                                      Нормальные языки _помогают_ писать хорошие программы, а PHP своей бездарной архитектурой провоцирует писать говнокод… Только теперь он будет банановый — с goto.

                                                                                                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                                                                    Самое читаемое