Dziedziczenie wielokrotne w PHP

Szukam dobrego, czystego sposobu na obejście faktu, że PHP5 nadal nie obsługuje dziedziczenia wielokrotnego. Oto hierarchia klas:

Wiadomość
-- TextMessage
-------- InvitationTextMessage
-- EmailMessage
-------- InvitationEmailMessage

Dwa rodzaje zaproszeń* mają ze sobą wiele wspólnego; chciałbym mieć wspólną klasę rodzica, zaproszenie, po której obie odziedziczyłyby. Niestety, mają też wiele wspólnego z ich obecnymi przodkami... TextMessage i EmailMessage. Klasyczne pragnienie wielokrotnego dziedziczenia tutaj.

Jakie jest najbardziej lekkie podejście do rozwiązania problemu?

Dzięki!

Author: Alex Weinstein, 2008-09-18

11 answers

Alex, większość przypadków, gdy potrzebujesz dziedziczenia wielokrotnego, jest sygnałem, że Twoja struktura obiektu jest nieco nieprawidłowa. W sytuacji, którą opisałeś, widzę, że masz zbyt szeroką odpowiedzialność klasową. Jeśli wiadomość jest częścią modelu biznesowego aplikacji, nie powinna dbać o wyniki renderowania. Zamiast tego możesz podzielić odpowiedzialność i użyć MessageDispatcher, który wysyła wiadomość przekazaną za pomocą backendu tekstowego lub html. Nie znam twojego kodu, ale pozwól mi to zasymulować. sposób:

$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <[email protected]>';
$m->to = 'Random Hacker <[email protected]>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');

$d = new MessageDispatcher();
$d->dispatch($m);

W ten sposób możesz dodać specjalizację do klasy wiadomości:

$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor

$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);

Zauważ, że MessageDispatcher podejmie decyzję, czy wysłać jako HTML czy zwykły tekst w zależności od właściwości type w przekazanym obiekcie wiadomości.

// in MessageDispatcher class
public function dispatch(Message $m) {
    if ($m->type == 'text/plain') {
        $this->sendAsText($m);
    } elseif ($m->type == 'text/html') {
        $this->sendAsHTML($m);
    } else {
        throw new Exception("MIME type {$m->type} not supported");
    }
}

Podsumowując, odpowiedzialność jest podzielona między dwie klasy. Konfiguracja wiadomości odbywa się w klasie InvitationHTMLMessage/InvitationTextMessage, a algorytm wysyłania jest delegowany do dyspozytora. To się nazywa wzór strategii, można przeczytać więcej na ten temat tutaj.

 141
Author: Michał Rudnicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 11:13:24

Może możesz zastąpić relację 'is-a' relacją 'has-a'? Zaproszenie może mieć wiadomość, ale niekoniecznie musi być wiadomością "is-a". Zaproszenie może zostać potwierdzone, co nie pasuje do modelu wiadomości.

Wyszukaj 'skład a dziedziczenie', jeśli chcesz wiedzieć więcej na ten temat.

 14
Author: Matthias Kestenholz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 08:45:27

Jeśli mogę zacytować Phila w tym wątku ...

PHP, podobnie jak Java, nie obsługuje dziedziczenia wielokrotnego.

Coming in PHP 5.4 will be Cechy które starają się zapewnić rozwiązanie do tego problemu.

W międzyczasie, powinieneś przemyśleć swój projekt klasowy. Ty może zaimplementować wiele interfejsów, jeśli szukasz rozszerzonego API do twoje zajęcia.

I Chris....

PHP doesn ' t really obsługa wielu dziedziczeń, ale są pewne (nieco niechlujne) sposoby jej wdrożenia. Sprawdź ten adres URL dla niektórych przykłady:

Http://www.jasny.net/articles/how-i-php-multiple-inheritance/

Myślałem, że obaj mają przydatne linki. Nie mogę się doczekać, aby wypróbować cechy lub może kilka mixins...

 7
Author: Simon East,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:17

Framework Symfony posiada wtyczkę mixin do tego, możesz chcieć to sprawdzić - nawet dla pomysłów, jeśli nie chcesz go używać.

Odpowiedź "wzorzec projektowy" polega na abstrakcji współdzielonej funkcjonalności do osobnego komponentu i komponowaniu w czasie wykonywania. Pomyśl o sposobie wyodrębnienia funkcji zaproszenia jako klasy, która zostanie powiązana z klasami wiadomości w inny sposób niż dziedziczenie.

 6
Author: joelhardi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 08:43:24
 3
Author: danio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 08:43:10

Jest to zarówno pytanie, jak i rozwiązanie....

A co z magicznymi metodami _call (), _get (), _ _ set ()? Jeszcze nie testowałem tego rozwiązania, ale co jeśli zrobisz klasę multiInherit. Chroniona zmienna w klasie potomnej może zawierać tablicę klas do dziedziczenia. Konstruktor w klasie multi-interface może tworzyć instancje każdej z klas, które są dziedziczone i łączyć je z prywatną własnością, np. _ext. Metoda _ _ call() może używać metoda method_exists () działa na każdej z klas w tablicy _ext w celu zlokalizowania właściwej metody do wywołania. __get () I _ _ set mogą być użyte do zlokalizowania wewnętrznych właściwości, lub jeśli twój ekspert z referencjami, możesz sprawić, że właściwości klasy potomnej i odziedziczonych klas będą referencjami do tych samych danych. Wielokrotne dziedziczenie obiektu byłoby przezroczyste dla kodu używającego tych obiektów. Ponadto wewnętrzne obiekty mogą uzyskać bezpośredni dostęp do odziedziczonych obiektów w razie potrzeby tak długo, jak długo _ext tablica jest indeksowana przez nazwę klasy. Wyobrażałem sobie stworzenie tej super klasy i jeszcze go nie zaimplementowałem, ponieważ uważam, że jeśli to zadziała, może to prowadzić do rozwoju niektórych złych nawyków programistycznych.

 3
Author: Ralph Ritoch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-20 07:52:24

Używam traits w PHP 5.4 jako sposobu rozwiązania tego problemu. http://php.net/manual/en/language.oop5.traits.php

Pozwala to na klasyczne dziedziczenie z rozszerzeniami, ale daje również możliwość umieszczania wspólnych funkcji i właściwości w 'cechach'. Jak mówi instrukcja:

Traits jest mechanizmem ponownego użycia kodu w językach dziedziczenia, takich jak PHP. Cecha ma na celu zmniejszenie niektórych ograniczeń pojedynczego dziedziczenia poprzez umożliwienie deweloperowi ponownego użycia zestawy metod dowolnie w kilku niezależnych klasach żyjących w różnych hierarchiach klasowych.

 3
Author: MatthewPearson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-15 12:02:11

Mam kilka pytań, aby wyjaśnić, co robisz:

1) Czy twój obiekt wiadomości just zawiera wiadomość np. ciało, odbiorca, harmonogram czasu? 2) co zamierzasz zrobić ze swoim zaproszeniem? Czy musi być traktowany specjalnie w porównaniu do wiadomości e-mail? 3) Jeśli tak, to co jest w nim takiego wyjątkowego? 4) Jeśli tak jest, dlaczego typy wiadomości wymagają innej obsługi dla zaproszenia? 5) co jeśli chcesz wysłać wiadomość powitalną lub OK wiadomość? Czy to też nowe obiekty?

Brzmi to tak, jakbyś próbował połączyć zbyt wiele funkcji w zestaw obiektów, które powinny zajmować się tylko przechowywaniem treści wiadomości - a nie tym, jak powinny być obsługiwane. Dla mnie nie ma różnicy między zaproszeniem a standardową wiadomością. Jeśli zaproszenie wymaga specjalnej obsługi, oznacza to logikę aplikacji, a nie typ wiadomości.

Na przykład: zbudowany przeze mnie system miał współdzielony obiekt wiadomości bazowej, który został rozszerzony na SMS, e-mail i inne typy wiadomości. Jednak: nie były one dalej rozszerzane - wiadomość z zaproszeniem była po prostu wstępnie zdefiniowanym tekstem, który miał być wysłany za pomocą wiadomości typu Email. Wniosek o specjalne zaproszenie dotyczyłby walidacji i innych wymogów dotyczących zaproszenia. Po tym wszystkim, wszystko, co chcesz zrobić, to wysłać wiadomość X do odbiorcy Y, który powinien być dyskretny system sam w sobie.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 14:13:19

Ten sam problem jak Java. Spróbuj użyć interfejsów z abstrakcyjnymi funkcjami do rozwiązania tego problemu

 0
Author: DeeCee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 08:45:27

PHP obsługuje interfejsy. To może być dobry zakład, w zależności od przypadków użycia.

 0
Author: Cheekysoft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 17:23:08

A może Klasa zaproszeń tuż pod klasą wiadomości?

Więc hierarchia idzie:

Wiadomość
--- Zaproszenie
------ TextMessage
------ EmailMessage

I w klasie Invitationtextmessage dodajemy funkcjonalność, która była w InvitationTextMessage i InvitationEmailMessage.

Wiem, że zaproszenie nie jest tak naprawdę rodzajem wiadomości, jest bardziej funkcjonalnością wiadomości. Więc nie jestem pewien, czy to dobry projekt OO, czy nie.

 -1
Author: nube,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-23 21:02:12