繁体   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