Множественное наследование в PHP - PullRequest
97 голосов
/ 18 сентября 2008

Я ищу хороший, чистый способ обойти тот факт, что PHP5 все еще не поддерживает множественное наследование. Вот иерархия классов:

Сообщение * * 1003 - TextMessage
-------- InvitationTextMessage
- EmailMessage
-------- InvitationEmailMessage

Два типа классов Invitation * имеют много общего; Я хотел бы иметь общий родительский класс, Приглашение, от которого они оба унаследуют. К сожалению, они также имеют много общего со своими нынешними предками ... TextMessage и EmailMessage. Классическое стремление к множественному наследованию здесь.

Какой самый легкий подход для решения проблемы?

Спасибо!

Ответы [ 11 ]

142 голосов
/ 18 сентября 2008

Алекс, в большинстве случаев вам нужно множественное наследование - это сигнал, что структура вашего объекта несколько неверна. В ситуации, которую вы обрисовали, я вижу, что у вас классовая ответственность слишком широка. Если Message является частью бизнес-модели приложения, он не должен заботиться о визуализации вывода. Вместо этого вы можете разделить ответственность и использовать MessageDispatcher, который отправляет сообщение, переданное с использованием текстового или html-интерфейса. Я не знаю ваш код, но позвольте мне смоделировать его следующим образом:

$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <jdoe@yahoo.com>';
$m->to = 'Random Hacker <rh@gmail.com>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');

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

Таким образом, вы можете добавить некоторую специализацию в класс Message:

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

Обратите внимание, что MessageDispatcher будет принимать решение о том, отправлять ли в виде HTML или обычного текста, в зависимости от свойства type в переданном объекте Message.

// 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");
    }
}

Подводя итог, ответственность распределяется между двумя классами. Конфигурация сообщения выполняется в классе InvitationHTMLMessage / InvitationTextMessage, а алгоритм отправки делегируется диспетчеру. Это называется паттерном стратегии, вы можете прочитать больше об этом здесь .

14 голосов
/ 18 сентября 2008

Может быть, вы можете заменить отношение «есть» на отношение «есть»? Приглашение может иметь сообщение, но оно не обязательно должно быть «есть». Приглашение, например может быть подтверждено, что не очень хорошо сочетается с моделью сообщений.

Ищите «состав против наследования», если вам нужно узнать об этом больше.

9 голосов
/ 22 марта 2012

Если я могу процитировать Фила в этой теме ...

PHP, как и Java, не поддерживает множественное наследование.

Выход в PHP 5.4 будет черт , которые пытаются найти решение к этой проблеме.

А пока тебе лучше переосмыслить дизайн своего класса. Вы может реализовать несколько интерфейсов, если вы после расширенного API для ваши занятия.

И Крис ....

PHP на самом деле не поддерживает множественное наследование, но есть некоторые (несколько грязный) способы его реализации. Проверьте этот URL для некоторых Примеры:

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

Думаю, у них обоих были полезные ссылки. Не могу дождаться, чтобы опробовать черты или, возможно, некоторые миксины ...

6 голосов
/ 18 сентября 2008

В платформе Symfony есть плагин mixin для этого , вы можете попробовать его - даже просто для идей, если не использовать его.

Ответ «шаблон проектирования» состоит в том, чтобы разделить общую функциональность на отдельный компонент и создавать во время выполнения. Подумайте о способе абстрагирования функциональности Приглашения как класса, который каким-либо образом связан с вашими классами сообщений, кроме наследования.

4 голосов
/ 15 ноября 2012

Я использую черты в PHP 5.4 как способ решения этой проблемы. http://php.net/manual/en/language.oop5.traits.php

Это допускает классическое наследование с помощью расширений, но также дает возможность поместить общую функциональность и свойства в «черту». Как сказано в руководстве:

Черты - это механизм повторного использования кода в языках с одним наследованием, таких как PHP. Черта предназначена для уменьшения некоторых ограничений одиночного наследования, позволяя разработчику свободно повторно использовать наборы методов в нескольких независимых классах, находящихся в разных иерархиях классов.

3 голосов
/ 20 октября 2010

Это и вопрос, и решение ....

А как насчет магических методов _ call (), _get (), __set ()? Я еще не тестировал это решение, но что если вы сделаете класс multiInherit. Защищенная переменная в дочернем классе может содержать массив классов для наследования. Конструктор в мультиинтерфейсном классе может создавать экземпляры каждого из наследуемых классов и связывать их с частным свойством, скажем _ext. Метод __call () может использовать функцию method_exists () для каждого из классов в массиве _ext, чтобы найти правильный метод для вызова. __get () и __set могут быть использованы для поиска внутренних свойств, или, если вы эксперт со ссылками, вы можете сделать свойства дочернего класса и унаследованных классов ссылками на одни и те же данные. Множественное наследование вашего объекта будет прозрачным для кода, использующего эти объекты. Кроме того, внутренние объекты могут обращаться к наследуемым объектам напрямую, если это необходимо, при условии, что массив _ext индексируется по имени класса. Я предполагал создать этот суперкласс и еще не реализовал его, так как считаю, что если он сработает, то это может привести к развитию некоторых вредных привычек программирования.

3 голосов
/ 18 сентября 2008

Похоже, что шаблон декоратора может подойти, но трудно сказать без подробностей.

1 голос
/ 18 сентября 2008

У меня есть пара вопросов, чтобы уточнить, что вы делаете:

1) Содержит ли ваш объект сообщения просто сообщение, например тело, получатель, график времени? 2) Что вы собираетесь делать с вашим объектом приглашения? Нужно ли это обрабатывать специально по сравнению с EmailMessage? 3) Если да, то, что такого особенного в этом? 4) Если это так, то почему типы сообщений должны обрабатываться по-разному для приглашения? 5) Что если вы хотите отправить приветственное сообщение или сообщение ОК? Они тоже новые объекты?

Звучит так, будто вы пытаетесь объединить слишком много функций в набор объектов, которые должны касаться только содержания сообщения, а не способа его обработки. Для меня, как видите, нет разницы между приглашением или стандартным сообщением. Если приглашение требует специальной обработки, то это означает логику приложения, а не тип сообщения.

Например: система, которую я построил, имела общий объект сообщения, который был расширен на SMS, электронную почту и другие типы сообщений. Однако: они не были расширены - сообщение с приглашением было просто предопределенным текстом для отправки через сообщение типа Email. Конкретная заявка на приглашение будет связана с проверкой и другими требованиями для приглашения. В конце концов, все, что вы хотите сделать, это отправить сообщение X получателю Y, который должен быть отдельной системой.

0 голосов
/ 24 мая 2012

Как насчет класса Приглашения прямо под классом Сообщения?

так иерархия идет:

Сообщение * * 1005 --- Приглашение
------ TextMessage
------ EmailMessage

А в классе Приглашения добавьте функциональность, которая была в InvitationTextMessage и InvitationEmailMessage.

Я знаю, что Приглашение на самом деле не тип сообщения, это скорее функциональность сообщения. Так что я не уверен, хороший ли это дизайн ОО или нет.

0 голосов
/ 18 сентября 2008

PHP поддерживает интерфейсы. Это может быть хорошей ставкой, в зависимости от ваших сценариев использования.

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