簡體   English   中英

定義兩個函數,或在一個內分支?

[英]Define two functions, or branch within one?

我正在閱讀如何在PHP中檢測文件的編碼,在某些博客或某處,有人建議這樣做:

if (function_exists('mb_detect_encoding')) {
    function is_utf8($str) {
        // do stuff using the mb* libraries
    }
} else {
    function is_utf8($str) {
        // do stuff manually
    }
}

對我來說,這感覺非常混亂,可以用這個代替:

function is_utf8($str) {
    if (...) {
        // mb stuff here
    } else {
        // manual stuff here
    }
}

但是,我也可以看到它也有一些好處。 根據if語句的復雜程度以及調用函數的頻率,這可能會更有效。 我的問題是:你會在什么時候考慮將功能分成兩個,就像在第一個例子中一樣? 我錯過了其他任何利弊嗎?

編輯 :請不要掛在這里的例子,問題是關於這種做法一般。

我的直覺反應是使用is_utf8函數的單個聲明。 PHP引擎非常擅長優化,並且多次調用function_exists()的開銷應該可以忽略不計。

一個好的做法,也許不是那種情況,但通常可能涉及使用工廠方法的OOP(對象)。

class my_utf8 
{
  // A static method that determine what object to create
  public static function factory() {
    if (function_exists('mb_detect_encoding')) {
      return new my_utf8_with_mb;
    } else {
      return new my_utf8_without_mb;
    }
  }
}

class my_utf8_with_mb extends my_utf8 {
    public function is_utf8($str) {
        // do stuff using the mb* libraries
    }
}

class my_utf8_without_mb extends my_utf8 {
    public function is_utf8($str) {
        // do stuff without the mb* libraries
    }
}

在您的申請中:

global $myUtfInstance;
// Call once
$myUtfInstance = my_utf8::factory();

// later and forever...
$myUtfInstance->is_utf8($str);

根據您的操作,您還可以使用單例模式。 它不會跳過IF,但不需要全局變量。

class my_utf8 
{
  private static $instance;

  public static function factory() {
    if (function_exists('mb_detect_encoding')) {
      return new my_utf8_with_mb;
    } else {
      return new my_utf8_without_mb;
    }
  }


  public static function getInstance()
  {
    if (!self::$instance) {
      self::$instance = self::factory();
    }

    return self::$instance;
  } 
}

在你的代碼中:

my_utf8::getInstance()->is_utf8($str);

在風格上,我傾向於推動第二個。 如果性能是一個問題,那么你最好考慮使用第一個。

if (function_exists("sin")) {
        function baz($farfs) {
            print "I am the first baz";
        }
    } else {
        function baz($farfs) {
            print "I am the second baz";
        }
    }

    function blarg($fgar) {
        if (function_exists("sin")) {
            print "I am the first blarg";
        } else {
            print "I am the second blarg";
        }
    }

    for ($i=0;$i

我在我的工作站上運行了這個,發現調用baz的總時間占總調用的50-75%到blarg,這取決於被測試的函數是否確實存在。

以下是實際數字:

  • function_exists( “取得foobar”)
    • blarg:36.64毫秒
    • 巴茲:14.71毫秒
  • function_exists( “贖罪”)
    • blarg:35.24毫秒
    • 巴茲:23.59毫秒

這兩個函數之間的唯一區別是條件和輸出中的兩個額外字符。 有趣的是,10001對function_exists的調用在兩次測試中分別只需要0.18和0.11 ms。 我想知道是否在某個配置文件中都沒有考慮到某些函數調用開銷。

至於風格,我真的不喜歡第一個。 在兩個不同的地方通過名稱定義函數似乎是一件很糟糕的事情,特別是當依賴於PHP中的奇怪性時,使得在全局范圍內不執行的函數定義無論如何都會影響全局范圍。 另一方面,我的偏見可能正在顯示,並且PHP社區的其余部分在這個實例中依賴PHP解釋器作為一種預處理器可能沒有問題。

聳聳肩這是風格問題。

默認情況下,始終使用最易讀的解決方案。 如果特定的代碼片段在您的應用程序中被證明是一個重要的阻力(測量,未假設),那么您將對其進行優化。

我會提前為最可能非常丑陋的PHP道歉,但我會做更多的事情:

if (function_exists('mb_detect_encoding')) {
    function is_utf8_mb($str) {
        // do stuff using the mb* libraries
    }
}
function is_utf8_manual($str) {
    // do stuff manually
}

if (function_exists('is_utf8_mb')) {
    function is_utf8($str) {
        is_utf8_mb($str)
    }
} else {
    function is_utf8($str) {
        is_utf8_manual($str)
    }
}

也就是說:執行環境中將存在一個is_utf8變體,它僅依賴於它是否可以在該環境中工作。 每個變體都在一個最小大小的代碼塊中,以確定是否應該加載該變量並執行其功能。 主要原因是我認為編寫函數所需的空間量越小,讀者就越容易理解函數的行為。 你的眼睛必須減少旅行,你必須少滾動,一般來說,首次理解一個功能所涉及的瑣碎挫折通常較少。 第二個原因是它提供了一種更好的代碼測試方法 - 當您可以同時訪問所有這些代碼時,您可以更輕松地自動檢查is_utf8變體例程產生相同結果的檢查。

這里有兩個方面:性能(不支付你不需要的東西)和可讀性。

正如許多明智的海報所說:在被證明是一個問題之前,不要擔心性能問題。

但是關於可讀性,在我看來,一個功能應該盡可能少地顯示責任層。 完全一件事的功能最容易理解。

你的問題實際上是關於'我應該如何混合兩個責任':

  1. 什么 :檢測庫的存在,並'調度'到正確的代碼塊
  2. 如何使用庫與如何使用庫。

這就是為什么我真的會創建兩個'層':一個層調度到適當的函數,另一個層包含'代碼塊',包含在一個具有正確名稱的函數中。

然后你仍然可以選擇是否明確地進行調度,或者使用PHP的可能性來實時聲明函數。

// functionality: defines how to detect utf8 encoding 
//

function is_utf8_mb( $arg ) {
... // using the mb library
}

function is_utf8_bare( $arg ) {
... // hand coded
}

// dispatching layer: decide what library to use
//

// option 1: define on-the-fly
function define_utf8_function() {
   if( function_exists('mb_detect_encoding') ) {
     function is_utf8( $arg ) { return is_utf8_mb( $arg ); }
   } else {
     function is_utf8( $arg ) { return is_utf8_bare( $arg ); }
   }
}

// option 2: check the dispatching on each function call
function is_utf8_runtimedispatch( $arg ) {
  if( function_exists('mb_detect_encoding') ) 
    return is_utf8_mb( $arg );
  else 
    return is_utf8_bar( $arg );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM