Interfejsy w PHP są nie tyle zbędne, co tak jak reszta obiektówki w nim - po prostu kulawe, albo przestrzelone (wystarczy chwila namysłu, przecież wszystko co w PHP nam przeszkadza zazwyczaj jest spowodowane tym, że główna idea PHP jest taka, aby był on dynamiczny, a tutaj interfejsy, które na nas coś wymuszają...). Poza tym brak w PHP możliwości type-hintingu dla zwracanych wartości funkcji dodatkowo przeszkadza w zwiększaniu użyteczności interfejsów. Ale oczywiście tak jak tutaj wszyscy już napisali są momenty kiedy się przydają.
Najczęściej oczywiście w przypadku, gdy udostępniamy nasz kod na zewnątrz, dajemy innym możliwość korzystania z niego, albo wręcz jego modyfikacji/rozbudowy.
Co do użycia to trzeba pamiętać, że interfejs to twór czysto abstrakcyjny. Określa jedynie sposoby wykorzystania bez żadnej namiastki implementacji. Dlatego tak jak
phpion powiedział, w przypadku Animal -> Monkey bardziej naturalne (i imho poprawne) byłoby użycie dziedziczenia - zwierzę to już jakiś (jak bardzo ogólny to nie ważne, ale jednak) byt, który nam od razu przywodzi na myśl jakieś zyjące stworzenie z kończynami i tak dalej...
Skoro już tak z tymi zwierzętami to ja bym zaproponował inną nieco strategię podziału, żeby zobrazować interfejsy:
<?php
interface Flying
{
public function start();
public function fly();
public function land();
}
abstract class Animal
{
}
class Bird extends Animal implements Flying
{
public function start()
{/* ... */}
public function fly()
{/* ... */}
public function land()
{/* ... */}
}
class Monkey extends Animal
{
}
class AirPlane
{
public function start()
{/* ... */}
public function fly()
{/* ... */}
public function land()
{/* ... */}
}
function moveObjectByAir(Flying $object)
{/* ... */}
moveObjectByAir( new Bird() ); // zadziala
moveObjectByAir( new AirPlane() ); // zadziala
moveObjectByAir( new Monkey() ); // nie zadziala
?>
Z bardziej realnych i praktycznych przykładów: tworzę system wymiany ofert dla biur nieruchomości i metody wymiany ofert są przeróżne. System, żeby ułatwić integrację z już istniejącymi mechanizmami powinien obsługiwać obecne metody synchronizacji (serwisów w stylu Gratka.pl, OtoDom.pl i tak dalej). I jedne eksporty opierają na plikach XML, inne na API w SOAP'ie, jeszcze inne na plikach we własnym INI-podobnym formacie. A jednak wszystkie "sterowniki" eksportu muszą udostępniać jednakowy interfejs. Poglądowo mniej więcej:
<?php
interface ExportInterface
{
public function init();
public function sync();
public function full();
}
class GratkaExport implements ExportInterface
{
/* export bazujący na plikach XML */
}
class OtoDomExport extends SoapClient implements ExportInterface
{
/* export z wykorzystaniem SOAP'u */
}
function exportOffers(ExportInterface $export, $full = false)
{
$export->init();
if($full)
{
$export->full();
}
else
{
$export->synch();
}
}
?>
(tutaj co najważniejsze chciałem pokazać, że Intefejsy pozwalają nam na użycie typowania instancji (type-hinting, instanceof i tak dalej) mimo dziedziczenia - w PHP nie ma dziedziczenia wielobazowego, ale interfejsów możemy implementować do woli, dlatego czasem są takie przydatne)