
в чем разница между
есть прикольная библиотека, там все функции которые нужны, еще 5 ненужных и одной не хватает, взял унаследовал, нехватающую дописал, лишнее не учел в интерфейсе,
// прикольная библиотека
class A{
  public function b(){} //  (одна) ненужных
// все функции которые нужны
  public function c(){}
  public function d(){}
}
interface D{
  public function c();
  public function d();
  public function x();// и одной не хватает,
}
// решение наследованием
class B extends A implements D{
  public function x(){
     return $this->a($this->b()) +$this->c();
  }
}
// решение композицией
class B implements D{
// вода или шум, хорошо что без комментов, иначе строк 70 ненужного кода
  private $a;
  public function __construct(A $a){
    $this->a = $a;
  }
  public function c(){
     return $this->a->c();
  }
  public function d(){
     return $this->a->d();
  }
// код
  public function x(){
     return $this->a($this->b()) +$this->c();
  }
}
	нужна конкретика, класс B можно легко заменитьИ вышел-таки снова на Дерибасовскую
class ThirdPartyLibrary {
    public function foo(A $a) {..};
}
class MyLibrary {
    public function bar(D $d) {..}
}
$d = new B(); // необязательно напрямую, пусть внутри DI, это ничего не меняет
$thirdPartyLibrary->foo($d);
$myLibrary->bar($d);
	И вот уже не так-то легко.класс B можно легко заменить
наверняка есть. уже давно пора реализовать.в PhpStorm... ну, надо сделать фичреквест.
поменяйтебя не устраивает контракт метода c() и ты хочешь его поменять
не мешает2) ты обновил библиотеку и в новой версии появился метод x()
Даже говоря про ПХП, когда это было удобно для какого-то общего бойлерплейт кода, но сейчас есть хотя бы трейты.Наследование ок, когда наследуешься от абстрактного класса, при этом ничего не добавляешь к фактическому публичному интерфейсу класса, а только реализуешь абстрактные методы.
Во всех остальных случаях так или иначе возникнет проблема с LSP и/или DIP.
поменяй
1) LSPне мешает
Чувак, изучи наконец SOLID, сколько раз уже LSP упоминали — ты до сих пор не понимаешь этого.поменяй
фаталити2) Оказалось, что в приватном методе базового класса из библиотеки вызывается $this->c() и $this->x().

Я, кстати, считаю трейты (в таком виде, в каком они реализованы в PHP) ошибкой дизайна. Было бы намного лучше, если бы реализовали Java 8 default methods в интерфейсах (кажется, все разумные случаи использования трейтов сводятся к некоей дефолтной реализации определенного интерфейса).Даже говоря про ПХП, когда это было удобно для какого-то общего бойлерплейт кода, но сейчас есть хотя бы трейты.
import java.time.*;
public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();
    
    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }
        
    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}
	
Легко, если рассматривать какие-нибудь базово-инфраструктурные штуки типа Collection и их "расширения" типа Countable/Iterable, которые хочется уметь комбинировать произвольно.Мне кажется будет крайне сложно найти такой пример где нужен будет именно интерфейс с дефолт методами(вместо абстрактного класса). Эта всеобщая любовь к интерфейсам(относительно абстрактных классов) немного туманит рассуждения.
 В тех редких случаях, когда никаких зависимостей нет (скажем, трейт для сбора и отдачи наружу списка domain events) - ну, да, ок, но и в этом случае интерфейс вида -able тоже явно уместен, и с default methods как-то аккуратнее.