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

PHP中的惰性函数定义-可能吗?

  •  5
  • scunliffe  · 技术社区  · 18 年前

    在JavaScript中,您可以使用 Lazy Function Definitions 通过执行

    我想在PHP5中做同样的事情,但是不允许重新定义函数,也不允许重载函数。

    实际上,我想做的是如下所示,只是进行了优化,以便第2-n次呼叫(比如25-100次)不需要重新检查它们是否是第一次呼叫。

    $called = false;
    function foo($param_1){
      global $called;
      if($called == false){
        doExpensiveStuff($param_1);
        $called = true;
      }
      echo '<b>'.$param_1.'</b>';
    }
    

    有什么想法吗?还是有更好的方法来解决这个问题?

    8 回复  |  直到 18 年前
        1
  •  13
  •   dirtside    18 年前

    使用本地静态变量:

    function foo() {
        static $called = false;
        if ($called == false) {
            $called = true;
            expensive_stuff();
        }
    }
    

    避免为此使用全局变量。它使全局名称空间变得混乱,使函数的封装程度降低。如果函数内部以外的其他地方需要知道它是否被调用,那么将此函数放入Alan Storm所指示的类中是值得的。

        2
  •  6
  •   John Millikin    18 年前

    你真的分析过这段代码吗?我怀疑额外的布尔测试是否会对页面呈现时间产生任何可测量的影响。

        3
  •  4
  •   Kent Fredric    18 年前

    有条件的

    if( !function_exists('baz') )
    { 
        function baz( $args ){ 
            echo $args; 
        }
    }
    

    但目前,函数在定义时会变成一块砖块。

    你可以用 create_function ,但我建议你 不 因为它速度慢,占用大量内存,在php退出之前无法释放(),并且是一个与eval()一样大的安全漏洞。

    等到PHP5.3,我们有“闭包” http://wiki.php.net/rfc/closures

    那你就可以这样做了

    if( !isset( $baz ) ) 
     { 
        $baz = function( $args )
        { 
            echo $args;
        }
    }
    
    $baz('hello');
    
    $baz = function( $args )
    { 
           echo $args + "world"; 
    }
    $baz('hello');
    

    进一步阅读后,这就是你想要的效果。

    $fname = 'f_first'; 
    function f_first( $even ) 
    { 
        global $fname; 
        doExpensiveStuff(); 
        $fname = 'f_others';
        $fname( $even );
        /* code */ 
    }
    function f_others( $odd ) 
    {
         print "<b>".$odd."</b>";
    }
    
    foreach( $blah as $i=>$v ) 
    {
       $fname($v);
    }
    

    它将执行您想要的操作,但是调用可能比普通函数调用要贵一点。

    在PHP5.3中,这也应有效:

    $func = function( $x ) use ( $func ) 
    { 
         doexpensive(); 
         $func = function( $y )
         { 
              print "<b>".$y."</b>";
         }
         $func($x);
    }
    foreach( range(1..200) as $i=>$v ) 
    { 
        $func( $v ); 
    }
    

    (就我个人而言,我当然认为所有这些巧妙的技巧都会比你之前比较的2个正数慢很多。)

    如果你真的想得到 到处飞驰

    $data = // some array structure
    doslowthing(); 
    foreach( $data as $i => $v ) 
    {
       // code here 
    }
    

    然而,你可能无法做到这一点,但你没有给予足够的空间来澄清。但是,如果你能做到这一点,那么简单的答案通常是最好的:)

        4
  •  1
  •   A J    10 年前

    请不要使用 include() 或 include_once() ,除非你不在乎 包括() 失败。如果你包含了代码,那么你就在乎了。始终使用 require_once() .

        5
  •  0
  •   Jurassic_C    18 年前

    如果最终发现额外的布尔测试过于昂贵,可以将变量设置为函数名并调用它:

    $func = "foo";    
    
    function foo()
    {
        global $func;
        $func = "bar";
        echo "expensive stuff";
    };
    
    
    function bar()
    {
        echo "do nothing, i guess";
    };
    
    for($i=0; $i<5; $i++)
    {
        $func();
    }
    

    试一试

        6
  •  0
  •   troelskn    18 年前

    在javascript中,您可以执行以下操作:

    var cache = null;
    function doStuff() {
      if (cache == null) {
        cache = doExpensiveStuff();
      }
      return cache;
    }
    

    使用类(在PHP中),您可以执行以下操作:

    class StuffDoer {
      function doStuff() {
        if ($this->cache == null) {
          $this->cache = $this->doExpensiveStuff();
        }
        return $this->cache;
      }
    }
    

    是的,基于类的oop比函数式编程更冗长,但在性能方面,它们应该差不多。

    detailed description of this feature .

        7
  •  0
  •   Michał Niedźwiedzki    18 年前

    使用局部静态变量怎么样?

    function doStuff($param1) {
        static $called = false;
        if (!$called) {
            doExpensiveStuff($param1);
            $called = true;
        }
        // do the rest
    }
    

    如果您只需要为给定的参数值执行一次昂贵的操作,则可以使用数组缓冲区:

    function doStuff($param1) {
        static $buffer = array();
        if (!array_key_exists($param1, $buffer)) {
            doExpensiveStuff($param1);
            $buffer[$param1] = true;
        }
        // do the rest
    }
    

    局部静态变量在函数调用中是持久的。他们记住返回后的值。

        8
  •  0
  •   Adam Bellaire    17 年前

    你有什么理由选择功能型模式吗?尽管有匿名函数和闭包计划,PHP实际上并不是一种函数语言。在这里,类和对象似乎是更好的解决方案。

    Class SomeClass{
        protected $whatever_called;
        function __construct(){
            $this->called = false;
        }
        public function whatever(){
            if(!$this->whatever_called){
                //expensive stuff
                $this->whatever_called = true;
            }
            //rest of the function
        }
    } 
    

    如果你想变得有趣,你可以使用神奇的方法来避免预定义所谓的布尔值。如果不想实例化对象,请转到静态。

    推荐文章