跳轉到

為什麼要有例外處理?

原文在 2024-05-14 完成

假設 PHP 沒有例外機制,那會怎樣呢?

建立一個函式 sum1(),會回傳兩個參數的總和。參數必須是可以加總的數字,所以 sum1() 的定義中,大部分的程式碼在檢查參數類型,實作功能的程式碼只有 return $x + $y; 而已。

<?php
$x = function() {
  return 1;
};
$y = 2;
printf(sum1($x, $y));

function sum1($x, $y)
{
  if( is_string($x) ) {
    printf('$x is a string' . PHP_EOL);
    exit;
  } else if ( is_string($y) ) {
    printf('$y is a string' . PHP_EOL);
    exit;
  }

  if( is_callable($x) ) {
    printf('$x is a callable object' . PHP_EOL);
    exit;
  } else if ( is_callable($y) ) {
    printf('$y is a callable object' . PHP_EOL);
    exit;
  }

  if( is_object($x) ) {
    printf('$x is an object' . PHP_EOL);
    exit;
  } else if ( is_object($y) ) {
    printf('$y is an object' . PHP_EOL);
    exit;
  }

  return $x + $y;
}

即使有例外機制,也常常可以看到這樣的程式碼:

<?php
sum1($x, $y)
{
  if( is_string($x) ) {
    throw new Exception('$x is a string');
  } else if ( is_string($y) ) {
    throw new Exception('$y is a string');
  }

  if( is_callable($x) ) {
    throw new Exception('$x is a callable object');
  } else if ( is_callable($y) ) {
    throw new Exception('$y is a callable object');
  }

  if( is_object($x) ) {
    throw new Exception('$x is an object');
  } else if ( is_object($y) ) {
    throw new Exception('$y is an object');
  }

  return $x + $y;
}

這和一開始的範例並無區別,都是產生錯誤訊息,停止執行程式,增加大量的檢查。

如果有 sum2() 定義如下,只有實作功能的程式碼,不需要檢查參數:

<?php
function sum2($x, $y)
{
  return $x + $y;
}

不應該認為使用者會照規矩呼叫程式,應該假設他們會丟各種奇怪的參數進來,必須事先做好防範,但是又要保持函式定義乾淨簡單,所以用例外機制,把錯誤往外丟,在其它地方處理:

<?php
try {
  $x = function() {
    return 2;
  };
  $y = 3;
  sum2($x, $y);
} catch (Throwable $e) {
  printf("something wrong happen! at line %s of file %s, and message is %s\n",
      $e->getLine(),
      $e->getFile(),
      $e->getMessage()
    );
}

PHP 還有 set_exception_handler()set_error_handler(),不用到處都是 try catch,可以統一在這兩個函式處理所有例外事件。

留言