PHP Sınıf Eklentileri?

4 Cevap php

ben sadece PHP öğrenirken, php, herhangi bir eklenti sistemi inşa uygulamak gelmez bir kaç soru daha var?

böylece eklenti çekirdek bileşeninin davranışını değiştirmek mümkün olacaktır.

Örneğin böyle bir şey çalışır:

include 'core.class.php';
include 'plugin1.class.php';
include 'plugin2.class.php';
new plugin2;

where core.class.php contains

class core {
  public function coremethod1(){
    echo 'coremethod1';
  }
  public function coremethod2(){
    echo 'coremethod2';
  }
}

plugin1.class.php içeriyor

class plugin1 extends core {
  public function coremethod1(){
    echo 'plugin1method1';
  }
}

plugin2.class.php içeriyor

class plugin2 extends plugin1 {
  public function coremethod2(){
    echo 'plugin2method2';
  }
}

Bu ideal değilse şimdi eklentileri birbirlerine güvenilir olan, ve eklentileri ortadan kaldırarak sorun için olacaktır:

include 'core.class.php';
//include 'plugin1.class.php';
include 'plugin2.class.php';
new plugin2;

her şeyi kırar ...

are there any proper methods to doing this? if there are not, them i might consider moving to a different langauge that supports this...

herhangi bir yardım için teşekkürler.

edit: obviously it is my understanding that is lacking, so here is a attempt at a clarification.

core.class.php içeriyorsa ...

plugin1.class.php içeriyor anything...

plugin2.class.php içeriyor anything...

include 'core.class.php';
include 'plugin1.class.php';
include 'plugin2.class.php';
$core = new core;
$core->coremethod1();//outputs plugin2method1

oysa:

include 'core.class.php';
include 'plugin2.class.php';
$core = new core;
$core->coremethod1();//outputs plugin1method1

I'm interested in any implementation, even one not involving classes for example

include 'core.php';
//does core stuff

include 'core.php';
include 'plugin1';
//does extended core stuff

include 'core.php';
include 'plugin2';
//does extended core stuff


include 'core.php';
include 'plugin2';
include 'plugin1';
//does very extended core stuff

including a file needs to change the application behavior. herhangi bir anlamı olması için.

Sanırım bu da ne denir biliyor musun, bu yüzden eğer varsa doğru isimlendirilmesi beni işaret etmemektedir.

4 Cevap

Senin tek endişe plugin1 dahil değil bir hata yaratacak ise, o zaman otomatik plugin2 yük plugin1 var hakklı için çare olabilir:

PHP Manual on spl_autoload olarak yorumlardan

// Your custom class dir
define('CLASS_DIR', 'class/')

// Add your class dir to include path
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);

// You can use this trick to make autoloader look 
// for commonly used "My.class.php" type filenames
spl_autoload_extensions('.class.php');

// Use default autoload implementation
spl_autoload_register();

Ancak, bir özellikleri / mixin-gibi özelliği arıyorsanız, eğer, o zaman cevap hayır. PHP şimdi bu desteklemez. En az not without patching the core veya üretim kodunda kullanmak istemiyorum these two API'leri başvuruyorlar.

Bir nesne zamanında nasıl davrandığını değiştirmek için doğru yolu kullanmak olacaktır Decorators:

$class = new BasicCache( new BasicValidators ( new Basic ) );

ya da Strategy desenler

$class = new Basic;
$class->setStrategy(function() { return 'foo'} );
echo $class->callStrategy(); // foo
$class->setStrategy(function() { return 'bar'} );
echo $class->callStrategy(); // bar

http://sourcemaking.com/design_patterns, en yaygın modeller için bkz.


EDIT İşte dekoratörler ile eklentileri oluşturmak için nasıl bir örnektir. Bazı olmayan oyuncu karakterleri sanal uzayda dolaşmak ve zaman zaman ana karakteri selamlıyorum çeşit bir oyun var, varsayalım. Yani şimdi yapmak hepsi bu. Biz onlar biz bu senaryoda bizim eklentileri / dekoratörler ihtiyaç neden olsa da, hangi selamlıyorum nasıl bazı varyasyon istiyorum.

İlk create an interface o selamlamak mümkün herhangi bir nesne olması gereken bazı yöntemler tanımlar. Biz bu yöntemler, belirli bir nesne üzerinde çağrıldığında ne yapar umurumda değil. Biz sadece emin yöntemleri mevcuttur olduklarını ve açıkça tanımlanmış bir girişi ile denir ki yapmak istiyorum:

interface GreetInterface
{
    public function greet($name);
    public function setGreeting($greeting);
}

Bir arabirim temelde herhangi bir uygulama bir nesne yerine getirmelidir bir sözleşmedir. Eğer selamlıyorum bir nesne varsa bizim durumumuzda, sözleşme diyor, siz iki yöntem olmalıdır. Bunları istediğiniz herhangi bir şekilde uygulamak, ancak bu yöntemler var.

Kullanıcı bu arabirimi uygulayan, şimdi bizim olmayan oyuncu karakter sınıfları inşa edelim

class Dude implements GreetInterface
{
    protected $greeting = 'hello';
    public function greet($name)
    {
        return sprintf('%s %s', $this->greeting, $name);
    }
    public function setGreeting($greeting)
    {
        $this->greeting = $greeting;
        return $this;
    }
}

Bu oldukça sanırım straigtforward oluyor. Dostum sınıfı sadece arabiriminden iki yöntemi tanımlar. Selamlıyorum () çağrıldığında, bu selamlıyorum yönteme geçirilen param tebrik depolanan dize ve prepend almak olacaktır. SetGreeting yöntem bize zamanında tebrik değiştirmenizi sağlar. Note: you could add a getter as well (I was just lazy)

Şimdi eklentileri üzerinde. Bizim gerçek eklentileri kod çoğaltmak istemiyorum çünkü biz, bazı shared boilerplate code içeren soyut bir GreetPlugin sınıf oluşturmak olacaktır. Soyut eklentisi sınıfı GreetInterface uygulayacak, böylece tüm alt sınıfları çok arabirimi uygulamak emin olabilirsiniz.

Dostum zaten de arabirimini uygulayan yana, eklentileri Dude genişletmek olabilir, ama uzanan bir is-a ilişkisi oluşturur, ama bir eklenti bir Dostum değil, çünkü bu, kavramsal yanlış olur.

abstract class GreetPluginAbstract implements GreetInterface
{
    protected $inner;
    public function __construct(GreetInterface $inner)
    {
         $this->inner = $inner;
    }
    public function setGreeting($greeting)
    {
        $this->inner->setGreeting($greeting);
        return $this;
    }
    public function greet($name)
    {
        return $this->inner->greet($name);
    }
}

GreetInterface uygularken herhangi bir sınıf: eklentisi sınıfı başlatıldı tek argüman kabul eder. TypeHint Emin, sınıf ahdine vefa yapar. Eğer kodda görebileceğiniz gibi, bizim eklentileri yapıcısı geçti sınıf arayüzü yöntemleri çağırmak gerekir, çünkü bu, gerekli oluyor. Biz Dude uzatıldı olsaydı, biz şimdi biraz garip olan, ahbaplar içine dudes sarmak mümkün olacaktır. Bunu yapmamak için bir başka neden.

Şimdi ilk eklenti üzerinde. Biz çocuklardan bazıları biryere aksan kullanımı anlamına gelen bir fantezi Fransız aksanı ile konuşmak istiyorum, ancak uygun bir h telaffuz edemez. Disclaimer: yes, I know that's a cliche. Please bear with my examples

class FrenchPlugin extends GreetPluginAbstract
{
    public function greet($name) {
       return str_replace(array('h', 'e'), array('', 'é'),
                          $this->inner->greet($name));
    }
}

Plugin soyut eklenti uzanır yana, biz şimdi normal bir dostum Selamını yapacağını nasıl değiştirir gerçek kodu odaklanabilirsiniz. Selamlıyorum () çağrıldığında, biz sarılı elemanına () selamlıyorum ve sonra da tüm h karakterleri kaldırmak ve tüm es es içine çevirmek diyoruz. Her şey değiştirilmemiş soyut davranıştır.

Başka bir eklenti, biz tebrik ifadeleri değiştirmek istiyorsanız, bu yüzden bazı ahbaplar yerine sadece Hello Heya, demek var. Sadece bazı değişim eklemek.

class EasyGoingPlugin extends GreetPluginAbstract
{
    protected $inner;
    public function __construct(GreetInterface $inner) {
         $this->inner = $inner->setGreeting('heya');
         parent::__construct($inner);
    }
}

Selamlıyorum yöntem sadece o olacak ne olursa olsun dönmek gerekir, çünkü bu şekilde biz sadece, kurucu geçersiz kılar. Bu yüzden bu eklenti geçirilen nesne üzerinde setGreeting yöntemi diyoruz. Nesne GreetInterface uygulamak zorundadır, çünkü biz bu çalıştığından emin olabilirsiniz.

Ben iç nesne olarak setGreeting dönüş değeri atama ediyorum unutmayın. Ben $ this dönmek çünkü setMethod denir zaman bu mümkündür. Bu arayüz üzerinden zorunlu olamaz, bu yüzden bu forma arayüz güvenemezsiniz. method chaining: Ben sadece başka bir tekniği göstermek için eklendi.

İki eklentileri bitmiş, biz yeterince farklılık var hissediyorum. Şimdi sadece Dudes oluşturmak için uygun bir yol gerekir. Bunun için bu gibi küçük bir sınıf oluşturmak:

class DudeBuilder
{
     public static function build()
     {
         $dude = new Dude();
         $decorators = func_get_args();
         foreach($decorators as $decorator) {
             $decorator .= "Plugin";
             // require_once $decorator;
             $dude = new $decorator($dude);
         }
         return $dude;
     }
}

Note: I always mix up Builder and AbstractFactory, so if the above is a Factory, well, then it's a factory. Check out the design patterns links I gave earlier on ;)

Bütün bu Builder, düzenli bir ahbap oluşturmak ve sonra sarmak / biz onu kullanmak anlatmak ve geri daha ne eklentileri ile / onu içine dekore edilir gelmez. Oluşturucu hayır kendi devletini kapsüller, çünkü biz inşa yöntemi statik yapmak.

Bu örnek için ben sana sağ üst verdi autoloading kodu kullanmış varsayalım. Değilse, sen foreach döngüsünde eklenti dosyaları içerebilir. Onlar yalnızca gerektiğinde tembel onları yükleme üstüne hepsini içeren üzerinde size birkaç mikrosaniye daha hızlı yükleme süreleri verecektir. Umarım, bu da ben davranış, bir dosya ekleme ile kontrol edilmemelidir savundu zaman çeşitli yorumlar ne anlama geldiğini açıklıyor. Dosya dahil sadece bir zorunluluktur. PHP bilmiyor bir sınıf kullanamazsınız. Ama gerçekten sınıfı kullanıldığı, yapı yöntemine eklenti isimleri geçerek, tek başına bizim kod tarafından kontrol edilir.

Şimdi bunu yapalım

$regularDude         = DudeBuilder::build();
$frenchDude          = DudeBuilder::build('French');
$easygoingDude       = DudeBuilder::build('EasyGoing');
$frenchEasyGoingDude = DudeBuilder::build('French', 'EasyGoing');

Bu, etkili bir yapıyor olarak aynıdır:

$regularDude         = new Dude;
$frenchDude          = new FrenchPlugin(new Dude);
$easygoingDude       = new EasyGoingPlugin(new Dude);
$frenchEasyGoingDude = new FrenchPlugin(new EasyGoingPlugin(new Dude));

Sadece iki eklentileri ile, biz şimdi Dudes üç tür oluşturabilirsiniz. Bırakalım selamlıyorum atalım:

echo $regularDude->greet('Yuri'), PHP_EOL,
     $frenchDude->greet('Yuri'), PHP_EOL,
     $easygoingDude->greet('Yuri'), PHP_EOL,
     $frenchEasyGoingDude->greet('Yuri'), PHP_EOL;

// gives

hello Yuri
éllo Yuri
heya Yuri
éya Yuri

Biz şimdi temel sınıfları süslemek için ek eklentileri oluşturabilirsiniz. Nedense, sizin oyun olarak iyi at veya araba konuşurken olmalıdır karar verirseniz, aynı zamanda bir sınıf Araba veya Atı oluşturmak ve çok selamlıyorum arabirimini uygulayan ve onlar için bir Builder eklemek olabilir. Daha sonra Fransız EasyGoing Otomobil veya Horses oluşturmak için eklentileri yeniden kullanabilirsiniz.

Siz dönem "eklentisi" kötüye vardır. actual PHP eklentileri (PHP dünyada denir extensions) olurdun yapmak için - bir eklenti genellikle bir sistemin taban işlevselliğini genişleten veya değiştiren bir kod paketi C yazarken veya C + +.

Burada ne tarif ettiğin sadece kullanım için geçerli yürütme içine sınıfları ya da sınıf ağaçları dahil olmak üzere. Ve orada is 'otomatik olarak' geçerli yürütme bağlamında içine getirmek için bir yol ve bu autoload system yoluyla.

Eğer autoloading üzerinde belgeleri okuduktan sonra, hala ileriye taşımak için nasıl emin, eğer, burada yorum ve ben birlikte size yardımcı olacaktır.

EDIT

Tamam, ben sonra ne konum görüyorum. Sen ne peşinde exactly yapamaz. Eğer sınıfının new core; Bir örneğini çalıştırdığınızda core iade edilecektir - Eğer tüm bu değişiklik yapamazsınız.

Eğer core örneklerini oluşturmak nasıl değiştirmek için hazırız, ancak o zaman ben sizin için işe yarayabilir bir şey olduğunu düşünüyorum, ve bu gibi bir şey olabilir.

class core {
  public function coremethod1(){
    echo 'coremethod1';
  }
  public function coremethod2(){
    echo 'coremethod2';
  }

  /**
   * @return core
   */
  final public static function create()
  {
    // listed in order of preference
    $plugins = array( 'plugin2', 'plugin1' );

    foreach ( $plugins as $plugin )
    {
        if ( class_exists( $plugin ) )
        {
          return new $plugin();
        }
    }

    return new self;
  }
}

class plugin1 extends core {
  public function coremethod1(){
    echo 'plugin1method1';
  }
}

class plugin2 extends plugin1 {
  public function coremethod2(){
    echo 'plugin2method2';
  }
}

$core = core::create();

// test what we have
echo get_class( $core ), '<br>'
   , $core->coremethod1(), '<br>'
   , $core->coremethod2()
;

PHP core (C + +, ben inanıyorum vardır) PECL uzantıları ile uzatılabilir.

(Eğer AKB PECL uzantısı kurduysanız) çekirdek fonksiyonları override_function ile geçersiz kılınabilir

Kullanıcı fonksiyonları call_user_func ile idam edilebilir.

Eğer planlama ne açıklayabilir Belki biz daha iyi bir cevap sunmak mümkün olurdu?

Plugin2 plugin1 uzanır çünkü kod kırma ve plugin1 sınıfı dahil etmiyoruz. Neden sınıf yapmak plugin2 çekirdeğini uzatmak değil? Bu sizin için gidiyoruz ne gibi görünüyor.