tag_strip - PHP:例外與錯誤?




strip_tags用法 (7)

thrown - 它們有意被捕獲。 錯誤通常是不可恢復的。 比方說,例如 - 你有一塊代碼將插入一行到數據庫中。 有可能這個調用失敗(重複的ID) - 你會希望有一個“錯誤”,在這種情況下是“異常”。 當你插入這些行時,你可以做這樣的事情

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

echo "Some more stuff";

程序執行將繼續 - 因為你“抓住”了異常。 除非被捕獲,否則異常將被視為錯誤。 它將允許您在失敗之後繼續執行程序。

也許我在PHP手冊的某處丟失了它,但是錯誤和異常究竟有什麼區別? 我可以看到的唯一區別是錯誤和異常處理方式不同。 但是什麼導致了異常,並導致錯誤?


回复:“但是錯誤和異常之間究竟有什麼區別?”

關於這裡的差異有很多很好的答案。 我只會添加一些尚未討論的內容 - 性能。 具體而言,這是為了區別拋出/處理異常和處理返回碼(成功或某種錯誤)。 通常,在PHP中,這意味著返回falsenull ,但它們可以更詳細,如文件上傳: http://php.net/manual/en/features.file-upload.errors.php : http://php.net/manual/en/features.file-upload.errors.php你甚至可以返回一個異常對象!

我用不同的語言/系統做過幾次性能測試。 一般來說,異常處理比檢查錯誤返回碼慢大約10,000倍。

所以,如果它絕對的話,肯定需要在它開始之前完成執行 - 嗯,因為時間旅行不存在,所以你運氣不好。 沒有時間旅行,返回代碼是最快的選擇。

編輯:

PHP針對異常處理進行了高度優化。 真實世界的測試表明,拋出異常比返回值慢2-10倍。


一旦定義了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
?>

我打算給你一個關於錯誤控制的最不尋常的討論。

幾年前,我在一種語言中構建了一個非常好的錯誤處理程序,雖然其中一些名稱已更改,但錯誤處理的原理今天是相同的。 我有一個定制的多任務操作系統,並且必須能夠從各個級別的數據錯誤中恢復,沒有內存洩漏,堆棧增長或崩潰。 所以接下來是我對錯誤和例外必須如何運作以及它們有何不同的理解。 我只是說我不了解try catch的內部是如何工作的,所以我會猜測一些措施。

發生錯誤處理的第一件事是從一種程序狀態跳轉到另一種程序狀態。 這是如何完成的? 我會做到這一點。

從歷史上看,錯誤年齡更大,更簡單,例外情況更新,更複雜,更有能力。 錯誤工作正常,直到你需要將它們冒泡為止,這相當於向你的主管處理了一個難題。

錯誤可以是數字,如錯誤號碼,有時也可以是一個或多個關聯的字符串。 例如,如果發生文件讀取錯誤,您可能能夠報告它是什麼,並可能正常失敗。 (乾草,就像過去一樣,它剛剛崩潰。)

關於異常的常見情況是,異常是在特殊異常堆棧上分層的對象。 它就像程序流程的返回堆棧,但它僅保留一個返回狀態,僅用於錯誤捕獲和捕獲。 (我曾經稱他們為ePush和ePop,並且Abort是一個有條件的投擲,它將ePop並恢復到該水平,而Abort則完全死亡或退出。)

在堆棧的底部是關於初始調用者的信息,這是知道啟動外部嘗試時的狀態的對象,這通常是程序啟動時的狀態。 在堆棧頂部,或者堆棧中的下一層,作為子節點,並且作為父節點,是下一個內部try / catch塊的異常對象。

如果你嘗試一下嘗試,你會在外部嘗試的頂部堆疊內部嘗試。 當內部嘗試發生錯誤並且內部catch不能處理它或錯誤被引發到外部try時,則控制被傳遞給外部catch塊(對象)以查看它是否可以處理錯誤,即你的主管。

所以這個錯誤堆棧真正做的是能夠標記和恢復程序流和系統狀態,換句話說,它允許程序在事情出錯時不會崩潰返回堆棧並將其他事物(數據)弄糟。 因此,它還可以節省內存分配池等任何其他資源的狀態,因此可以在捕獲完成時清除它們。 一般來說,這可能是一件非常複雜的事情,這就是為什麼異常處理通常很慢的原因。 通常情況下需要進入這些異常塊。

所以try / catch塊設置一個狀態,如果其他所有事情都搞砸了,就可以返回到狀態。 這就像一個家長。 當我們的生活變得混亂起來時,我們可以回到父母的身邊,他們會一切順利。

希望我沒有讓你失望。


我通常將set_error_handler為一個接受錯誤並引發異常的函數,以便發生任何事情時我只會處理異常。 沒有更多的@file_get_contents只是很好,整齊的try / catch。

在調試的情況下,我也有一個異常處理程序,輸出一個類似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' );

?>

正如其他答案中所述,將錯誤處理程序設置為異常thrower是處理PHP中錯誤的最佳方式。 我使用更簡單的設置:

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

請注意error_reporting()檢查以保持@操作符正常工作。 此外,沒有必要定義自定義異常,PHP有一個很好的類。

拋出異常的好處在於異常具有與它們相關的堆棧跟踪,因此很容易找到問題所在。


通過代碼使用throw,錯誤......故意拋出異常......並非如此。

錯誤是由於某些通常不被處理的結果而產生的。 (IO錯誤,TCP / IP錯誤,空引用錯誤)





error-handling