Ссылка на метод контейнерного объекта в PHP? - PullRequest
8 голосов
/ 06 августа 2009

Учитывая следующее в PHP:

<?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' вызвал метод 'magic bullet' класса 'foo'. Экземпляр 'bar' содержится в экземпляре 'foo', но не имеет с ним отношения родитель / потомок. На самом деле, у меня есть много различных классов «bar», которые «foo» имеет в массиве, каждый из которых делает что-то отличное от $ id, прежде чем передать его в функцию «magic_bullet» для конечного результата, поэтому, за исключением структуры изменение отношений классов, возможно ли получить доступ к методу экземпляра контейнера?

Ответы [ 5 ]

4 голосов
/ 06 августа 2009

Вы должны изменить свой код, чтобы обеспечить связь. в ООП-языке мы называем это агрегацией .

Предполагается PHP 4 и идея "массива баров"

<?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 );
4 голосов
/ 06 августа 2009

Нет, это невозможно, так как отношения не определены.

Я бы предложил, чтобы вместо прямой установки свойства $test->bar вы использовали установщик и могли таким образом устанавливать отношения. Вам также необходимо добавить свойство container в класс bar. Внутри класса foo:

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

Это устанавливает отношения между объектами. Теперь измените функцию bar::target($id) на:

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

Вы должны быть в состоянии сделать это сейчас:

$test = new foo();
$bar = new bar();
$test->setBar($bar);
$test->bar->target(42);
1 голос
/ 06 августа 2009

Мне кажется (хотя только на основе кода, который вы показали!) Идеальный случай для статического метода ...

<?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);

Или, если когда-нибудь будет только один объект "Foo" - может быть, шаблон Singleton Design?

0 голосов
/ 06 августа 2009

У вас есть несколько вариантов здесь. Я бы рекомендовал не идти по глобальному маршруту.

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

Это сработает, если вы сохраните $ test в конструкторе bar. Вы также можете:

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

... и использовать данный тестовый объект в методе bar ().

0 голосов
/ 06 августа 2009

Вы $bar экземпляр, внутри Foo, не можете узнать, что это за класс; так что нельзя вызывать какой-либо метод этого метода.

(Ну, может быть (возможно, не) работа с Reflection ... Я должен попробовать это однажды ^^)

РЕДАКТИРОВАТЬ: немного подумать об этом: вы можете, внутри вашего класса bar, держать указатель на foo; примерно так:

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

Обратите внимание, что я использовал method_exists в качестве меры безопасности.

И вы получите:

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)

Итак, это можно сделать ... Если вы немного измените свой код; -)


Редактировать 2: хо, зомбат бить меня, кажется: - (

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...