代码之家  ›  专栏  ›  技术社区  ›  nickf

定义两个函数,还是一个函数内的分支?

  •  3
  • nickf  · 技术社区  · 16 年前

    我正在阅读关于如何在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 语句,以及函数的调用频率,这可能会更有效率。我的问题是:在哪一点上你会考虑像第一个例子中那样把一个函数一分为二?有没有其他的优点/缺点我错过了?

    编辑

    6 回复  |  直到 16 年前
        1
  •  5
  •   leepowers    16 年前

    我的直觉反应是只宣布 is_utf8 功能。PHP引擎非常擅长优化和多个调用的开销 function_exists() 应该可以忽略不计。

        2
  •  3
  •   Pmax    16 年前

    一个好的实践,也许不是在这种情况下,但一般来说可能涉及使用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);
    
        3
  •  2
  •   Ed Carrel    16 年前

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

        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的调用的聚合时间占对blarg的聚合调用的50-75%,这取决于被测试的函数是否真的存在。

    以下是实际数字:

    • 函数存在(“foobar”)
      • 布拉格:36.64毫秒
      • 巴兹:14.71毫秒
    • 函数存在(“sin”)
      • 布拉格:35.24毫秒
      • 巴兹:23.59毫秒

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

    至于风格,我真的不喜欢第一种。在两个不同的地方用名字定义一个函数似乎是一件不明智的事情,特别是当依赖于PHP中的奇怪之处时,这种奇怪之处使得没有在全局范围内执行的函数定义无论如何都会影响全局范围。另一方面,我的偏见可能正在显现,而PHP社区的其他成员在本例中依赖PHP解释器作为某种预处理器可能没有问题。

    这就是风格问题。

        4
  •  1
  •   Emilio M Bumachar    16 年前

    默认情况下,始终使用可读性最高的解决方案。如果这段代码对您的应用程序造成了很大的阻力(测量的,而不是假设的),那么您可以对其进行优化。

        5
  •  0
  •   Aidan Cully    16 年前

    我会提前为最有可能相当难看的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 变量将存在于执行环境中,仅取决于它是否可以在该环境中工作。每个变量都位于一个最小大小的代码块中,以确定是否应该加载该变量并执行其功能。主要原因是我认为编写函数所需的空间越小,读者就越容易理解函数的行为。你的眼睛必须少走走,你必须少滚动,在第一次理解一个函数的过程中,那些琐碎的挫折通常会少一些。第二个原因是它提供了一种更好的测试代码的方法—您可以更轻松地自动化 是utf8吗 当您可以同时访问所有变量例程时,它们会产生相同的结果。

        6
  •  0
  •   xtofl Adam Rosenfield    16 年前

    正如许多明智的海报所说:不要为性能操心,直到它被证明是一个问题。

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

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

    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 );
    }
    
    推荐文章