Php 5.3 önce Binding Geç Statik Faking

5 Cevap php

Ben kılınmış "iç" başka bir statik fonksiyonu çağırmak için "çağrı" kalıtsal bir statik işlev gerekir. Ben geç statik bağlama ile bu yapabileceğini, ama benim ana henüz PHP5.3 yok ve bu yüzden etrafında çalışmak gerekiyor.

class ClassA{
    static function call()
    {
    	return self::inner();
    }

    static function inner(){
    	return "Class A";
    }	
}

class ClassB extends ClassA{
    static function inner(){
    	return "Class B";
    }
}

echo "<p>Class A = " . ClassA::call();
echo "<p>Class B = " . ClassB::call();

I would like the output to be:
Class A = Class A
Class B = Class B

But what it is:
Class A = Class A
Class B = Class A

Benim gut ben "çağrısı ()", iyi, çağrıldığında başvurulan ne bir nesne tespit çağrısında şey () yazmak mümkün olması gerektiğini söyler. Yani yerine self :: iç () o olur yani calledclass hatları :: iç () boyunca bir şey. Özgün yöntem çağrısı aramak için iç uygun sürümü () algılama.

5 Cevap

Sen nesne örnekleri yerine sınıflarını kullanabilirsiniz. Eğer küresel bir sembolü istiyorsanız, global bir değişken kullanabilirsiniz. Onlar PHP oldukça hantal olduğundan, bir hüner, bir fonksiyon içine etmektir. Örn.:

class ClassA {
  function call() {
    return $this->inner();
  }
  function inner() {
    return "Class A";
  }   
}
function ClassA() {
  static $instance;
  return $instance ? $instance : new ClassA();
}

class ClassB extends ClassA {
  function inner() {
    return "Class B";
  }
}
function ClassB() {
  static $instance;
  return $instance ? $instance : new ClassB();
}

echo "<p>Class A = " . ClassA()->call();
echo "<p>Class B = " . ClassB()->call();

Ama daha iyi bir fikir tamamen küresel semboller önlemek için olabilir; Bu Ruby / Rails iyi çalışıyor nedeni, Ruby gerçekten PHP sahip olduğu aynı şekilde statik bir devlete sahip olmamasıdır. A sınıfı ribaund ve çerçeve kolay uzatılması için izin zamanında, at ilave olabilir. PHP, sınıflar her zaman kesindir, bu nedenle uygulama kodu onlara atıfta bağlantı çok güçlü bir derecesidir.

Performans sorunu değilse, sen denilen sınıf bulmak için () debug_backtrace kullanabilirsiniz:

$bt = debug_backtrace();
return get_class($bt[1]['object']);

http://php.net/manual/en/function.debug-backtrace.php

Ne yazık ki bunu yapmak için güzel bir yolu (aksi PHPers o özellik için çok tezahürat olmaz) var.

Sen have to pas sınıf adı. PHP < 5.3 Ayrıca bütün şey bile çirkin kılan dinamik sınıf adı ile statik aramalar için güzel sözdizimi yok:

static function call($class)
{
    return call_user_func(array($class,"inner"));
}
…
ClassA::call("ClassA");
ClassB::call("ClassB");

Eğer kodunu değiştirmek durumunda (ve kullanmayın static), sonra singletons daha katlanılabilir hale. Sen yardımcı function sözdizimi kolaylaştırmak için yapabilirsiniz:

X("ClassA")->call();
X("ClassB")->call();

X fonksiyonu, bakmak oluşturmak ve bir sınıfın örneğini döndürmesi gerekir.

Bir çocuk da, çocuğun soyut bir statik yöntemini çağırır, ebeveynin bir yöntem geri çağırdığında genellikle, bağlama geç statik gereklidir. Ben böyle bir postition oldu, ve statik kullanamadı :: benim PHP sürüm 5.3 değildi (veya üstü) gibi. Debug_backtrace yolu () tarafından bağlayıcı aşağıdaki başarılı geç statik.

abstract class ParentClass
{
    static function parent_method()
    {
        $child_class_str = self::get_child_class();
        eval("\$r = ".$child_class_str."::abstract_static();");
        return $r;
    }// CHILD MUST OVERRIDE TO PUT ITSELF INTO TRACE

    protected abstract static function abstract_static(); // THIS NEEDS LATE STATIC BINDING

    private static function get_child_class()
    {
        $backtrace = debug_backtrace();
        $num = count($backtrace);
        for($i = 0; $i < $num; $i++)
        {
             if($backtrace[$i]["class"] !== __CLASS__)
                  return $backtrace[$i]["class"];
        }
        return null;
    }
}

class ChildClass extends ParentClass
{
    static function parent_method(){ return parent::parent_method(); }

    protected static function abstract_static()
    {
        return __METHOD__."()";
    }// From ParentClass
}

print "The call was: ". ChildClass::parent_method();

Burada hızlı bir örnek.

<?php

class ClassA{
   public function call(){
      return $this->inner();
   }

   static function inner(){
      return "Class A";
   }

   static function init($class){
      return new $class();
   }   
}

class ClassB extends ClassA{
   static function inner(){
      return "Class B";
   }
}

echo "<p>Class A = " . ClassA::init("ClassA")->call();
echo "<p>Class B = " . ClassB::init("ClassB")->call();

?>

Eğer sınıf adı geçen sevmiyorum Eğer çocuk sınıf statik bir init işlevi eklemek ve açıkça de orada geçebileceği. > () Çağrısı ve ClassB :: init () - -> () çağrısı, ancak bazı küçük kod tekrarını olurdu) ClassA :: init (: Bu gibi bir şey yapmak için izin verecek.