GOTO是一个好习惯吗? (在这个特殊情况下?)

时间:2011-09-26 15:23:04

标签: php algorithm generics

我在向用户呈现错误的方式存在一些问题。我使用两个Goto指令“解决”了这个问题。请看一下代码:

<?php require_once("registration/include/membersite_config.php"); ?>
<!DOCTYPE html>
<html lang="en">
<head><?php include_once("parts/head.php"); ?></head>
  <body><div id="footerfix">
  <?php include_once("parts/header.php"); ?>
    <div class="container">
      <div class="hero-unit">
<?php
if(isset($_GET['i'])){ unlink("users/thumbs/".$_SESSION["user_code"].".jpg"); header('Location: profile.php?i=mycv');}
if(isset($_FILES['avatar']['tmp_name'])){
    $file_ext = end(explode('.',$_FILES['avatar']['name']));
    if(in_array($file_ext,array('jpg','jpeg','png','gif'))==false){echo("<h2>Error!</h2><p>Your profile photo have to be a picture file.</p>"); goto nomore;}
    $src_size=getimagesize($_FILES['avatar']['tmp_name']);
    if($src_size['mime']=='image/jpeg') {$src_img=imagecreatefromjpeg($_FILES['avatar']['tmp_name']);
    } elseif($src_size['mime']=='image/png') {$src_img=imagecreatefrompng($_FILES['avatar']['tmp_name']);
    } elseif($src_size['mime']=='image/gif') {$src_img=imagecreatefromgif($_FILES['avatar']['tmp_name']);
    } else {echo("<h2>Error!</h2><p>Incorrect file format.</p>"); goto nomore;}
    $thumb_w = 150;
    if($src_size[0]<=$thumb_w){$thumb=$src_img;
    }else{ 
        $new_size[0] = $thumb_w;
        $new_size[1] = ($src_size[1]/$src_size[0])*$thumb_w;
    $thumb=imagecreatetruecolor($new_size[0],$new_size[1]);
    imagecopyresampled($thumb,$src_img,0,0,0,0,$new_size[0],$new_size[1],$src_size[0],$src_size[1]);
    }
    imagejpeg($thumb,"users/thumbs/".$_SESSION["user_code"].".jpg");
    //header('Location: profile.php?i=mycv');
    echo('<h2>Ready!</h2><p>Your profile picture is updated. <a href="profile.php">Go back</a>.</p>');
    nomore: echo "</div></div>"; include_once("parts/footer.php"); echo "</div></body></html>";
}
?>

我从来没有理解为什么goto是代码中可能发生的最糟糕的想法(至少,每个人都这么说),我想听听你对此的看法,如果这真的是最糟糕的想法,那么怎么样?使用我的代码whitout他们?谢谢!

enter image description here

6 个答案:

答案 0 :(得分:7)

简短的回答为什么GOTO是一个坏主意:可读性受损。考虑一下:

<?php require_once("registration/include/membersite_config.php"); ?>
<!DOCTYPE html>
<html lang="en">
<head><?php include_once("parts/head.php"); ?></head>
  <body><div id="footerfix">
  <?php include_once("parts/header.php"); ?>
    <div class="container">
      <div class="hero-unit">
<?php
if(isset($_GET['i'])){ unlink("users/thumbs/".$_SESSION["user_code"].".jpg"); header('Location: profile.php?i=mycv');}
if(isset($_FILES['avatar']['tmp_name'])){
    $file_ext = end(explode('.',$_FILES['avatar']['name']));
    if(in_array($file_ext,array('jpg','jpeg','png','gif'))==false){
        echo("<h2>Error!</h2><p>Your profile photo have to be a picture file.</p>");
    }
    else {
        $src_size=getimagesize($_FILES['avatar']['tmp_name']);
        if($src_size['mime']=='image/jpeg') {
            $src_img=imagecreatefromjpeg($_FILES['avatar']['tmp_name']);
        } elseif($src_size['mime']=='image/png') {
            $src_img=imagecreatefrompng($_FILES['avatar']['tmp_name']);
        } elseif($src_size['mime']=='image/gif') {
            $src_img=imagecreatefromgif($_FILES['avatar']['tmp_name']);
        } else {
            echo("<h2>Error!</h2><p>Incorrect file format.</p>");
        }
        if(!empty($src_img)) {
            $thumb_w = 150;
            if($src_size[0]<=$thumb_w){
                $thumb=$src_img;
            }else{ 
                $new_size[0] = $thumb_w;
                $new_size[1] = ($src_size[1]/$src_size[0])*$thumb_w;
                $thumb=imagecreatetruecolor($new_size[0],$new_size[1]);
                imagecopyresampled($thumb,$src_img,0,0,0,0,$new_size[0],$new_size[1],$src_size[0],$src_size[1]);
            }
            imagejpeg($thumb,"users/thumbs/".$_SESSION["user_code"].".jpg");
            //header('Location: profile.php?i=mycv');
            echo('<h2>Ready!</h2><p>Your profile picture is updated. <a href="profile.php">Go back</a>.</p>');
        }
    }
}
?>
    </div></div>
    <?php include_once("parts/footer.php"); ?>
</div>
</body>
</html>

无论如何,您应该考虑将模板与逻辑(谷歌“MVC”)分开,并至少使用函数进行复杂的操作。

答案 1 :(得分:5)

你在这里使用goto对我来说似乎很合理,因为你基本上使用了以下模式:

if (error_condition_1) {
    goto handle_errors;
} else {
    // do stuff
}
if (error_condition_2) {
    goto handle_errors;
} else {
    // do stuff
}
// ...
if (last_error_condition) {
    goto handle_errors;
} else {
    // do stuff
}
// do stuff
handle_errors:
    // handling errors

还有其他方法可以做到这一点,不涉及转到;例如,您可以在适当的位置使用do ... while (false)循环和break语句。但是,这实际上只是模糊了你使用goto的事实。

goto在计算机程序员中具有贱民地位,这些日子在很大程度上是不公平的;在某些情况下,使用goto是一个完全合理的选择(不是大多数情况,我赶紧补充),但一般来说,使用goto可能会让你陷入困境,无论它是否是一个有效的设计选择。

正如Daniel Brockman所说,你的主要问题是你的代码难以阅读。它似乎挤满了尽可能少的线条,而且非常密集。看看其他人如何在他们的网站和其他地方展示他们的代码,看看你是否同意使用其他约定的代码更具可读性。

在PHP中,您需要记住goto仅在5.3版本中可用,因此如果您的代码需要可移植,您可能需要考虑其他选项。

答案 2 :(得分:2)

Goto通过创建意大利面条代码来介绍问题!换句话说,您将很难理解代码块中代码的流程!总是可以使用结构化控制结构并完全消除gotos!正如着名的计算机科学家Edsger W. Dijkstra所暗示的“Goto”在他1968年的文章“反对GO TO声明的案例”中被认为是有害的(文章由编辑Niklaus Wirth重新命名为“Go To Statement Considered Harmful”)。以控制结构的维基百科条目http://en.wikipedia.org/wiki/Control_structures为出发点。

这个概念适用于所有编程语言!

答案 3 :(得分:2)

你的代码很乱。实施GOTO声明会让它成为一场噩梦。 像XKCD节目一样,会发生可怕的事情。我记得当我开始学习C ++时,术语“Spaghetti代码”经常提到goto用法。它总会搞砸你的执行流程。更不用说它破坏了可读性。

无论如何,我已经为你重组了这个程序,现在应该可以了。

脚本


<?php require_once("registration/include/membersite_config.php"); 
    //redirect user if i is defined
    if(isset($_GET['i'])){ unlink("users/thumbs/".$_SESSION["user_code"].".jpg"); header('Location: profile.php?i=mycv');}
?>
<!DOCTYPE html>
<html lang="en">
<head><?php include_once("parts/head.php"); ?></head>
  <body>
    <div id="footerfix">
        <?php include_once("parts/header.php"); ?>
        <div class="container">
            <div class="hero-unit">
<?php

check_file();

function check_file(){
    //check for file 
    if(isset($_FILES['avatar']['tmp_name'])){
        //get the file extension
        $file_ext = end(explode('.',$_FILES['avatar']['name']));

        //validate extension
        if(in_array($file_ext,array('jpg','jpeg','png','gif')) ==false){
            echo "<h2>Error!</h2><p>Your profile photo have to be a picture file.</p>"; 
            return -1;
        }

        //get the image dimensions
        $src_size = getimagesize($_FILES['avatar']['tmp_name']);

        switch($src_size['mime']){
            case 'image/jpeg':
                $src_img=imagecreatefromjpeg($_FILES['avatar']['tmp_name']); break;
            case 'image/png':
                $src_img=imagecreatefrompng($_FILES['avatar']['tmp_name']); break;
            case 'image/gif':
                $src_img=imagecreatefromgif($_FILES['avatar']['tmp_name']); break;
            default:
                echo("<h2>Error!</h2><p>Incorrect file format.</p>");
                return -1;
        }

        $thumb_w = 150;

        //if image is within allowed dimensions, set thumbnail as image
        if($src_size[0]<=$thumb_w){
            $thumb = $src_img;
        }else{ 
            $new_size[0] = $thumb_w;
            $new_size[1] = ($src_size[1]/$src_size[0])*$thumb_w;
            $thumb= imagecreatetruecolor($new_size[0],$new_size[1]);
            imagecopyresampled($thumb,$src_img,0,0,0,0,$new_size[0],$new_size[1],$src_size[0],$src_size[1]);
        }

        //create the updated image
        imagejpeg($thumb,"users/thumbs/".$_SESSION["user_code"].".jpg");

        echo '<h2>Ready!</h2><p>Your profile picture is updated. <a href="profile.php">Go back</a>.</p>';
    }
}
?>
                </div>
            </div>
            <?php include_once("parts/footer.php"); ?>
        </div>
    </body>
</html>

如您所见,我将整个过程封装在一个函数中。这样,每当遇到错误时,您都可以执行return语句。使其成为一种功能还可以实现快速重用。您可以添加一些参数以使其更具动态性。

答案 4 :(得分:0)

GOTO在任何地方都不是一个好习惯。

答案 5 :(得分:0)

在我看来,continuebreak会更好。如果您想尝试使用goto,请考虑脚本的流程,可能会对其进行改进。