PHP konteyner nesnesinin bir yöntem başvurmak?

5 Cevap

PHP aşağıdaki Verilen:

<?php
class foo {
  public $bar;
  function __construct() {
    "Foo Exists!";
  }

  function magic_bullet($id) {
    switch($id) {
    case 1:
      echo "There is no spoon! ";
    case 2:
      echo "Or is there... ";
      break;
    }
  }
}

class bar {
  function __construct() {
    echo "Bar exists";
  }
  function target($id) {
    echo "I want a magic bullet for this ID!";
  }
}

$test = new foo();
$test->bar = new bar();
$test->bar->target(42);

'Bar' sınıf 'foo' sınıf 'sihirli mermi' yöntemini çağırmak için mümkün olup olmadığını merak ediyorum. 'Bar' örnek 'foo' Örneğin içerdiği, ancak onunla bir ebeveyn / çocuk ilişkisi içinde değildir. Aslında, ben "foo" bir dizide olduğu çok çeşitli "bar" sınıfları var, her böylece bir yapı engelleme, bir sonuç için "magic_bullet" işlevine geçmek isteyen önce $ id farklı bir şey yapıyor sınıf ilişkilerinin değişimi, bir 'konteyner' örneğinin bir yöntem erişmek mümkün mü?

5 Cevap

Sen bir ilişki sağlamak için kodunuzu değiştirmeniz gerekir. OOP dili ile, biz bu aggregation diyoruz.

PHP 4, ve "barlar bir dizi" fikrini varsayarsak

<?php

class foo {
  var $bars = array();
  function __construct() {
    "Foo Exists!";
  }

  function magic_bullet($id) {
    switch($id) {
    case 1:
      echo "There is no spoon! ";
    case 2:
      echo "Or is there... ";
      break;
    }
  }

  function addBar( &$bar )
  {
    $bar->setFoo( $this );
    $this->bars[] = &$bar;
  }
}

class bar {
  var $foo;
  function __construct() {
    echo "Bar exists";
  }

  function target($id){
    if ( isset( $this->foo ) )
    {
      echo $this->foo->magic_bullet( $id );
    } else {
      trigger_error( 'There is no foo!', E_USER_ERROR );
    }
  }
  function setFoo( &$foo )
  {
    $this->foo = &$foo;
  }
}

$test = new foo();
$bar1 = new bar();
$bar2 = new bar();

$test->addBar( $bar1 );
$test->addBar( $bar2 );

$bar1->target( 1 );
$bar1->target( 2 );

Tanımlı hiçbir ilişki yoktur gibi Hayır, mümkün değil.

Bunun yerine, doğrudan $test->bar özelliğini ayarlama, bir ayarlayıcı kullanın ve bir münasebetini bu şekilde kurabilir öneririm. Ayrıca bar sınıfına bir container özellik eklemek gerekir. Sınıf içinde foo,

function setBar(bar $bar)
{
    $bar->container = $this;
    $this->bar = $bar;
}

Bu nesneler arasında bir ilişki kurar. : Şimdi bar::target($id) işlevini değiştirmek

function target($id)
{
    $this->container->magic_bullet($id);
}

Bunu şimdi yapmak gerekir:

$test = new foo();
$bar = new bar();
$test->setBar($bar);
$test->bar->target(42);

(Sadece size gösterilen ettik koduna dayalı olsa!) Bu benim için görünen bir statik Yöntem için mükemmel bir durumda olmak için ...

<?php
class foo {
  var $bar;
  function __construct() {
    "Foo Exists!";
  }

  static function magic_bullet($id) {
    switch($id) {
    case 1:
      echo "There is no spoon! ";
    case 2:
      echo "Or is there... ";
      break;
    }
  }
}

class bar {
  function __construct() {
    echo "Bar exists";
  }
  function target($id) {
    echo Foo::magic_bullet($id)
  }
}

$test = new foo();
$test->bar = new bar();
$test->bar->target(42);

Yoksa, sadece hiç bir "Foo" Nesne olacaksa eğer - belki bir Singleton Tasarım desen?

Sen $bar örneği, Foo içinde, onu içeren sınıf ne olduğunu bilmek için bir yol vardır; böylece, o birinin herhangi bir yöntemini çağırmak için bir yol.

(Well, maybe (probably not) working with Reflection... I should try that, one day ^^ )

EDIT: bu konuda biraz düşünme: Eğer bar sınıfının içinde, foo bir gösterici tutmak olabilir; Bu gibi biraz:

class foo {
  var $bar;
  function __construct() {
    var_dump("Foo Exists!");
  }

  function magic_bullet($id) {
      var_dump('magic_bullet : ' . $id);
    switch($id) {
    case 1:
      var_dump("There is no spoon! ");
    case 2:
      var_dump("Or is there... ");
      break;
    }
  }
}

class bar {
  protected $pointer_to_foo;
  function __construct($pointer_to_foo) {
    var_dump("Bar exists");
    $this->pointer_to_foo = $pointer_to_foo;
  }
  function target($id) {
    var_dump("I want a magic bullet for this ID!");
    if (method_exists($this->pointer_to_foo, 'magic_bullet')) {
        $this->pointer_to_foo->magic_bullet($id);
    }
  }
}

$test = new foo();
$test->bar = new bar($test);
$test->bar->target(42);

Ben bir güvenlik önlemi olarak method_exists kullanılır dikkat edin.

Ve alırsınız:

string 'Foo Exists!' (length=11)

string 'Bar exists' (length=10)

string 'I want a magic bullet for this ID!' (length=34)

string 'magic_bullet : 42' (length=17)

Eğer kod biraz değiştirirseniz Yani, ... yapılabilir ;-)


Edit 2 : ho, zombat beat me to it, it seems :-(

Burada bir kaç seçenek var. Ben küresel rota gidiş karşı tavsiye ederim.

$test->bar = new bar($test);

Eğer Barın kurucudaki $ testi saklıyorsanız, bu işe olur. Sen de olabilir:

class test {
...
  public function target($someInt) {
    $this->bar->target($someInt,$this);
  }
}
$test->target(42);

... Ve bar hedef () yöntemi verilen test nesnesini kullanın.