2009-08-06 15 views
8

Biorąc pod uwagę następujących w PHP:Odsyłacz do metody obiektu kontenerowego w 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); 

Zastanawiam się, czy to możliwe, że klasa „bar” do wywołania „magiczny” metodę klasy „foo”. Instancja "bar" jest zawarta w instancji "foo", ale nie znajduje się w relacji rodzic/dziecko z nią. W rzeczywistości mam wiele różnych klas "bar", które "foo" ma w tablicy, każda robi coś innego niż $ id, zanim chce przekazać ją do funkcji "magic_bullet" dla wyniku końcowego, więc nie ma struktury zmiana relacji klasowych, czy możliwy jest dostęp do metody instancji "kontenera"?

Odpowiedz

4

Musisz zmodyfikować swój kod, aby zapewnić związek. w języku OOP-speak, nazywamy to aggregation.

Zakładając PHP 4, a pomysł z „tablicą barów”

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

Genialny! To działa dla mojej instalacji, powyżej innych sugestii dodawania wskaźnika do instancji foo dla instancji paska, ponieważ zakładając wiele instancji "słupkowych", nie chcę mieć COPIES instancji foo wewnątrz instancji paska (dodatkowe użycie pamięci, plus jeśli oryginalna instancja testowa $ zmieni coś, co zmodyfikowało zachowanie 'magic_bullet', wszystkie kopie byłyby nieaktualne), chcę REFERENCJĘ (' $ this-> pointer_to_foo = &$foo; ', a nie' $ this-> pointer_to_foo = $ foo '). – MidnightLightning

+0

Biorąc pod uwagę, że pracujesz z PHP5 (jesteś, jeśli używasz __construct jako konstruktora), nie powinno być potrzeby znaku &: obiekty są przekazywane domyślnie przez odniesienie –

+0

Haha, nie wiem jak przeoczyłem styl PHP 5 konstruktorów, właśnie wykluczyłem użycie 'var' oraz brak modyfikatorów dostępu/widoczności na metodach. @MidnightLightning, jeśli faktycznie używasz PHP 5, Pascal MARTIN jest poprawny - nie potrzebujesz operatora referencyjnego. Przepraszam za wszelkie zamieszanie, które stworzyłem. –

0

You instancji $bar instancji, wewnątrz Foo, nie ma sposobu, aby dowiedzieć się, co zawiera klasa; więc nie ma sposobu na wywołanie tej metody.

(No, może (prawdopodobnie nie) działa z refleksji ... powinienem spróbować że jeden dzień ^^)

EDIT: myśleć trochę o nim: Możesz, wewnątrz klasy bar, trzymaj wskaźnik na foo; trochę tak:

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

Uwaga Użyłem method_exists jako zabezpieczenia.

a dostaniesz:

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) 

Tak, można to zrobić ... Jeśli zmodyfikować kod trochę ;-)


Edit 2: ho, zombat bicie ja do niej, wydaje :-(

4

nie, to nie jest możliwe, ponieważ nie ma żadnego związku z definicją.

Proponuję, aby zamiast ustawiać bezpośrednio właściwość $test->bar, użyjesz ustawiającego i możesz ustanowić relację w ten sposób. Będziesz także musiał dodać właściwość container do klasy bar. Klasa wewnętrzna foo:

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

Umożliwia ustawienie relacji między obiektami. Teraz zmienić funkcję bar::target($id) do:

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

Powinieneś być w stanie to zrobić teraz:

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

Masz kilka opcji tutaj. Polecam, aby nie iść na globalną trasę.

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

Będzie to działać, jeśli następnie zostanie zapisany test $ w konstruktorze słupkowym. Można również:

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

... i użyć podanego obiektu testowego w metodzie celowania baru().

1

to wygląda dla mnie (choć tylko na podstawie kodu masz pokazanego!) Być idealnym przypadku statycznego Metoda ...

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

Albo, jeśli istnieje tylko jeden obiekt "Foo" - może wzór Singleton Design?

+0

Excellent! Tak, opierając się na tym, co dałem, skorzystanie z metody statycznej lub Singlton rozwiązałoby problem "magic_bullet" dla wszystkich. Ale w rzeczywistości istnieje więcej niż jedna funkcja, której "foo" ma, że ​​chcę "bar", aby uzyskać dostęp, i zamiast sprawić, by wszystkie stały się statyczne, pójdę z rozwiązaniem wskaźnika z innej odpowiedzi – MidnightLightning

+0

Jeśli rzeczy w nie potrzebuje dostępu do barów ... wtedy singleton może być najlepszym pomysłem. Zrobiłbyś wtedy coś takiego jak Foo :: getInstance() -> any_of_your_functions ($ vars); – Mez

Powiązane problemy