Как многие из вас знают, PHP не поддерживает множественное наследование. То есть у производного класса может быть только один родительский. Но с помощью "магической" функции __call() его можно cэмулировать. Пример ниже - это расширенный паттерн примесь (mixin). Он также позволяет вызывать защищенные и скрытые методы из базовых классов.
<?php abstract class Inheritance { private $_inheritances = array(); public function __call($method, array $arguments = array()) { // Здесь мы можем перехватить вызовы методов. foreach ($this->_inheritances as $inheritance) { $inheritance->invoke($method, $arguments); } } public function invoke($method, $arguments) { if (is_callable(array($this, $method))) { return call_user_func_array(array($this, $method), $arguments); } } protected function _addInheritance(Inheritance $inheritance) { $this->_inheritances[get_class($inheritance)] = $inheritance; } }
Вот и все! Теперь можно использовать:
Сделаем два простейших класса Bird и Horse с несколькими методами:
<?php /** * первый базовый класс */ class Bird extends Inheritance { public function chirp() { echo "<br/>чирикаю..."; } public function fly() { echo "<br/>летаю ..."; } protected function _eat() { echo "<br/>ем червяков..."; } } /** * второй базовый класс */ class Horse extends Inheritance { public function whinny() { echo "<br/>ржу..."; } protected function _eat() { echo "<br/>ем сено..."; } }
Создадим новый класс Pegasus, который унаследует все методы от Bird и Horse. Унаследуем его от класса Inheritance и в конструкторе добавим оба базовык класса с помощью метода _addInheritance().
<?php class Pegasus extends Inheritance { public function __construct() { // привязываем базовые классы $this->_addInheritance(new Bird); $this->_addInheritance(new Horse); } public function eat() { // это работает и с защищенными методами $this->_eat(); } } $pegasus = new Pegasus; $pegasus->chirp(); $pegasus->fly(); $pegasus->whinny(); $pegasus->eat();
И вот на выходе:
chirp ..
fly ..
whinny ..
eat worms ..
eat hay ..


Спасибо, интересное применение :)
eat worms ..
eat hay ..
а весь прикол в том, что должен быть только один вызов. У нас же ж наследование.
111, А как система должна выбирать метод какого класса нужно запускать при пересечении имен?
111, Andrey, думаю не проблема переписать код таким образом, чтобы вызывался хоть первый из встретившихся, хоть последний, т.к. схему наследования реализуем мы сами.
Andrey, система не должна выбирать, по крайнере мере в том случае, когда вы используете классы сторонних разработчиков, иначе придется внимательно вникать их, и, возможно, переписывать некоторую их часть, т.е. переименовывать методы. Множественное наследование - не самая необходимая и безопасная(с т.з. конфликта имен) вещь. Во многих языках от этой практики отказались, так в Ruby, множественное наследование подменяется примесями (mixins), что вполне себя оправдывает и предоставляет практически все, что можно почерпнуть из множественного наследования. Интересно, можно ли реализовать подобие примесей средствами самого РНР?
Понравилось
Но вот на днях столкнулся с проблемкой
Есть например абтрактный класс модели и метод получения ссылки (obHref)ну и другие конечно)
Есть наследники модели для обработки во Front End приложении которые гененрируют на себя ссылки для FE пользователей определяя (obHref)
Потом появилась задача разработать не тривиальный интерфейс для Back End приложения (админки проще говоря)
Унаследовал все классы - BE модели от FE - так как там все необходимые мне методы. И столкнулся с проблемой. Во всех BE моделях ссылки для BE пользователей генерируются одинаково(obHref должен быть одинаков у всех). Но во всех FE моделях по разному.
Как переопределить метод (obHref) который бы вызывался из всех моделей BE и работал бы одинаково для каждой модели.. Сам не додумался и переопределил в каждой модели BE метод obHref одинаковым во всех моделях кодом... а моделей очень и очень не мало.
@andrey, а почему не перенести код obHref в родительскую для всех модель, а там где он индивидуальный - переопределять на свой?