PHP: ข้อยกเว้นและข้อผิดพลาด?


117

บางทีฉันอาจจะพลาดที่ไหนสักแห่งในคู่มือ PHP แต่อะไรคือความแตกต่างระหว่างข้อผิดพลาดและข้อยกเว้น? ความแตกต่างเดียวที่ฉันเห็นคือข้อผิดพลาดและข้อยกเว้นจะได้รับการจัดการที่แตกต่างกัน แต่อะไรทำให้เกิดข้อยกเว้นและอะไรทำให้เกิดข้อผิดพลาด?

คำตอบ:


88

มีการโยนข้อยกเว้น- ตั้งใจให้จับได้ ข้อผิดพลาดมักไม่สามารถกู้คืนได้ ยกตัวอย่างเช่นคุณมีบล็อกโค้ดที่จะแทรกแถวลงในฐานข้อมูล เป็นไปได้ว่าการโทรนี้ล้มเหลว (รหัสซ้ำ) - คุณจะต้องมี "ข้อผิดพลาด" ซึ่งในกรณีนี้คือ "ข้อยกเว้น" เมื่อคุณแทรกแถวเหล่านี้คุณสามารถทำสิ่งนี้ได้

try {
  $row->insert();
  $inserted = true;
} catch (Exception $e) {
  echo "There was an error inserting the row - ".$e->getMessage();
  $inserted = false;
}

echo "Some more stuff";

การเรียกใช้โปรแกรมจะดำเนินต่อไป - เนื่องจากคุณ 'จับได้' ข้อยกเว้น ข้อยกเว้นจะถือเป็นข้อผิดพลาดเว้นแต่จะถูกจับได้ จะช่วยให้คุณดำเนินการโปรแกรมต่อไปได้หลังจากที่ล้มเหลวเช่นกัน


29
Errors are generally unrecoverable<- อันนี้ไม่จริงเลย E_ERRORและE_PARSEเป็นข้อผิดพลาดที่ไม่สามารถกู้คืนได้ที่พบบ่อยที่สุดสองข้อ (มีอีกสองข้อ) แต่ข้อผิดพลาดส่วนใหญ่ที่คุณจะเห็นใน dev นั้นสามารถกู้คืนได้ ( E_NOTICE, E_WARNINGและคณะ) น่าเสียดายที่การจัดการข้อผิดพลาดของ PHP เป็นเรื่องที่ยุ่งเหยิง - ทุกสิ่งทำให้เกิดข้อผิดพลาดโดยไม่จำเป็น (เช่นฟังก์ชันระบบไฟล์ส่วนใหญ่เป็นต้น) โดยทั่วไปข้อยกเว้นคือ "วิธี OOP" แต่น่าเสียดายที่ OOP API ดั้งเดิมของ PHP บางตัวใช้ข้อผิดพลาดแทนข้อยกเว้น :-(
DaveRandom

1
@DaveRandom E_NOTICE, E_WARNING ไม่ใช่ "ข้อผิดพลาด" ตามคำจำกัดความใช่หรือไม่ ฉันมักจะคิดว่ามันเป็น PHP 'ข้อความ' แสดงเพื่อแจ้งให้โปรแกรมเมอร์ทราบว่ามีบางอย่างผิดปกติกับโค้ดที่เขาเขียน
slhsen

2
@slhsen ปัญหานี้เป็นคำศัพท์ที่เส็งเคร็งจริงๆข้อความทุกรูปแบบเหล่านี้ผ่าน "ระบบจัดการข้อผิดพลาด" ใน PHP เหตุการณ์ทั้งหมดนี้เป็น "ข้อผิดพลาด" ตามความหมายแม้ว่าการแจ้งเตือน / คำเตือนตามความหมายจะไม่เหมือนกับ " error "ในบริบทนั้น โชคดีที่ PHP7 ที่กำลังจะมาถึงอย่างน้อยก็ได้ปูทางไปสู่การจัดเรียงความยุ่งเหยิงนี้โดยการเปลี่ยนสิ่งเหล่านี้ส่วนใหญ่ให้เป็นข้อยกเว้นที่จับได้ (โดยใช้Throwableอินเทอร์เฟซใหม่) ทำให้มีวิธีที่ชัดเจนและชัดเจนมากขึ้นในการแยกแยะและใช้งานจริงอย่างเหมาะสม ปัญหาและข้อความให้คำแนะนำ
DaveRandom

"การดำเนินการโปรแกรมจะดำเนินต่อไป" ฉันคิดว่าเปลี่ยนไปหรือ เนื่องจาก PHP ระบุว่า "เมื่อมีการยกเว้นรหัสตามคำสั่งจะไม่ถูกดำเนินการ" ( php.net/manual/en/language.exceptions.php )
Robert Sinclair

1
ผมคิดว่าสิ่ง OP มีความหมายมากขึ้นเกี่ยวกับความแตกต่างระหว่างลูกหลานของErrorVS Exceptionลูกหลานของ
XedinUnknown

55

ฉันมักset_error_handlerจะใช้ฟังก์ชันที่รับข้อผิดพลาดและโยนข้อยกเว้นเพื่อไม่ว่าจะเกิดอะไรขึ้นฉันจะมีข้อยกเว้นที่ต้องจัดการ ไม่@file_get_contentsเพียงแค่ลอง / จับที่ดีและเรียบร้อยอีกต่อไป

ในสถานการณ์การดีบักฉันยังมีตัวจัดการข้อยกเว้นที่แสดงผลเหมือนหน้า asp.net ฉันกำลังโพสต์สิ่งนี้บนท้องถนน แต่หากมีการร้องขอฉันจะโพสต์แหล่งข้อมูลตัวอย่างในภายหลัง

แก้ไข:

นอกจากนี้ตามสัญญาฉันได้ตัดและวางโค้ดบางส่วนเข้าด้วยกันเพื่อสร้างตัวอย่าง ฉันได้บันทึกข้อมูลด้านล่างนี้ลงในเวิร์กสเตชันของฉันแล้วคุณไม่สามารถดูผลลัพธ์ได้อีกต่อไปที่นี่ (เนื่องจากลิงก์เสีย)

<?php

define( 'DEBUG', true );

class ErrorOrWarningException extends Exception
{
    protected $_Context = null;
    public function getContext()
    {
        return $this->_Context;
    }
    public function setContext( $value )
    {
        $this->_Context = $value;
    }

    public function __construct( $code, $message, $file, $line, $context )
    {
        parent::__construct( $message, $code );

        $this->file = $file;
        $this->line = $line;
        $this->setContext( $context );
    }
}

/**
 * Inspire to write perfect code. everything is an exception, even minor warnings.
 **/
function error_to_exception( $code, $message, $file, $line, $context )
{
    throw new ErrorOrWarningException( $code, $message, $file, $line, $context );
}
set_error_handler( 'error_to_exception' );

function global_exception_handler( $ex )
{
    ob_start();
    dump_exception( $ex );
    $dump = ob_get_clean();
    // send email of dump to administrator?...

    // if we are in debug mode we are allowed to dump exceptions to the browser.
    if ( defined( 'DEBUG' ) && DEBUG == true )
    {
        echo $dump;
    }
    else // if we are in production we give our visitor a nice message without all the details.
    {
        echo file_get_contents( 'static/errors/fatalexception.html' );
    }
    exit;
}

function dump_exception( Exception $ex )
{
    $file = $ex->getFile();
    $line = $ex->getLine();

    if ( file_exists( $file ) )
    {
        $lines = file( $file );
    }

?><html>
    <head>
        <title><?= $ex->getMessage(); ?></title>
        <style type="text/css">
            body {
                width : 800px;
                margin : auto;
            }

            ul.code {
                border : inset 1px;
            }
            ul.code li {
                white-space: pre ;
                list-style-type : none;
                font-family : monospace;
            }
            ul.code li.line {
                color : red;
            }

            table.trace {
                width : 100%;
                border-collapse : collapse;
                border : solid 1px black;
            }
            table.thead tr {
                background : rgb(240,240,240);
            }
            table.trace tr.odd {
                background : white;
            }
            table.trace tr.even {
                background : rgb(250,250,250);
            }
            table.trace td {
                padding : 2px 4px 2px 4px;
            }
        </style>
    </head>
    <body>
        <h1>Uncaught <?= get_class( $ex ); ?></h1>
        <h2><?= $ex->getMessage(); ?></h2>
        <p>
            An uncaught <?= get_class( $ex ); ?> was thrown on line <?= $line; ?> of file <?= basename( $file ); ?> that prevented further execution of this request.
        </p>
        <h2>Where it happened:</h2>
        <? if ( isset($lines) ) : ?>
        <code><?= $file; ?></code>
        <ul class="code">
            <? for( $i = $line - 3; $i < $line + 3; $i ++ ) : ?>
                <? if ( $i > 0 && $i < count( $lines ) ) : ?>
                    <? if ( $i == $line-1 ) : ?>
                        <li class="line"><?= str_replace( "\n", "", $lines[$i] ); ?></li>
                    <? else : ?>
                        <li><?= str_replace( "\n", "", $lines[$i] ); ?></li>
                    <? endif; ?>
                <? endif; ?>
            <? endfor; ?>
        </ul>
        <? endif; ?>

        <? if ( is_array( $ex->getTrace() ) ) : ?>
        <h2>Stack trace:</h2>
            <table class="trace">
                <thead>
                    <tr>
                        <td>File</td>
                        <td>Line</td>
                        <td>Class</td>
                        <td>Function</td>
                        <td>Arguments</td>
                    </tr>
                </thead>
                <tbody>
                <? foreach ( $ex->getTrace() as $i => $trace ) : ?>
                    <tr class="<?= $i % 2 == 0 ? 'even' : 'odd'; ?>">
                        <td><?= isset($trace[ 'file' ]) ? basename($trace[ 'file' ]) : ''; ?></td>
                        <td><?= isset($trace[ 'line' ]) ? $trace[ 'line' ] : ''; ?></td>
                        <td><?= isset($trace[ 'class' ]) ? $trace[ 'class' ] : ''; ?></td>
                        <td><?= isset($trace[ 'function' ]) ? $trace[ 'function' ] : ''; ?></td>
                        <td>
                            <? if( isset($trace[ 'args' ]) ) : ?>
                                <? foreach ( $trace[ 'args' ] as $i => $arg ) : ?>
                                    <span title="<?= var_export( $arg, true ); ?>"><?= gettype( $arg ); ?></span>
                                    <?= $i < count( $trace['args'] ) -1 ? ',' : ''; ?> 
                                <? endforeach; ?>
                            <? else : ?>
                            NULL
                            <? endif; ?>
                        </td>
                    </tr>
                <? endforeach;?>
                </tbody>
            </table>
        <? else : ?>
            <pre><?= $ex->getTraceAsString(); ?></pre>
        <? endif; ?>
    </body>
</html><? // back in php
}
set_exception_handler( 'global_exception_handler' );

class X
{
    function __construct()
    {
        trigger_error( 'Whoops!', E_USER_NOTICE );      
    }
}

$x = new X();

throw new Exception( 'Execution will never get here' );

?>

นั่นจะเป็นประโยชน์ ทุกสิ่งที่จะทำให้เวลาที่ฉันจัดการกับ PHP ง่ายขึ้นจะช่วยได้ :-)
Jason Baker

รหัสที่ดีขอบคุณ ฉันไม่เข้าใจว่าคลาส X มาจากไหนและจุดประสงค์ของมันคืออะไร?
Alec

ทุกอย่างด้านล่าง "set_exception_handler ('global_exception_handler');" เป็นเพียงการสาธิตคุณไม่จำเป็นต้องใช้เพียงเพื่อแสดงสิ่งที่จะเกิดขึ้นในสถานการณ์ข้อผิดพลาดที่ไม่ใช่ข้อยกเว้นตามปกติ
Kris

PHP มาตรฐานกำหนด ErrorException โดยเฉพาะที่จะโยนจากตัวจัดการข้อผิดพลาดทั่วไป คุณอนุญาตให้ฉันแก้ไขและอัปเดตโพสต์ของคุณได้ไหม
Tiberiu-Ionuț Stan

@ Tiberiu-IonuțStan: แน่นอน แต่ตัวอย่างการทำงานจะไม่ตรงกัน นอกจากนี้ในปัจจุบันฉันอาจแนะนำให้ผู้คนไปที่github.com/theredhead/red.web/blob/master/src/lib/bootstrap.phpจากprivate-void.comแทน
Kris

21

คำตอบสมควรพูดถึงช้างในห้อง

ข้อผิดพลาดเป็นวิธีเก่าในการจัดการเงื่อนไขข้อผิดพลาดในขณะทำงาน โดยปกติรหัสจะโทรไปยังบางสิ่งเช่นset_error_handlerก่อนที่จะเรียกใช้รหัสบางอย่าง ตามธรรมเนียมการขัดจังหวะภาษาแอสเซมบลี นี่คือลักษณะของรหัสพื้นฐานบางส่วน

on error :divide_error

print 1/0
print "this won't print"

:divide_error

if errcode = X
   print "divide by zero error"

มันยากที่จะตรวจสอบให้แน่ใจว่าset_error_handlerจะถูกเรียกด้วยมูลค่าที่ถูกต้อง และที่แย่ไปกว่านั้นคือการโทรไปยังขั้นตอนแยกต่างหากที่จะเปลี่ยนตัวจัดการข้อผิดพลาด นอกจากนี้หลายครั้งการโทรถูกสลับกับการset_error_handlerโทรและตัวจัดการ เป็นเรื่องง่ายที่โค้ดจะหลุดจากการควบคุมได้อย่างรวดเร็ว การจัดการข้อยกเว้นเข้ามาช่วยโดยการจัดรูปแบบไวยากรณ์และความหมายของโค้ดที่ดีที่กำลังทำอยู่

try {
   print 1/0;
   print "this won't print";
} catch (DivideByZeroException $e) {
   print "divide by zero error";
}

ไม่มีฟังก์ชันแยกหรือความเสี่ยงในการเรียกตัวจัดการข้อผิดพลาดที่ไม่ถูกต้อง ตอนนี้รหัสรับประกันว่าจะอยู่ในที่เดียวกัน นอกจากนี้เรายังได้รับข้อความแสดงข้อผิดพลาดที่ดีขึ้น

PHP เคยมีเพียงการจัดการข้อผิดพลาดเมื่อภาษาอื่น ๆ ได้พัฒนาไปสู่รูปแบบการจัดการข้อยกเว้นที่ดีกว่าแล้ว ในที่สุดผู้ผลิต PHP ได้ดำเนินการจัดการข้อยกเว้น แต่มีแนวโน้มว่าจะรองรับโค้ดเก่าพวกเขายังคงจัดการข้อผิดพลาดและให้วิธีการจัดการข้อผิดพลาดดูเหมือนการจัดการข้อยกเว้น ยกเว้นว่าจะไม่มีการรับประกันว่าโค้ดบางตัวอาจไม่รีเซ็ตตัวจัดการข้อผิดพลาดซึ่งเป็นสิ่งที่การจัดการข้อยกเว้นถูกกำหนดไว้อย่างแม่นยำ

คำตอบสุดท้าย

ข้อผิดพลาดที่ถูกเข้ารหัสก่อนที่จะใช้การจัดการข้อยกเว้นยังคงมีข้อผิดพลาดอยู่ ข้อผิดพลาดใหม่น่าจะเป็นข้อยกเว้น แต่ไม่มีการออกแบบหรือตรรกะใดที่เป็นข้อผิดพลาดและเป็นข้อยกเว้น มันขึ้นอยู่กับสิ่งที่มีอยู่ในเวลาที่มีการเข้ารหัสและความชอบของโปรแกรมเมอร์ที่เข้ารหัส


3
นี่คือเหตุผลที่แท้จริงว่าทำไมข้อยกเว้นและข้อผิดพลาดจึงอยู่ร่วมกันได้ หากได้รับการออกแบบมาตั้งแต่ต้น php ควรมีเพียงตัวเดียว
Tomas Zubiri

1
เป็นคำตอบที่ดีที่สุดในความคิดของฉันเนื่องจากมีรายละเอียดและอธิบายได้มากที่สุด
Robert Kusznier

8

สิ่งหนึ่งที่ต้องเพิ่มที่นี่คือเกี่ยวกับการจัดการข้อยกเว้นและข้อผิดพลาด สำหรับวัตถุประสงค์ของนักพัฒนาแอปพลิเคชันทั้งข้อผิดพลาดและข้อยกเว้นคือ "สิ่งที่ไม่ดี" ที่คุณต้องการบันทึกเพื่อเรียนรู้เกี่ยวกับปัญหาที่แอปพลิเคชันของคุณมี - เพื่อให้ลูกค้าของคุณได้รับประสบการณ์ที่ดีขึ้นในระยะยาว

ดังนั้นจึงควรเขียนตัวจัดการข้อผิดพลาดที่ทำสิ่งเดียวกับสิ่งที่คุณทำสำหรับข้อยกเว้น


ขอบคุณที่ให้ลิงค์!
Mike Moore

@ Alex Weinstein: ลิงก์เสีย
Marco Demaio

7

ตามที่ระบุไว้ในคำตอบอื่น ๆ การตั้งค่าตัวจัดการข้อผิดพลาดไปยังตัวโยนข้อยกเว้นเป็นวิธีที่ดีที่สุดในการจัดการข้อผิดพลาดใน PHP ฉันใช้การตั้งค่าที่ง่ายกว่าเล็กน้อย:

set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
        if (error_reporting()) {
                throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
        }
});

โปรดสังเกตerror_reporting()เช็คเพื่อเก็บไว้@ผู้ปฏิบัติงานทำงานต่อไป นอกจากนี้ไม่จำเป็นต้องกำหนดข้อยกเว้นที่กำหนดเอง PHP มีคลาสที่ดีสำหรับสิ่งนั้น

ประโยชน์อย่างมากของการโยนข้อยกเว้นคือข้อยกเว้นมีการติดตามสแต็กที่เกี่ยวข้องดังนั้นจึงง่ายต่อการค้นหาว่าปัญหาอยู่ที่ไหน


5

Re: "แต่ข้อผิดพลาดและข้อยกเว้นต่างกันอย่างไร"

มีคำตอบที่ดีมากมายเกี่ยวกับความแตกต่างที่นี่ ฉันจะเพิ่มในสิ่งที่ยังไม่ได้พูดถึงนั่นคือประสิทธิภาพ โดยเฉพาะอย่างยิ่งนี่คือความแตกต่างระหว่างข้อยกเว้นการขว้างปา / การจัดการและการจัดการรหัสส่งคืน (ไม่ว่าจะสำเร็จหรือผิดพลาด) โดยปกติใน php หมายถึงการส่งคืนfalseหรือnullแต่สามารถให้รายละเอียดได้มากขึ้นเช่นเมื่ออัพโหลดไฟล์: http://php.net/manual/en/features.file-upload.errors.phpคุณสามารถส่งคืนอ็อบเจ็กต์ Exception !

ฉันได้แสดงประสิทธิภาพบางอย่างในภาษา / ระบบต่างๆ โดยทั่วไปการจัดการข้อยกเว้นจะช้ากว่าการตรวจสอบรหัสส่งคืนข้อผิดพลาดประมาณ 10,000 เท่า

ดังนั้นหากเป็นไปได้อย่างแน่นอนคุณต้องดำเนินการให้เสร็จสิ้นก่อนที่มันจะเริ่ม - คุณก็โชคไม่ดีเพราะไม่มีการเดินทางข้ามเวลา หากไม่มีการเดินทางข้ามเวลารหัสส่งคืนเป็นตัวเลือกที่เร็วที่สุด

แก้ไข:

PHP ได้รับการปรับให้เหมาะสมอย่างมากสำหรับการจัดการข้อยกเว้น การทดสอบในโลกแห่งความเป็นจริงแสดงให้เห็นว่าการโยนข้อยกเว้นช้ากว่าการส่งคืนค่าเพียง 2-10 เท่า


3
แน่นอน แต่จำนวนรอบที่สูญเสียไปจากการขว้างข้อยกเว้นนั้นมากกว่าที่สร้างขึ้นจากพลังพิเศษในการอธิบายที่คุณได้รับจากข้อยกเว้น คุณสามารถโยนข้อยกเว้นบางประเภทหรือเพิ่มข้อมูลในข้อยกเว้นเพื่อให้มีรหัสข้อผิดพลาด ฉันสงสัยอย่างจริงจังเกี่ยวกับการอ้างสิทธิ์ 10,000 * ของคุณเช่นกัน แม้ว่าคุณจะพูดถูกเกี่ยวกับความแตกต่างของเวลา แต่เวลาที่ใช้ในการส่งคืน & ถ้าเทียบกับการดำเนินการใหม่การโยนการจับในสถานการณ์โลกแห่งความจริงนั้นมีแนวโน้มที่จะน้อยมากเมื่อเทียบกับโค้ดที่เรียกใช้งานซึ่งเป็นการเพิ่มประสิทธิภาพก่อนกำหนดอย่างแน่นอน ยกเว้นข้อยกเว้นพวกเขาดีกว่าที่จะจัดการกับ 90% ของเวลา
gnarf

1
1. 10,000x ถูกต้อง - มีความแปรปรวนบางอย่างตามตัวเลือกภาษาและคอมไพเลอร์ 2. คุณไม่จำเป็นต้องคืนค่า null / false คุณสามารถส่งคืนหมายเลข - ได้สูงสุด MAX_ULONG รหัสส่งคืนที่นั่น คุณสามารถส่งคืนสตริงความล้มเหลวและตรวจสอบสตริงความสำเร็จหรือ int หรือ null ได้ 3. ในสถานการณ์จริงทุกรอบนาฬิกามีค่า Facebook มีผู้ใช้งาน 552 ล้านคนต่อวัน สมมติว่ามีข้อยกเว้นเพียง 2x และการตรวจสอบ user / pass ใช้เวลา. 001 ซึ่งหมายถึงการประหยัดเวลาในการประมวลผล 153 ชั่วโมงทุกวัน ที่ 10,000x ประหยัดเวลา 175 ปี เพียงเพื่อตรวจสอบความพยายามในการเข้าสู่ระบบ - ในแต่ละวัน
evan

@evan: FYI ที่นี่พวกเขาทดสอบโค้ดด้วยข้อยกเว้นและดูเหมือนจะไม่ช้าลง: stackoverflow.com/a/445094/260080
Marco Demaio

@MarcoDemaio คำถามนั้นครอบคลุมเฉพาะบล็อก try / catch โดยไม่มีข้อยกเว้น การทดสอบที่ดีกว่าคือการส่งคืนค่าใน noexcept () และโยนข้อยกเว้นใน except () นอกจากนี้ควรกระจายไปตามฟังก์ชันต่างๆ stackoverflow.com/a/104375/505172ระบุว่าจริงๆแล้วความแตกต่างของ PHP อยู่ที่ 54x ฉันทำการทดสอบของตัวเองโดยดูตามเวลาจริงและดูเหมือนว่าจะช้าลง 2-10 เท่า นี่เป็นวิธีที่ดีเกินคาด
evan

@evan: ตอนนั้นฉันจะไม่กังวลฉันใช้ข้อยกเว้นเพื่อติดตามข้อผิดพลาดที่ไม่คาดคิด / ไม่สามารถกู้คืนได้เท่านั้นดังนั้นแม้ว่ามันจะช้ากว่า 100 เท่าฉันก็ไม่สนใจ ความกังวลของฉันคือการทำให้โค้ดช้าลงโดยเพียงแค่เพิ่มบล็อก try / catch
Marco Demaio

4

ฉันคิดว่า anwser ที่คุณกำลังมองหานั่นคือ;

ข้อผิดพลาดเป็นสิ่งมาตรฐานที่คุณคุ้นเคยเช่นการสะท้อนตัวแปร $ ที่ไม่มีอยู่จริง
ข้อยกเว้นมีเฉพาะตั้งแต่ PHP 5 เป็นต้นไปและเกิดขึ้นเมื่อจัดการกับวัตถุ

เพื่อให้ง่าย:

ข้อยกเว้นคือข้อผิดพลาดที่คุณได้รับเมื่อจัดการกับวัตถุ คำสั่ง try / catch ช่วยให้คุณสามารถทำบางสิ่งเกี่ยวกับพวกเขาได้และใช้เหมือนกับคำสั่ง if / else ลองทำสิ่งนี้หากปัญหาไม่สำคัญให้ทำเช่นนี้

หากคุณไม่ "จับ" ข้อยกเว้นก็จะกลายเป็นข้อผิดพลาดมาตรฐาน

ข้อผิดพลาดคือข้อผิดพลาดพื้นฐานของ php ซึ่งมักจะหยุดสคริปต์ของคุณ

Try / catch มักใช้สำหรับสร้างการเชื่อมต่อฐานข้อมูลเช่น PDO ซึ่งเป็นเรื่องปกติหากคุณต้องการเปลี่ยนเส้นทางสคริปต์หรือทำอย่างอื่นหากการเชื่อมต่อไม่ทำงาน แต่ถ้าคุณแค่ต้องการแสดงข้อความแสดงข้อผิดพลาดและหยุดสคริปต์คุณก็ไม่จำเป็นต้องใช้ข้อยกเว้นที่ไม่ถูกตรวจจับจะกลายเป็นข้อผิดพลาดร้ายแรง หรือคุณสามารถใช้การตั้งค่าการจัดการข้อผิดพลาดทั่วทั้งไซต์ได้เช่นกัน

หวังว่าจะช่วยได้


3
ข้อยกเว้นสามารถใช้กับโค้ดขั้นตอนใน PHP ได้เช่นกัน
Tiberiu-Ionuț Stan

2

ใน PHP 7.1 และใหม่กว่าบล็อกcatchอาจระบุข้อยกเว้นหลายข้อโดยใช้อักขระไปป์ (|) สิ่งนี้มีประโยชน์เมื่อมีการจัดการข้อยกเว้นที่แตกต่างจากลำดับชั้นของคลาสที่เหมือนกัน

try {
  // do something
} catch (Error | Exception $e) {
  echo $e->getMessage();
}

1

ข้อยกเว้นถูกโยนรหัสโดยเจตนาโดยใช้การโยนข้อผิดพลาด ... ไม่มาก

ข้อผิดพลาดเกิดจากสิ่งที่ไม่ได้รับการจัดการโดยทั่วไป (ข้อผิดพลาด IO ข้อผิดพลาด TCP / IP ข้อผิดพลาดอ้างอิง null)


1
สิ่งนี้ไม่จำเป็นต้องเป็นความจริง ในหลาย ๆ กรณีมีการตรวจสอบข้อผิดพลาดและรหัสส่งคืนจะถูกส่งกลับโดยเจตนาตามความเหมาะสม ในความเป็นจริงนั่นเป็นกรณีสำหรับทุกภาษาที่ไม่ใช่เชิงวัตถุ ข้อยกเว้นเป็นเพียงข้อยกเว้นของกฎ ในทั้งสองกรณีมีบางอย่างผิดพลาดสังเกตเห็นและควรได้รับการจัดการ การอัปโหลดไฟล์ PHP เป็นตัวอย่างหนึ่งของการจัดการข้อผิดพลาดโดยเจตนาผ่านรหัสส่งคืน - php.net/manual/en/features.file-upload.errors.php
evan

1

ฉันตั้งใจจะให้คุณพูดคุยเกี่ยวกับการควบคุมข้อผิดพลาดที่ผิดปกติที่สุด

ฉันสร้างตัวจัดการข้อผิดพลาดที่ดีมากในภาษาเมื่อหลายปีก่อนและแม้ว่าบางชื่อจะเปลี่ยนไป แต่หลักการของการประมวลผลข้อผิดพลาดก็เหมือนกันในปัจจุบัน ฉันมีระบบปฏิบัติการมัลติทาสกิ้งที่สร้างขึ้นเองและต้องสามารถกู้คืนจากข้อผิดพลาดของข้อมูลในทุกระดับโดยไม่มีหน่วยความจำรั่วไหลการเติบโตของสแต็กหรือล่ม ดังนั้นสิ่งที่ตามมาคือความเข้าใจของฉันว่าข้อผิดพลาดและข้อยกเว้นต้องดำเนินการอย่างไรและแตกต่างกันอย่างไร ฉันจะบอกว่าฉันไม่มีความเข้าใจว่าภายในของ try catch ทำงานอย่างไรดังนั้นฉันจึงคาดเดาถึงมาตรการบางอย่าง

สิ่งแรกที่เกิดขึ้นภายใต้ฝาครอบสำหรับการประมวลผลข้อผิดพลาดคือการกระโดดจากสถานะโปรแกรมหนึ่งไปยังอีกสถานะหนึ่ง เป็นอย่างไรบ้าง? ฉันจะไปที่นั่น

ในอดีตข้อผิดพลาดเก่ากว่าและง่ายกว่าและข้อยกเว้นใหม่กว่าและซับซ้อนและมีความสามารถมากกว่าเล็กน้อย ข้อผิดพลาดทำงานได้ดีจนกว่าคุณจะต้องแจ้งให้ทราบซึ่งเท่ากับการส่งปัญหาที่ยากให้กับหัวหน้างานของคุณ

ข้อผิดพลาดอาจเป็นตัวเลขเช่นหมายเลขข้อผิดพลาดและบางครั้งอาจมีสตริงที่เกี่ยวข้องอย่างน้อยหนึ่งสตริง ตัวอย่างเช่นหากเกิดข้อผิดพลาดในการอ่านไฟล์คุณอาจสามารถรายงานได้ว่ามันคืออะไรและอาจล้มเหลวอย่างสง่างาม (เฮย์มันเป็นขั้นตอนที่เพิ่มขึ้นจากการพังทลายเหมือนในสมัยก่อน)

สิ่งที่ไม่ได้กล่าวถึงบ่อยครั้งเกี่ยวกับข้อยกเว้นคือข้อยกเว้นคือวัตถุที่อยู่บนสแตกข้อยกเว้นพิเศษ มันเหมือนกับการส่งคืนสแต็กสำหรับโฟลว์โปรแกรม แต่มันมีสถานะส่งคืนสำหรับการลองผิดพลาดและการจับ (ฉันเคยเรียกพวกเขาว่า ePush และ ePop และ? Abort เป็นการโยนแบบมีเงื่อนไขซึ่งจะทำให้ ePop และฟื้นตัวไปสู่ระดับนั้นในขณะที่ Abort เป็นตายเต็มหรือออก)

ที่ด้านล่างของสแต็กคือข้อมูลเกี่ยวกับผู้เรียกเริ่มต้นซึ่งเป็นออบเจ็กต์ที่รู้เกี่ยวกับสถานะเมื่อเริ่มการทดลองภายนอกซึ่งมักจะเป็นตอนที่โปรแกรมของคุณเริ่มทำงาน ด้านบนหรือชั้นถัดไปบนสแต็กโดยที่เป็นเด็กและเป็นผู้ปกครองเป็นวัตถุยกเว้นของบล็อก try / catch ชั้นในถัดไป

ถ้าคุณลองใส่ลองคุณกำลังซ้อนลองด้านในที่ด้านบนของลองด้านนอก เมื่อเกิดข้อผิดพลาดในการลองด้านในและตัวจับด้านในไม่สามารถจัดการได้หรือข้อผิดพลาดถูกโยนไปยังการลองด้านนอกจากนั้นการควบคุมจะถูกส่งไปยังบล็อกการจับด้านนอก (อ็อบเจ็กต์) เพื่อดูว่าสามารถจัดการกับข้อผิดพลาดได้หรือไม่เช่น หัวหน้างานของคุณ

ดังนั้นสิ่งที่สแต็กข้อผิดพลาดนี้ทำจริงๆคือสามารถทำเครื่องหมายและเรียกคืนผังโปรแกรมและสถานะของระบบได้กล่าวอีกนัยหนึ่งก็คือจะช่วยให้โปรแกรมไม่ขัดข้องในการส่งคืนสแต็กและทำให้สิ่งอื่น ๆ (ข้อมูล) ยุ่งเหยิงเมื่อมีสิ่งผิดปกติเกิดขึ้น ดังนั้นจึงยังช่วยประหยัดสถานะของทรัพยากรอื่น ๆ เช่นพูลการจัดสรรหน่วยความจำและสามารถล้างข้อมูลได้เมื่อจับเสร็จ โดยทั่วไปสิ่งนี้อาจเป็นเรื่องที่ซับซ้อนมากและนั่นคือสาเหตุที่การจัดการข้อยกเว้นมักจะช้า โดยทั่วไปค่อนข้างจำเป็นต้องเข้าไปในบล็อกข้อยกเว้นเหล่านี้

ดังนั้นการเรียงลำดับของบล็อก try / catch จะตั้งค่าสถานะให้สามารถกลับไปเป็นได้หากสิ่งอื่น ๆ ทั้งหมดยุ่งเหยิง มันเหมือนพ่อแม่ เมื่อชีวิตของเรายุ่งเหยิงเราสามารถกลับไปนั่งตักพ่อแม่ได้และพวกเขาจะทำให้ทุกอย่างกลับมาเหมือนเดิม

หวังว่าฉันจะไม่ทำให้คุณผิดหวัง


1

คุณสามารถเพิ่มความคิดเห็นนี้

function doSomething()
{
   /** @noinspection PhpUnhandledExceptionInspection */
   throw new Exception();
}

0

เมื่อกำหนด set_error_handler () แล้วตัวจัดการข้อผิดพลาดจะคล้ายกับ Exception's ดูรหัสด้านล่าง:

 <?php
 function handleErrors( $e_code ) {
   echo "error code: " . $e_code . "<br>";
 }

 set_error_handler( "handleErrors" ); 

 trigger_error( "trigger a fatal error", E_USER_ERROR);
 echo "after error."; //it would run if set_error_handler is defined, otherwise, it wouldn't show
?>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.