ホームページ  >  記事  >  バックエンド開発  >  PHP プログラマーが遭遇するエラーと例外 パート 2: 例外

PHP プログラマーが遭遇するエラーと例外 パート 2: 例外

不言
不言オリジナル
2018-04-14 15:02:111537ブラウズ

この記事では、PHP プログラマーが遭遇したエラーと例外を紹介します。必要な友人は参照してください

前の記事: 当時の PHP で遭遇したエラーと例外: 前の記事のエラー

1. PHP における例外の導入と使用

1.1 例外実行プロセス

try
{
    // 需要进行异常处理的代码段;
    throw 语句抛出异常;
}catch( Exception $e )
{
    ... 
}
catch( Exception $e )
{
    // 处理异常
}
contine.....

キャッチされない例外は致命的なエラーを報告します: Fatal error:UncaughtException.... Fatal error:Uncaught exception.....

1.2 PHP异常特点

  1. PHP不会主动捕获异常,需要程序中主动抛出 (throw)异常,才能捕获。

  2. throw会自动向上抛出

  3. throw之后的语句不会执行

  4. try后必须有catch,否则解析错误Parse error

try{
    $num1=3;
    $num2=0;
    if($num2==0){
        throw new Exception('0不能当作除数');
        echo 'this is a test';//看不到
    }else{
        $res=$num1/$num2;
    }
}catch(Exception $e){
    echo $e->getMessage();
}

1.3 PHP内置异常

Php不像java提供了很多异常类,所以很多异常都会当成错误。要想变错误为抛出异常,需要手动throw异常对象

PHP内置异常如:PDOExceptionSplFileObject 可以自动抛出异常,后面的代码可以继续执行。

PHP プログラマーが遭遇するエラーと例外 パート 2: 例外

PHP プログラマーが遭遇するエラーと例外 パート 2: 例外

1.4 错误和异常的区别

1.4.1 异常处理

     当异常被抛出,throw后的代码不会继续执行PHP 会尝试查找匹配的 catch 代码块。如果异常没有被捕获,而且又没用使用set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 “Uncaught Exception” (未捕获异常)的错误消息。

1.4.2 异常的基本语法结构

     try - 需要进行异常处理的代码应该放入try代码块内,以便捕获潜在的异常。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常
     throw - 这里规定如何触发异常。每一个trythrow 必须对应至少一个 catch。使用多个catch代码块可以捕获不同种类的异常。
     catch - catch代码块会捕获异常,并创建一个包含异常信息的对象

1.4.3 重新抛出异常

     有时,当异常被抛出时,也许希望以不同于标准的方式对它进行处理。可以在一个 catch 代码块中再次抛出异常。注意再次抛出异常需要try{}catch{},不能直接在catch代码块中throw异常

     脚本应该对用户隐藏系统错误。对程序员来说,系统错误也许很重要,但是用户对它们并不感兴趣。为了让用户更容易使用,您可以再次抛出带有对用户比较友好的消息的异常。
     简而言之:如果抛出了异常,就必须捕获它。

1.4.4 错误与异常的区别

异常:程序运行与预期不太一致

错误:触发的是本身的错误

  • 当遇到错误的时候,触发的是本身的错误,不会自动的抛出异常。异常可以通过throw语句抛出异常,通过catch捕获异常,如果未捕获会产生致命错误。

  • 错误在发生的时候或触发的时候,必须马上对脚本进行处理。异常可以一一向上传递,直到被捕获,再处理。

  • 错误触发不具有相关代码或名称。异常可以自定义处理错误信息(异常的好处就体现出来了),是通过代码来抛出,捕获然后处理

二、自定义异常类

2.1 自定义异常类

  1. 自定义异常类只能重写构造函数和toString两个函数

  2. 自定义异常类可以增加自己的方法

  3. 多个catch 时,一般Exception1.2 PHP 例外機能

    1. PHP
    2. は積極的に例外をキャッチしません
    。プログラム内で積極的にスローする必要があります ( throw ) 例外をキャッチできます。

  4. throw は自動的に上向きにスローします

    🎜
  5. 🎜throw の後のステートメントは実行されません🎜🎜
  6. 🎜try の後には <code>catch が続く必要があります。そうでない場合、解析エラー Parse error🎜🎜🎜
    /**
     * 自定义异常类
     * Class MyException
     */
    class MyException extends Exception
    {
        public function __construct($message = "", $code = 0, Throwable $previous = null)
        {
            parent::__construct($message, $code, $previous);
        }
        public function __toString()
        {
            $message = "<h2>出现异常了,信息如下</h2>";
            $message .= "<p>".__CLASS__."[{$this->code}]:{$this->message}</p>";
            return $message;
        }
        public function test()
        {
            echo &#39;this is a test&#39;;
        }
        public function stop()
        {
            exit(&#39;script end...&#39;);
        }
        //自定义其它方法
    }
    
    try{
        echo &#39;出现异常啦&#39;;
        throw new MyException(&#39;测试自定义异常&#39;);
    }catch (MyException $exception){
        echo $exception->getMessage();
        echo $exception;
    }
    //会继续执行
    echo &#39;continue.........&#39;;
    🎜1.3 PHP 組み込み例外🎜🎜Phpjava とは異なり、多くの例外クラスが提供されるため、多くの例外がエラーとみなされます。エラーを例外に変更するには、例外オブジェクト 🎜🎜🎜PHP 組み込み例外 (🎜PDOExceptionSplFileObject) を手動で <code>throw する必要があります。 code> 🎜 は自動的に例外をスローし、次のコードは実行を続行できます。 🎜🎜🎜PHP プログラマーが遭遇するエラーと例外 パート 2: 例外 🎜🎜PHP プログラマーが遭遇するエラーと例外 パート 2: 例外🎜 🎜1.4 エラーと例外の違い🎜🎜1.4.1 例外処理🎜🎜 例外がスローされると、🎜throw🎜🎜 以降のコードは実行を継続しません🎜, PHP code> は、一致する <code>catch ブロックの検索を試みます。例外がキャッチされず、対応する処理に set_Exception_handler() を使用する必要がない場合、重大なエラー (🎜致命的エラー🎜) が発生し、「Uncaught Exception」が発生します。 " (キャッチされない例外) エラー メッセージ。 🎜🎜1.4.2 例外の基本構文構造🎜🎜 🎜try🎜 - 例外を処理する必要があるコードは、潜在的な例外をキャッチするために try コード ブロック内に配置する必要があります。例外がトリガーされない場合、コードは通常どおり実行を続行します。ただし、例外がトリガーされると、例外がスローされます。
    throw - 例外をトリガーする方法を指定します。それぞれの 🎜try🎜 または 🎜throw🎜 🎜must🎜 は、少なくとも 1 つの 🎜catch🎜 に対応しています。複数の 🎜catch🎜 ブロックを使用して、さまざまな種類の例外をキャッチできます。
    catch - 🎜catch🎜 コード ブロックは例外をキャッチし、例外情報を含むオブジェクトを作成します🎜🎜1.4.3 例外を再スローします🎜🎜 例外がスローされると、おそらく、標準とは異なる扱いをしたい。例外は 🎜catch🎜 ブロックで再度スローできます。 例外を再度スローするには try{}catch{} が必要であり、例外を catch コード ブロックで直接スローすることはできないことに注意してください。 🎜🎜 スクリプトはシステムエラーをユーザーから隠す必要があります。システム エラーはプログラマにとって重要かもしれませんが、ユーザーはそれらに興味がありません。ユーザーにとって使いやすいように、わかりやすいメッセージを付けて例外を再度スローできます。
    つまり、例外がスローされた場合は、それをキャッチする必要があります。 🎜🎜1.4.4 エラーと例外の違い🎜
    例外: プログラムが期待と矛盾して実行される🎜エラー: エラーはそれ自体によって引き起こされる🎜
    • 🎜エラーが発生した場合、エラー自体がトリガーされ、例外は自動的にスローされません。例外は 🎜throw🎜 ステートメントによってスローされ、🎜catch🎜 によってキャッチされます。キャッチされない場合は、致命的なエラーが発生します。 🎜🎜
    • 🎜エラーが発生した場合、またはトリガーされた場合、スクリプトは直ちに処理される必要があります。例外は、捕捉されて処理されるまで 1 つずつ渡すことができます。 🎜🎜
    • 🎜エラー トリガーには、関連付けられたコードまたは名前がありません。例外は、エラー メッセージを処理するようにカスタマイズできます (例外の利点が反映されます)。例外はコードを通じてスローされ、キャプチャされてから処理されます🎜🎜
    🎜 2. カスタム例外クラス🎜🎜2.1 カスタム例外クラス🎜
    1. 🎜カスタム例外クラス🎜は、コンストラクターと toString の 2 つの関数のみ🎜🎜
    2. 🎜カスタム例外クラスを追加できます 独自のメソッド 🎜🎜
    3. 🎜catch が複数ある場合、通常、Exception 基本クラスが最後に配置されます。🎜 基本クラスはカスタム例外クラスで定義されたメソッドを呼び出すことができます🎜。 🎜 🎜🎜
      try{
          throw new MyException(&#39;测试自定义异常&#39;);
      }catch (Exception $exception){
          echo $exception->getMessage();
          $exception->test();
      } catch (MyException $exception){
          echo $exception->getMessage();
      }
      //将错误用错误抑制符吸收,然后抛出异常
      If(@!fwrite($filename,$data)) throw new exception(自定义异常)
      
      PHP_EOL #换行符
      🎜2.2 ヒント🎜
      Exception_Observer.php
      
      /**
       * 给观察者定义规范
       *
       * Interface Exception_Observer
       */
      interface Exception_Observer
      {
          public function update(Observable_Exception $e);
      }
      🎜 エラーログ情報を記録する方法:🎜

           (1) :file_put_contents(LOG_PATH.'error.log';, '错误信息'.' '.date('Y-m-d H:i:s')."\r\n", FILE_APPEND);

           (2) :error_log('错误信息'.' '.date('Y-m-d H:i:s')."\r\n",3,LOG_PATH.'error.log');

      2.3 使用观察者模式处理异常信息

      Exception_Observer.php
      
      /**
       * 给观察者定义规范
       *
       * Interface Exception_Observer
       */
      interface Exception_Observer
      {
          public function update(Observable_Exception $e);
      }
      Observable_Exception.php
      
      /**
       * 定义观察者
       * Class Observable_Exception
       */
      class Observable_Exception extends Exception
      {
          //保存观察者信息
          public static $_observers = array();
          public static function attach(Exception_Observer $observer)
          {
              self::$_observers[] = $observer;
          }
          public function __construct($message = "", $code = 0, Throwable $previous = null)
          {
              parent::__construct($message, $code, $previous);
              $this->notify();
          }
          public function notify()
          {
              foreach (self::$_observers as $observer) {
                  $observer->update($this);
              }
          }
      }
      Logging_Exception_Observer.php
      
      /**
       * 记录错误日志
       * Class Logging_Exception_Observer
       */
      class Logging_Exception_Observer implements Exception_Observer
      {
          protected $_filename = __DIR__.&#39;/error_observer.log&#39;;
          public function __construct($filename = null)
          {
              if ($filename!==null && is_string($filename)){
                  $this->_filename = $filename;
              }
          }
      
          public function update(Observable_Exception $e)
          {
              $message = "时间:".date(&#39;Y:m:d H:i:s&#39;,time()).PHP_EOL;
              $message.= "信息:".$e->getMessage().PHP_EOL;
              $message.= "追踪信息:".$e->getTraceAsString().PHP_EOL;
              $message.= "文件:".$e->getFile().PHP_EOL;
              $message.= "行号:".$e->getLine().PHP_EOL;
              error_log($message,3,$this->_filename);//写到日志中
          }
      }
      test.php
      
      /**
       *测试
       */
      header(&#39;content-type:text/html;charset=utf-8&#39;);
      require_once &#39;Exception_Observer.php&#39;;
      require_once &#39;Logging_Exception_Observer.php&#39;;
      require_once &#39;Observable_Exception.php&#39;;
      
      Observable_Exception::attach(new Logging_Exception_Observer());
      
      class MyException extends Observable_Exception{
          public function test()
          {
              echo &#39;this is a test&#39;;
          }
      }
      
      try{
          throw new MyException(&#39;出现了异常!&#39;);
      }catch (MyException $exception){
          echo $exception->getMessage();
      }

      三、自定义异常处理器

      3.1 如何自定义异常处理器

      3.1.1 自定义异常处理器

      1. 类似set_error_handler接管系统的错误处理函数,set_exception_handler接管所有没有被catch的异常

      2. restore_exception_handlerrestore_error_handler一样,本质上应该说从异常/错误处理函数栈中弹出一个。比如有一个异常处理函数,弹出一个的话,就没有异常处理函数,如果有异常没有捕获,会交由错误处理函数,如没有错误处理函数,异常最终会有系统错误处理函数处理。如果设置了2个异常处理函数,弹出一个,会交由下面一个异常处理函数处理。

      /**
       * 自定义异常函数处理器
       */
      header(&#39;content-type:text/html;charset=utf-8&#39;);
      function exceptionHandler_1($e)
      {
          echo &#39;自定义异常处理器1<br/>函数名:&#39;.__FUNCTION__.PHP_EOL;
          echo &#39;异常信息:&#39;.$e->getMessage();
      }
      function exceptionHandler_2($e)
      {
          echo &#39;自定义异常处理器2<br/>函数名:&#39;.__FUNCTION__.PHP_EOL;
          echo &#39;异常信息:&#39;.$e->getMessage();
      }
      
      set_exception_handler(&#39;exceptionHandler_1&#39;);
      //set_exception_handler(&#39;exceptionHandler_2&#39;);
      //恢复到上一次定义过的异常处理函数,即exceptionHandler_1
      //restore_exception_handler();
      //致命错误信息
      //restore_exception_handler();
      throw new Exception(&#39;测试自定义异常处理器&#39;);
      
      //自定义异常处理器,不会向下继续执行,因为throw之后不会再继续执行;try{} catch{}之后,会继续执行
      //回顾:自定义错误处理器会继续执行代码,而手动抛出的错误信息不会继续执行
      echo &#39;test&#39;;
      /**
       * 自定义异常类处理器
       * Class ExceptionHandler
       */
      
      class ExceptionHandler
      {
          protected $_exception;
          protected $_logFile = __DIR__.&#39;/exception_handle.log&#39;;
          public function __construct(Exception $e)
          {
              $this->_exception = $e;
          }
          public static function handle(Exception $e)
          {
              $self = new self($e);
              $self->log();
              echo $self;
          }
          public function log()
          {
              error_log($this->_exception->getMessage().PHP_EOL,3,$this->_logFile);
          }
      
          /**
           * 魔术方法__toString()
           * 快速获取对象的字符串信息的便捷方式,直接输出对象引用时自动调用的方法。
           * @return string
           */
          public function __toString()
          {
              $message = <<<EOF
              <!DOCTYPE html>
              <html lang="en">
              <head>
                  <meta charset="UTF-8">
                  <title>Title</title>
              </head>
              <body>
                  <h1>出现异常了啊啊啊啊</h1>
              </body>
              </html>
      EOF;
          return $message;
          }
      
      }
      set_exception_handler(array(&#39;ExceptionHandler&#39;,&#39;handle&#39;));
      /**
       * try catch不会被自定义异常处理!!!!
       */
      try{
          throw new Exception(&#39;this is a test&#39;);
      }catch (Exception $exception) {
          echo $exception->getMessage();
      }
      throw new Exception(&#39;测试自定义的异常处理器&#39;);

      3.1.2 错误/异常之后是否继续执行代码问题总结

      异常:

      自定义异常处理器不会向下继续执行,因为throw之后不会再继续执行
      try{} catch{}之后,会继续执行

      错误:

      自定义错误处理器会继续执行代码,而手动抛出的错误信息不会继续执行

      3.2 像处理异常一样处理PHP错误

      3.2.1 方式一:ErrorException

      /**
       * 方式一:ErrorException错误异常类
       * @param $errno
       * @param $errstr
       * @param $errfile
       * @param $errline
       * @throws ErrorException
       */
      function exception_error_handler($errno,$errstr,$errfile,$errline){
      
          throw new ErrorException($errstr,0,$errno,$errfile,$errline);
      }
      
      set_error_handler(&#39;exception_error_handler&#39;);
      
      try{
          echo gettype();
      }catch (Exception $exception){
          echo $exception->getMessage();
      }

      3.2.2 方式二:自定义异常类,继承基类Exception

      /**
       * 方式二:自定义异常类
       * Class ErrorToException
       */
      //显示所有的错误
      error_reporting(-1);
      class ErrorToException extends Exception{
          public static function handle($errno,$errstr)
          {
              throw new self($errstr,0);
          }
      }
      
      set_error_handler(array(&#39;ErrorToException&#39;,&#39;handle&#39;));
      set_error_handler(array(&#39;ErrorToException&#39;,&#39;handle&#39;),E_USER_WARNING|E_WARNING);
      
      try{
          echo $test;//notice,不会被处理
          echo gettype();//warning
          //手动触发错误
          trigger_error(&#39;test&#39;,E_USER_WARNING);
      }catch (Exception $exception){
          echo $exception->getMessage();
      }

      3.3 PHP页面重定向实现

      header(&#39;Content-type:text/html;charset=utf-8&#39;);
      class ExceptionRedirectHandler{
          protected $_exception;
          protected $_logFile = __DIR__.&#39;redirect.log&#39;;
          public $redirect=&#39;404.html&#39;;
          public function __construct(Exception $e){
              $this->_exception=$e;
          }
          public static function handle(Exception $e){
              $self=new self($e);
              $self->log();
              // ob_end_clean()清除所有的输出缓冲,最后没有缓存的时候会产生通知级别的错误
              while(@ob_end_clean());
              header(&#39;HTTP/1.1 307 Temporary Redirect&#39;); //临时重定向
              header(&#39;Cache-Control:no-cache,must-revalidate&#39;);//no-cache强制向源服务器再次验证,must-revalidate可缓存但必须再向源服务器进行确认
              header(&#39;Expires: Sat, 28 Mar 2016 13:28:48 GMT&#39;); //资源失效的时间
              header(&#39;Location:&#39;.$self->redirect); //跳转
          }
          public function log(){
              error_log($this->_exception->getMessage().PHP_EOL,3,$this->_logFile);
          }
      }
      set_exception_handler(array(&#39;ExceptionRedirectHandler&#39;,&#39;handle&#39;));
      $link=@mysqli_connect(&#39;127.0.0.1&#39;,&#39;root&#39;,&#39;1234561&#39;);
      if(!$link){
          throw new Exception(&#39;数据库连接出错啦&#39;);
      }

      完!

      参考课程视频:那些年你遇到的错误与异常

      相关推荐:

      PHP程序员遇到的错误与异常上篇之错误

以上がPHP プログラマーが遭遇するエラーと例外 パート 2: 例外の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。