PHP tembel Fonksiyon Tanımı - mümkün mü?

8 Cevap php

Yaparak bir işleve N. çağrı expensive, sadece işlevine ilk çağrı tek zamanlı operasyonlar - JavaScript olarak, Lazy Function Definitions 2 optimize etmek için kullanabilirsiniz.

Ben PHP 5 şey aynı tür yapmak istiyorum, ama bir işlevi yeniden tanımlıyor izin verilmez, ne de bir fonksiyon aşırı yükleme var.

Etkili ne yapmak istiyorum, sadece bu nedenle 2 optimize aşağıdaki gibidir - N. aramalar (25-100 diyelim) gerek yok onlar ilk çağrı ise tekrar kontrol edin.

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

PS Ben sadece bir kez harici kod çalıştırmak için fonksiyon birinci hat olarak bir include_onceyi () veya require_once () kullanarak düşündüm, ama bunlar çok pahalı olduğunu duydum.

Herhangi bir düşünce? ya da bu mücadele için daha iyi bir yolu var mı?

8 Cevap

Yerel bir statik var kullanmak:

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

Bunun için küresel kullanmaktan kaçının. Bu global namespace Clutterlar ve işlevi daha az kapsüllü yapar. Fonksiyonunun bağırsaklar yanı sıra diğer yerlerde denir oldu bilmek gerekiyorsa, o zaman Alan Fırtına gibi bir sınıf içinde bu işlevi koymak için belirtilen değer olurdu.

Aslında bu kodu profilli var? Ben ekstra bir boolean test sayfası oluşturma zamanında herhangi bir ölçülebilir bir etkiye sahip oluyor şüpheli değilim.

Eğer conditional fonksiyon tanımını yapabilir.

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

Tanımlı Ama şu anda, bir işlev, bir tuğla olur.

Sen create_function kullanabilirsiniz, ancak bu bellek kullanır, yavaş çünkü seni DONT öneririm,) 'e kadar php çıkar d (ücretsiz olsun, ve bir güvenlik yok eval () gibi büyük delik.

Bekle PHP5.3 kadar, biz "kapanışları" var burada http://wiki.php.net/rfc/closures

O zaman yapmanız gereken izin olacak

if( !isset( $baz ) ) 
 { 
    $baz = function( $args )
    { 
        echo $args;
    }
}

$baz('hello');

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

Daha fazla okuma üzerine, bu istediğiniz etkisidir.

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

Bu ne istediğinizi yapacağım, ama çağrı biraz daha pahalı normal bir işlev çağrısı daha olabilir.

PHP5.3 bu geçerli de olmalıdır:

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

(Şahsen, ben bütün bu düzgün hileler 2 pozitif bit sizin daha önceki karşılaştırıldığında daha epically yavaş olacak tabii ki düşünüyorum. ;))

Eğer alma konusunda gerçekten endişe ediyorsanız best her yerde hız

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

Ancak bunu yapmak mümkün olmayabilir, ama size açıklamak için yeterli kapsam verilmemiştir ettik. Ancak, daha sonra iyi ki yapabilir, basit cevaplar :) genellikle en iyisidir

Eğer ekstra bir mantıksal bir test çok pahalı olacak bulma rüzgar yoksa, bir fonksiyonun adına bir değişken ayarlamak ve onu arayabilirsiniz:

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

Verdikleri bir atış

Etmeyiniz () veya include_onceyi (), () başarısız eklerseniz umurumda değil sürece. Dahil Eğer kodu dahil ediyorsanız, o zaman umurumda. Her zaman require_once () kullanın.

PHP sözcük kapsama sahip değildir, bu yüzden bir fonksiyon ile ne istediğinizi yapamazsınız. Bununla birlikte, PHP, kavramsal olarak, bu amaç için tam olarak aynı şekilde çalışır sınıfları vardır.

Javascript, sen yapardın:

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

(PHP) sınıfları ile yapmanız olacaktır:

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

Evet, sınıf-temelli oop işlevsel programlama daha ayrıntılı, ancak performans-bilge onlar hakkında benzer olmalıdır.

Hepsi bir yana o, PHP 5.3 muhtemelen anlamsal kapsamı / kapatma desteği alacak, böylece çıktığında size daha akıcı fonksiyonel programlama tarzı yazabilirsiniz. Bir detailed description of this feature için PHP RFC-wiki bakın.

Nasıl bir yerel statik değişkenler kullanarak?

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

Size verilen parametre değeri için sadece bir kez pahalı şeyler yapmak gerekiyorsa, bir dizi tampon kullanabilirsiniz:

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

Yerel statik değişkenler fonksiyon çağrıları arasında kalıcıdır. Onlar döndükten sonra değerini hatırlıyorum.

Eğer fonksiyonel stil desen taahhüt ediyoruz herhangi bir neden? Anonim işlevler ve kapatılması için planlar olmasına rağmen, PHP gerçekten işlevsel bir dil değildir. Bir sınıf ve nesne burada iyi bir çözüm olacak gibi görünüyor.

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
    }
}

Eğer fantezi almak istedim Eğer denilen booleans önceden tanımlamak zorunda kalmamak için sihirli yöntemler kullanabilirsiniz. Eğer bir nesne oluşturmak istemiyorsanız, statik gidin.