定义两个函数,或在一个内分支?

时间:2009-12-08 00:51:19

标签: php function

我正在阅读如何在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
    }
}

但是,我也可以看到它也有一些好处。根据{{​​1}}语句的复杂程度以及调用函数的频率,这可能会更有效。我的问题是:你会在什么时候考虑将功能分成两个,就像在第一个例子中一样?我错过了其他任何优点/缺点吗?

修改:请不要挂在这里的例子上,问题是关于这种做法。

6 个答案:

答案 0 :(得分:5)

我的直觉反应是使用is_utf8函数的单个声明。 PHP引擎非常擅长优化,对function_exists()的多次调用的开销应该可以忽略不计。

答案 1 :(得分:3)

一个好的做法,也许不是那种情况,但通常可能涉及使用工厂方法的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);

答案 2 :(得分:2)

在风格上,我倾向于推动第二个。如果性能是一个问题,那么你最好考虑使用第一个。

    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 ms
    • baz:14.71 ms
  • function_exists( “罪”)
    • blarg:35.24 ms
    • baz:23.59 ms

这两个函数之间的唯一区别是条件和输出中的两个额外字符。有趣的是,10001对function_exists的调用在两次测试中分别只需要0.18和0.11 ms。我想知道是否在某个配置文件中都没有考虑到某些函数调用开销。

至于风格,我真的不喜欢第一个。在两个不同的地方通过名称定义函数似乎是一件很糟糕的事情,特别是当依赖于PHP中的奇怪性时,使得在全局范围内不执行的函数定义无论如何都会影响全局范围。另一方面,我的偏见可能正在显示,并且PHP社区的其余部分可能没有问题,在这种情况下依赖PHP解释器作为一种预处理器。

耸肩这就是风格问题。

答案 3 :(得分:1)

默认情况下,始终使用最易读的解决方案。如果特定的代码片段在您的应用程序中被证明是一个重要的阻力(测量,而不是假设),那么您可以对其进行优化。

答案 4 :(得分:0)

我会提前为最可能非常丑陋的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变体例程产生相同的结果。

答案 5 :(得分:0)

这里有两个方面:表现(不要为你不需要的东西买单)和可读性。

正如许多明智的海报所说:在被证明是一个问题之前,不要担心表现。

但是关于可读性,在我看来,一个功能应该尽可能少地展示责任。完全一件事的函数最容易理解。

你的问题实际上是关于'我应该如何混合两个责任':

  1. 什么:检测库的存在,并“调度”到正确的代码块
  2. 如何使用该库与如何不使用。
  3. 这就是我真正创建两个'层'的原因:一层调度到适当的函数,另一层包含'代码块',包含在一个具有正确名称的函数中。

    然后你仍然可以选择是否明确地进行调度,或者使用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 );
    }