Можно ли расширить класс, используя более 1 класс в PHP?

Если у меня есть несколько классов с функциями, которые мне нужны, но я хочу хранить отдельно для организации, могу ли я расширить класс для обоих?

т.е. class a extends b extends c

edit: Я знаю, как продлить классы по одному, но я ищу метод для немедленного расширения класса с использованием нескольких базовых классов – AFAIK, вы не можете сделать это на PHP, но должны быть пути вокруг него, не прибегая к class c extends b , class b extends a

Отвечая на ваше редактирование:

Если вы действительно хотите подделать множественное наследование, вы можете использовать магическую функцию __call ().

Это уродливо, хотя оно работает с точки зрения пользователя класса А:

 class B { public function method_from_b($s) { echo $s; } } class C { public function method_from_c($s) { echo $s; } } class A extends B { private $c; public function __construct() { $this->c = new C; } // fake "extends C" using magic function public function __call($method, $args) { $this->c->$method($args[0]); } } $a = new A; $a->method_from_b("abc"); $a->method_from_c("def"); 

Печать "abcdef"

У вас не может быть класса, который расширяет два базовых класса. Вы не могли этого сделать.

 // this is NOT allowed (for all you google speeders) Matron extends Nurse, HumanEntity 

Однако вы можете иметь иерархию следующим образом …

 Matron extends Nurse Consultant extends Doctor Nurse extends HumanEntity Doctor extends HumanEntity HumanEntity extends DatabaseTable DatabaseTable extends AbstractTable 

и так далее.

Вы можете использовать черты, которые, надеюсь, будут доступны из PHP 5.4.

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

Они признаны за их потенциал в поддержке лучшего состава и повторного использования, следовательно, их интеграции в более новые версии языков, таких как Perl 6, Squeak, Scala, Slate и Fortress. Черты также были перенесены на Java и C #.

Дополнительная информация: https://wiki.php.net/rfc/traits

Классы не предназначены только для коллекций методов. Предполагается, что класс представляет абстрактную концепцию, состоящую из состояния (полей) и поведения (методов), которое изменяет состояние. Использование наследования только для того, чтобы получить желаемое поведение, похоже на плохой дизайн OO, и именно по той причине, почему многие языки запрещают множественное наследование: чтобы предотвратить «наследование спагетти», то есть расширение 3 класса, потому что каждый из них имеет необходимый вам метод и в конечном итоге класс, который наследует 100 методов и 20 полей, но только когда-либо использует 5 из них.

Полагаю, что скоро планируется добавить микширование.

Но до тех пор идите с принятым ответом. Вы можете абстрагироваться от этого немного, чтобы создать «расширяемый» класс:

 class Extendable{ private $extender=array(); public function addExtender(Extender $obj){ $this->extenders[] = $obj; $obj->setExtendee($this); } public function __call($name, $params){ foreach($this->extenders as $extender){ //do reflection to see if extender has this method with this argument count if (method_exists($extender, $name)){ return call_user_func_array(array($extender, $name), $params); } } } } $foo = new Extendable(); $foo->addExtender(new OtherClass()); $foo->other_class_method(); 

Обратите внимание, что в этой модели «OtherClass» получает «знать» около $ foo. Для настройки этого отношения у другогоClass должна быть открытая функция, называемая setExtendee. Затем, если его методы вызывают из $ foo, он может получить доступ к $ foo изнутри. Однако он не получит доступ к каким-либо частным / защищенным методам / переменным, например, к реальному расширенному классу.

Я прочитал несколько статей, обескураживающих наследование в проектах (в отличие от библиотек / фреймворков) и поощряя программировать интерфейсы agaisnt, а не от реализаций.
Они также выступают за ОО по составу: если вам нужны функции в классах a и b, сделайте c имеющими члены / поля этого типа:

 class C { private $a, $b; public function __construct($x, $y) { $this->a = new A(42, $x); $this->b = new B($y); } protected function DoSomething() { $this->a->Act(); $this->b->Do(); } } 

В настоящее время принятый ответ @Franck будет работать, но на самом деле это не множественное наследование, а дочерний экземпляр класса, определенного вне области видимости, также есть стенограмма __call() – рассмотрим возможность использования метода $this->childInstance->method(args) везде, где вам нужен метод класса ExternalClass в расширенном классе.

Точный ответ

Нет, вы не можете, соответственно, не очень, так как руководство по extends ключевого слова говорит:

Расширенный класс всегда зависит от одного базового класса, т. Е. Множественное наследование не поддерживается.

Реальный ответ

Однако, как предположил @adam, это НЕ запрещает вам использовать множественное иерархическое наследование.

Вы МОЖЕТЕ расширить один класс, другой, другой с другим и так далее …

Настолько довольно простой пример на этом:

 class firstInheritance{} class secondInheritance extends firstInheritance{} class someFinalClass extends secondInheritance{} //...and so on... 

Важная заметка

Как вы могли заметить, вы можете выполнять только несколько (2+) intehritance по иерархии, если у вас есть контроль над всеми классами, включенными в процесс, – это означает, что вы не можете применять это решение, например, со встроенными классами или с классами, которые вы просто не можете редактировать – если вы хотите это сделать, вы останетесь с решением @Franck – дочерними экземплярами.

… И, наконец, пример с некоторым выходом:

 class A{ function a_hi(){ echo "I am a of A".PHP_EOL."<br>".PHP_EOL; } } class B extends A{ function b_hi(){ echo "I am b of B".PHP_EOL."<br>".PHP_EOL; } } class C extends B{ function c_hi(){ echo "I am c of C".PHP_EOL."<br>".PHP_EOL; } } $myTestInstance = new C(); $myTestInstance->a_hi(); $myTestInstance->b_hi(); $myTestInstance->c_hi(); 

Какие результаты

 I am a of AI am b of BI am c of C 
 <?php // what if we want to extend more then one class? Abstract class ExtensionBridge { // array containing all the extended classes private $_exts = array(); public $_this; function __construct(){$_this = $this;} public function addExt($object) { $this->_exts[]=$object; } public function __get($varname) { foreach($this->_exts as $ext) { if(property_exists($ext,$varname)) return $ext->$varname; } } public function __call($method,$args) { foreach($this->_exts as $ext) { if(method_exists($ext,$method)) return call_user_method_array($method,$ext,$args); } throw new Exception("This Method {$method} doesn't exists"); } } class Ext1{ private $name=""; private $id=""; public function setID($id){$this->id = $id;} public function setName($name){$this->name = $name;} public function getID(){return $this->id;} public function getName(){return $this->name;} } class Ext2{ private $address=""; private $country=""; public function setAddress($address){$this->address = $address;} public function setCountry($country){$this->country = $country;} public function getAddress(){return $this->address;} public function getCountry(){return $this->country;} } class Extender extends ExtensionBridge { function __construct() { parent::addExt(new Ext1()); parent::addExt(new Ext2()); } public function __toString() { return $this->getName().', from: '.$this->getCountry(); } } $o = new Extender(); $o->setName("fabio"); $o->setCountry("brazil"); echo $o; ?> 

Я просто решил проблему с множественным наследованием:

 class Session { public $username; } class MyServiceResponsetype { protected $only_avaliable_in_response; } class SessionResponse extends MyServiceResponsetype { /** has shared $only_avaliable_in_response */ public $session; public function __construct(Session $session) { $this->session = $session; } } 

Таким образом, я могу управлять сеансом внутри SessionResponse, который расширяет MyServiceResponsetype, который все еще способен обрабатывать сеанс сам по себе.

Вы можете сделать это, используя Traits в PHP, который был объявлен как PHP 5.4

Вот вам быстрый учебник, http://culttt.com/2014/06/25/php-traits/

На уровне интерфейса, похоже, работает несколько наследований. Я сделал тест на php 5.6.1.

Вот рабочий код:

 <?php interface Animal { public function sayHello(); } interface HairyThing { public function plush(); } interface Dog extends Animal, HairyThing { public function bark(); } class Puppy implements Dog { public function bark() { echo "ouaf"; } public function sayHello() { echo "hello"; } public function plush() { echo "plush"; } } echo PHP_VERSION; // 5.6.1 $o = new Puppy(); $o->bark(); $o->plush(); $o->sayHello(); // displays: 5.6.16ouafplushhello 

Я не думал, что это возможно, но я наткнулся на исходный код SwiftMailer в классе Swift_Transport_IoBuffer, который имеет следующее определение:

 interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream 

Я еще не играл с этим, но я подумал, что это может быть интересно поделиться.

Использовать черты в качестве базовых классов. Затем используйте их в родительском классе. Расширьте его.

 trait business{ function sell(){ } function buy(){ } function collectMoney(){ } } trait human{ function think(){ } function speak(){ } } class BusinessPerson{ use business; use human; // If you have more traits bring more } class BusinessWoman extends BusinessPerson{ function getPregnant(){ } } $bw = new BusinessWoman(); $bw ->speak(); $bw->getPregnant(); 

Теперь деловая женщина логически унаследовала бизнес и человека;

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

Для некоторых примеров см. http://www.hudzilla.org/php/6_17_0.php .

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

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

Всегда хорошая идея – создать родительский класс с функциями … т. Е. Добавить эту функциональность к родительскому.

И «переместить» все классы, которые используют это иерархически вниз. Мне нужно – переписать функции, которые являются конкретными.

Если вы хотите проверить, является ли функция общедоступной, см. Эту тему: https://stackoverflow.com/a/4160928/2226755

И используйте метод call_user_func_array (…) для многих или не аргументов.

Как это :

 class B { public function method_from_b($s) { echo $s; } } class C { public function method_from_c($l, $l1, $l2) { echo $l.$l1.$l2; } } class A extends B { private $c; public function __construct() { $this->c = new C; } public function __call($method, $args) { if (method_exists($this->c, $method)) { $reflection = new ReflectionMethod($this->c, $method); if (!$reflection->isPublic()) { throw new RuntimeException("Call to not public method ".get_class($this)."::$method()"); } return call_user_func_array(array($this->c, $method), $args); } else { throw new RuntimeException("Call to undefined method ".get_class($this)."::$method()"); } } } $a = new A; $a->method_from_b("abc"); $a->method_from_c("d", "e", "f"); 

Одной из проблем PHP как языка программирования является то, что вы можете иметь только одно наследование. Это означает, что класс может наследовать только один класс.

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

Эта проблема может привести к классу, который имеет долгую семейную историю наследования, которая часто не имеет смысла.

В PHP 5.4 добавлена ​​новая функция языка, известная как «Черты». Трейт похож на Mixin, поскольку он позволяет смешивать классы Trait с существующим классом. Это означает, что вы можете уменьшить дублирование кода и получить преимущества, избегая при этом проблем с множественным наследованием.

Черты