5

JavaScriptでは、レイジー関数定義を使用して、関数の最初の呼び出しでのみコストのかかる1回限りの操作を実行することにより、関数の2番目からN番目の呼び出しを最適化できます。

PHP 5でも同じようなことをしたいのですが、関数の再定義は許可されておらず、関数のオーバーロードも許可されていません。

事実上、私がやりたいのは次のようなものですが、最適化されているだけなので、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>';
}

PS外部コードを1回だけ実行する関数の最初の行としてinclude_once()またはrequire_once()を使用することを考えましたが、これらも高価であると聞きました。

何か案は?またはこれに取り組むためのより良い方法はありますか?

4

8 に答える 8

13

ローカル静的変数を使用します。

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

このためにグローバルを使用することは避けてください。グローバル名前空間が乱雑になり、関数のカプセル化が少なくなります。関数の内部以外の他の場所で、関数が呼び出されたかどうかを知る必要がある場合は、この関数をAlanStormが示すようなクラス内に配置する価値があります。

于 2008-09-23T05:06:32.993 に答える
6

このコードを実際にプロファイリングしましたか?追加のブールテストがページのレンダリング時間に測定可能な影響を与えるかどうかは疑わしいです。

于 2008-09-23T01:55:27.290 に答える
4

条件付き関数の定義を行うことができます。

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

しかし現在、関数は定義されるとブリックになります。

を使用することはできますが、低速であり、大量のメモリを使用し、php が終了するまで free() が取得されず、eval() と同じくらい大きなセキュリティ ホールであるため、使用しないことcreate_functionをお勧めします。

「クロージャー」がある 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 
}

ただし、それはできないかもしれませんが、明確にするのに十分な範囲が与えられていません。ただし、それができる場合は、簡単な答えが最善の場合がよくあります:)

于 2008-09-23T01:55:36.523 に答える
1

失敗してもかまわない場合を除いて、include()またはを使用しないでください。コードを含める場合は、気にします。常に使用してください。include_once()include()require_once()

于 2008-09-23T02:27:33.373 に答える
0

余分なブールテストが高額になりすぎることに気付いた場合は、変数を関数の名前に設定して呼び出すことができます。

$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();
}

そのショットを与える

于 2008-09-23T02:07:12.847 に答える
0

機能的なスタイルのパターンに取り組んでいる理由は何ですか?匿名関数とクロージャの計画があるにもかかわらず、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
    }
} 

ファンシーになりたい場合は、魔法のメソッドを使用して、呼び出されたブール値を事前に定義する必要をなくすことができます。オブジェクトをインスタンス化したくない場合は、静的にします。

于 2008-09-23T02:12:02.040 に答える
0

ローカル静的変数を使用するのはどうですか?

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

特定のパラメータ値に対して1回だけ高価な作業を行う必要がある場合は、配列バッファを使用できます。

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

ローカル静的変数は、関数呼び出し間で永続的です。彼らは戻った後の値を覚えています。

于 2008-09-23T09:29:18.650 に答える
0

PHP にはレキシカル スコープがないため、関数で必要なことを行うことはできません。ただし、PHP にはクラスがあり、概念的にはこの目的でまったく同じように機能します。

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 は関数型プログラミングよりも冗長ですが、パフォーマンスに関してはほぼ同じはずです。

それはさておき、PHP 5.3 ではレキシカル スコープ/クロージャがサポートされる可能性が高いので、それが出てきたら、より流暢な関数型プログラミング スタイルで書くことができます。この機能の詳細な説明については、PHP rfc-wiki を参照してください。

于 2008-09-23T08:47:45.927 に答える