Я пытаюсь понять, как использование интерфейсов дает мне многократное наследование, поскольку я искал поисковые запросы.
class A { function do1(){} function do2(){} function do3(){} } class B extends A { function do4(){} function do5(){} function do6(){} } class C extends B { }
В приведенном выше примере класс C имеет все методы из классов A и B. Однако класс B также имеет все методы класса A, что не является необходимым.
Мои поиски пришли к использованию интерфейсов для решения этой проблемы путем перемещения методов в класс и создания интерфейсов, как показано ниже.
interface A { function do1(); function do2(); function do3(); } interface B { function do4(); function do5(); function do6(); } class C implements A, B { function do1(){} function do2(){} function do3(){} function do4(){} function do5(){} function do6(){} }
Я действительно не вижу, как это решает проблему, потому что весь код находится в новом классе. Если бы я просто хотел использовать класс A, как изначально, мне пришлось бы создать новый класс, реализующий интерфейс A и скопировавший тот же код в новый класс.
Есть что-то, что мне не хватает?
PHP не имеет множественного наследования. Если у вас есть PHP 5.4, вы можете использовать черты, чтобы, по крайней мере, избегать того, чтобы каждый класс копировал код.
interface A { public function do1(); public function do2(); public function do3(); } trait Alike { public function do1() { } public function do2() { } public function do3() { } } interface B { public function do4(); public function do5(); public function do6(); } trait Blike { public function do4() { } public function do5() { } public function do6() { } } class C implements A, B { use Alike, Blike; } class D implements A { use Alike; // You can even "override" methods defined in a trait public function do2() { } }
Однако обратите внимание, что вам нужно как реализовать интерфейс, так и использовать его (или, конечно же, обеспечить собственную реализацию). И C и D вообще не связаны, за исключением как реализации интерфейса A. Черты в основном просто копируют и вставляют на уровне интерпретатора и не влияют на наследование.
Первое, что нужно знать о интерфейсах, – это то, что они НЕ используются для наследования. Это очень важно понять. Если вы пытаетесь заставить несколько классов использовать один и тот же конкретный код, для этого не нужен интерфейс.
Второе, что нужно понять, – это разница между кодом клиента и кодом обслуживания.
Клиентский код по существу является «последним шагом» в последовательности запросов на данные. Контроллер или представление в MVC можно считать кодом клиента. Модель, между тем, может считаться служебным кодом.
Интерфейсы предназначены для клиентского кода для обеспечения согласованности типов данных, которые он получает от служб. Или другой способ подумать об этом – интерфейсы – это способ для служб, чтобы убедиться, что они будут совместимы с запросом с клиентского кода. Это все, что они делают. Они буквально предоставляют интерфейс, с помощью которого осуществляется доступ к данным, а не реализация, которую могут использовать несколько классов.
Чтобы дать вам конкретный пример:
Код клиента – класс ProfileViewController для профиля форума пользователя
class ProfileViewController { public function showProfile(User $user) { $user->getProfile(); } }
Код службы – модель пользователя, которая извлекает данные и передает их клиенту, который запрашивает его.
class User { public function getProfile() { $profile = Do some SQL query here or something return $profile; } }
Теперь предположим, что позже вы решили разбить пользователей на членов, администраторов, рефери, модераторов, писателей, редакторов и т. Д., И каждый из них имеет свой собственный уникальный тип профиля. (например, собственный пользовательский запрос или данные или что у вас есть)
В настоящее время здесь есть две проблемы:
1 легко решить с помощью абстрактных классов и методов (или через интерфейсы). 2 сначала звучит легко, потому что вы можете просто сделать Модераторы, Администраторы и Члены всеми подклассами базового класса User.
Но тогда, что происходит, когда по дороге, помимо профилей USER, вы хотите иметь общие профили для вещей. Возможно, вы хотите показать профили спортивных игроков или даже профили знаменитостей. Они не являются пользователями, но у них все еще есть страницы профилей / подробностей.
Поскольку они не являются пользователями, может не иметь смысла рассматривать их подклассы пользователя.
Так что теперь вы немного застряли. showProfile () должен иметь возможность принимать больше, чем просто объект User. На самом деле, вы не знаете, какой тип объекта вы в конечном итоге захотите пройти там. Но в то же время, поскольку вы всегда хотите захватить $ user-> getProfile (), все, что вы передаете, должно быть достаточно общим для передачи, и реализовать конкретный метод getProfile ().
Решение? Интерфейсы !!!!!
Сначала некоторый код обслуживания
// First define an interface for ANY service object that will have a profile interface IHasProfile { public function getProfile(); } // Next, define the class for an object that should have a profile. I'll do a bunch for the sake of an example... class User implements IHasProfile { public function getProfile() { $profile = Your unique user profile query here return $profile; } } class Celebrity implements IHasProfile { public function getProfile() { $profile = Your unique celebrity profile query here return $profile; } } class Car implements IHasProfile { public function getProfile() { $profile = Your unique vehicle profile query goes here return $profile; } }
Затем клиентский код, который будет использовать его
class ProfileViewController { public function showProfile(IHasProfile $obj) { $obj->getProfile(); } }
И вот он у вас есть. showProfile () теперь полностью абстрагирован, что ему все равно, какой объект он получает, он только заботится о том, чтобы объект имел общедоступный метод getProfile (). Итак, теперь вы можете создавать новые типы объектов в своем сердце, и если они предназначены для создания профилей, вы можете просто дать им «реализует IHasProfile», и они автоматически будут работать с showProfile ().
Вид надуманного примера, но он должен проиллюстрировать, по крайней мере, концепцию интерфейсов.
Конечно, вы могли бы просто «лениться» и вообще не прибегать к типу объекта и, таким образом, позволять ЛЮБОЙ объект проходить. Но это отдельная тема целиком;)
Множественное наследование возможно только для интерфейсов!
такой как мой вывод для него:
php > interface A{}; php > interface B{}; php > interface C extends A,B{}; php > class D implements C{}; php > $d = new D(); php > echo ($d instanceof A); 1
Для lulz я пытаюсь создать класс E, который расширяет классы D и stdclass и получает ошибку!
php > class E extends D, stdclass{}; PHP Parse error: syntax error, unexpected ',', expecting '{' in php shell code on line 1 Parse error: syntax error, unexpected ',', expecting '{' in php shell code on line 1
Множественное наследование невозможно в PHP, например, во многих поддерживаемых OOP
языках
См. Аналогичную тему здесь . Тема находится в AS3
но дает вам ответ.
Чтобы ответить, в частности, на решение с использованием интерфейсов, ответили в том же сообщении здесь
Надеюсь это поможет
Как сказано здесь @tonicospinelli, кажется, что на деле PHP допускает взаимное наследование интерфейса , но неясно объяснено, просто приведен пример
Способ множественного наследования, хотя внутри PHP проходит, используя Traits, что реализует интерфейсы .
Когда вы объявляете класс, реализующий «мультиинтерфейс» (1), вы можете использовать уже определенные черты, чтобы гарантировать наследование, хорошо выполненное.
(1) : Говоря «multi-interface», я имею в виду класс, реализующий интерфейс, который простирается от нескольких других интерфейсов