2009-08-06 3 views
8

Учитывая следующее PHP:Ссылка на метод контейнерного объекта в 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); 

Я интересно, если это возможно для класса «бар», чтобы вызвать метод «волшебной пули» класса «Foo». Экземпляр «bar» содержится в экземпляре «foo», но не связан с ним родительским/дочерним. На самом деле у меня есть много различных классов «бар», которые «foo» имеет в массиве, каждый из которых делает что-то отличное от $ id, прежде чем хочет передать его функции «magic_bullet» для конечного результата, поэтому запрет структуры изменение отношений класса, можно ли получить доступ к методу экземпляра «контейнер»?

ответ

4

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

Предполагая, 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); 
+0

Блестящий! Это работает для моей настройки, помимо других предложений по добавлению указателя на экземпляр foo для экземпляра бара, потому что, предполагая множество экземпляров «bar», я не хочу, чтобы COPIES экземпляра foo внутри экземпляра бара (дополнительное использование памяти, плюс если исходный экземпляр $ test изменит что-то, что изменило поведение 'magic_bullet', все копии будут устаревшими), я хочу СПРАВОЧНИК (' $ this-> pointer_to_foo = &$foo; ', а не' $ this-> pointer_to_foo = $ foo '). – MidnightLightning

+0

Учитывая, что вы работаете с PHP5 (вы, если используете __construct как конструктор), не должно быть необходимости в знаке & sign: по умолчанию передаются объекты по ссылке –

+0

Ха-ха, я не знаю, как я пропустил стиль PHP 5 конструкторы, я просто отменил использование «var» и отсутствие модификаторов доступа/видимости в методах. @MidnightLightning, если вы на самом деле используете PHP 5, Pascal MARTIN верен - вам не нужен ссылочный оператор. Извините за любую путаницу, которую я создал. –

0

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

(ну, может быть, (вероятно, не) работать с отражением ... Я должен попробовать, что один день ^^)

EDIT: Подумав немного об этом: вы могли бы, в классе бар, держите указатель на 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) 

Таким образом, можно сделать ... Если изменить код немного ;-)


Edit 2: хо, zombat бить мне это, кажется :-(

4

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

Я бы предположил, что вместо того, чтобы напрямую устанавливать свойство $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); 
0

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

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

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

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

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

1

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

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

Отлично! Да, основываясь на том, что я дал, со Static Method или Singlton решила бы получить «magic_bullet» для всех. Но на самом деле существует более одной функции, которую «foo» имеет, что я хочу, чтобы «бар» получал доступ, и вместо того, чтобы сделать все из них статичным, я пойду с помощью указателя из другого ответа. – MidnightLightning

+0

Если все ему не нужен доступ к барам ... тогда синглтон может быть лучшей идеей. Затем вы сделали бы что-то вроде Foo :: getInstance() -> any_of_your_functions ($ vars); – Mez

Смежные вопросы