Dlaczego PHP ma interfejsy?

35

Zauważyłem, że od PHP5 dodano interfejsy do języka. Ponieważ jednak PHP jest tak luźno wpisane, wydaje się, że większość korzyści płynących z używania interfejsów została utracona. Dlaczego jest to uwzględnione w języku?

GSto
źródło
5
Myślę, że poprawne pytanie brzmi: dlaczego nie?
Alberto Fernández,
5
ponieważ nie wydają się oferować żadnych korzyści, więc po co je uwzględniać?
GSto,
4
@HorusKol i przed ich wdrożeniem nie były używane, więc można zobaczyć, jak były nieużywane i bezużyteczne, tylko wersja wcześniejsza. Trzeba również wysunąć i poprzeć twierdzenie, że ich użycie jest jakimś ulepszeniem, aby powiedzieć, że są przydatne.
Rein Henrichs,
6
@HorusKol W ogóle nie jest specious. Łatwo jest zademonstrować wartość młota. To pytanie wymaga, aby ktoś zademonstrował propozycję wartości interfejsów PHP, a nie tylko zadeklarował ich wartość w sposób argumentacyjny.
Rein Henrichs
3
I pamiętaj, że interfejsy to nie tylko pisanie. Interfejs to umowa stwierdzająca, że ​​klasa implementująca musi zawierać metody, które określa. Przydatny do takich rzeczy jak silniki wtyczek.
Michael,

Odpowiedzi:

30

Główną zaletą interfejsów w PHP jest to, że klasy mogą implementować wiele interfejsów. Umożliwia to grupowanie klas, które mają pewną funkcjonalność, ale niekoniecznie dzielą klasę nadrzędną. Niektóre przykłady mogą obejmować buforowanie, wyjście lub uzyskiwanie dostępu do właściwości klasy w określony sposób.

W kodzie możesz sprawdzić, czy klasa implementuje dany interfejs zamiast sprawdzać nazwę klasy. Wówczas Twój kod będzie nadal działał po dodaniu nowych klas.

PHP zapewnia pewne predefiniowane interfejsy, które mogą się przydać w różnych sytuacjach: http://php.net/manual/en/reserved.interfaces.php .

EDYCJA - dodawanie przykładu

Jeśli masz interfejs o nazwie MyInterface i pracujesz z wieloma obiektami różnych klas, które mogą, ale nie muszą, dzielić niektóre funkcje, interfejsy pozwalają ci zrobić coś takiego:

// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
 if($obj instanceof MyInterface) {
     $obj->a();
     $obj->b();
     $obj->c();
   }
}
pjskeptic
źródło
23
Innymi słowy: „możesz całkowicie zignorować wszystkie zalety języków dynamicznych”
Kamil Tomšík
11
@Kamil, myślę o tym bardziej, jako o możliwości korzystania z zalet pisania statycznego bez ponoszenia wad, gdy ich nie chcesz.
Karl Bielefeldt
9
Mówisz poważnie? wystąpienie? jeśli-to-jeśli-wtedy-jeśli-to-wtedy-cały czas, czy to nie brzmi znajomo? tak, programowanie proceduralne.
Kamil Tomšík
23
@Kamil Tomšík Kolejna zniewaga dotycząca języka PHP, a nie ludzi, którzy używają go w sposób niekompetentny. PHP posiada wszystkie narzędzia do kompletnego programowania obiektowego. To, czy ich użyjesz, zależy od programisty. Co więcej, nie ma nic złego w samym programowaniu proceduralnym.
Lotus Notes
18
@Kamil - jakie to dziwne, po przeczytaniu twojego komentarza można dojść do wniosku, że w OOP nie ma żadnych „if”, i że w jakiś magiczny sposób wszystko zaczyna działać. Łał.
Michael JV
23

PHP jest luźno pisane, ale można go mocno pisać na temat parametrów metod.

Rozważ następujący przykład:

interface Car { function go(); }

class Porsche { function go() {} }

function drive(Car $car) {}

$porsche = new Porsche();

drive($porsche);

Powyższy kod wyświetli:

Argument 1 przekazany do drive () musi implementować interfejs Car, podana instancja Porsche

Emanuil Rusev
źródło
1
Jasne, to szkoda. Możesz jednak mieć nulldomyślną wartość parametru.
Emanuil Rusev
5
ale jeśli to drivewymaga Car, to i tak podanie nullnie byłoby bardzo pomocne ...
HorusKol,
7
Nigdy nie przechodź na zero. Użyj obiektu „Special Case” (Google dla wyjaśnienia Martina Fowlera).
Martin Blore
2
@Reneesis Jeśli ustawisz wartość domyślną na null, możesz przekazać null do metod z podpowiedziami typu. (CAR $ car = null) pozwala na wywołanie tej metody z argumentem null. Byłaby to jednak dość głupia praktyka. Dlaczego, u licha, chcesz to robić?
dqhendricks
2
Konkretny przykład: function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);możesz mieć, $methodNameale nie $securityMode.
Nicole
7

Interfejsy umożliwiają wdrożenie zasady otwartego zamknięcia, utrzymanie luźno powiązanej bazy kodu i wdrożenie wielu najlepszych wzorców projektowych OOP.

Na przykład, jeśli jedna klasa akceptuje inną klasę jako argument:

class A {

    public function __construct(B $class_b) {
        // use class b
        $class_b->run();
    }
}

Twoja klasa A i klasa B mają teraz ścisłe powiązanie, a klasa A nie może używać żadnej innej klasy oprócz B. Podpowiedzi typu zapewniają, że masz poprawny typ argumentu, ale teraz utrwaliły związek między A i B.

Powiedzmy, że chcesz, aby klasa A mogła korzystać ze wszystkich typów klas, które mają metodę run (). Jest to w zasadzie (ale nie do końca) wzorzec projektowy COMMAND. Aby rozwiązać, zamiast tego wpisz podpowiedź za pomocą interfejsu zamiast konkretnej klasy. B wdrożyłby ten interfejs i zostanie zaakceptowany jako argument dla klasy A. W ten sposób klasa A może zaakceptować każdą klasę, która używa tego interfejsu jako argument dla swojego konstruktora.

Ten typ kodowania jest wykorzystywany w większości wzorców projektowych OOP i pozwala na DUŻO łatwiejsze zmiany kodu w późniejszym czasie. Są to podstawy programowania AGILE.

dqhendricks
źródło
1
Lub dowolną podklasę B
Mez
7

@pjskeptic ma dobrą odpowiedź , a @Kamil Tomšík ma dobry komentarz do tej odpowiedzi.

Wspaniałą rzeczą w dynamicznie wpisywanych językach, takich jak PHP, jest to, że możesz próbować używać metod na obiektach i nie krzyczy na ciebie, chyba że metody nie ma.

Problem z dynamicznie wpisywanymi językami, takimi jak PHP, polega na tym, że możesz próbować używać metod na obiektach i krzyczy na ciebie, gdy metody nie ma.

Interfejsy dodają wygodny sposób wywoływania metod na nieznanym obiekcie i pewność, że metody tam są (niekoniecznie są one poprawne lub będą działać). Nie jest to niezbędna część języka, ale sprawia, że ​​kodowanie jest wygodniejsze. Umożliwia programistom OOP o silnym typie pisanie silnie napisanego kodu PHP, który może następnie współpracować z luźno napisanym kodem PHP napisanym przez innego programistę PHP.

funkcja taka jak:

foo( IBar $bar )
{
  $baz = $bar->baz();
  ...
}

jest wygodniejszy niż:

foo( $bar )
{
  if ( method_exists( $bar, 'baz' ) )
  {
    $baz = $bar->baz();
  }
  else
  {
    throw new Exception('OMGWTF NO BAZ IN BAR!');
  }
  ...
}

a prosty, czytelny kod IMHO to lepszy kod.

zzzzBov
źródło
1
zamiast tego po prostu nie sprawdzasz metody, awarię i wypalenie następuje, gdy ktoś wywoła twoją funkcję z nieprawidłowymi danymi. To nie twój problem, jeśli ktoś źle używa twojej funkcji.
Raynos
nie dokładnie - twój przykład jest koszmarem dla każdego, kto chce przekazać dowolną dynamiczną „kaczkę”, taką jak proxy, adapter, dekorator itp.
Kamil Tomšík
1
@Kamil? Jak to. Serwer proxy byłby klasą opakowania dla czegoś, co nie implementuje interfejsu, aby pozwolić na jego użycie z tą funkcją.
tylermac
@tylermac dynamiczny serwer proxy za pomocą __call () - a jeśli __call jest tam jedyną metodą, po prostu nie może zaimplementować IBar, co oznacza, że ​​nie możesz przekazać go do foo (IBar $ bar)
Kamil Tomšík
5

Są całkowicie bezużyteczne, jeśli używasz kaczych typerów, w rzeczywistości, gdy piszesz kaczki, bardzo denerwująca jest praca z bibliotekami / frameworkiem, które używają podpowiedzi typu.

Dotyczy to również wszelkiego rodzaju dynamicznych metaprogramowania (metod magicznych).

Kamil Tomšík
źródło
3

PHP nie jest luźno ani silnie, ale dynamicznie pisane .

Jeśli chodzi o interfejsy, pierwszą rzeczą, którą powinieneś sobie zadać, jest: jakie są większość zalet interfejsów?

W OOP interfejsy dotyczą nie tylko typów, ale także zachowania.

Ponieważ PHP ma również funkcję podpowiedzi typu , możesz używać interfejsów tak jak w czystym języku oo, takim jak Java.

interface File
{
    public function getLines();
}

CSVFile implements File
{
    public function getLines()
    {}
}

XMLFile implements File 
{
    public function getLines()
    {}
}

JSONFile implements File 
{
    public function getLines()
    {}
}

class FileReader
{
    public function read(File $file)
    {
        foreach($file->getLines() as $line)
        {
            // do something
        }
    }
}

Dzięki implementacji interfejsu PHP możesz także tworzyć symulacje dla klas abstrakcyjnych za pomocą PHPUnit - i to jest niesamowita funkcja:

public function testSomething()
{
    $mock = $this->getMockForAbstractClass('File');

    $mock->expects($this->once())
         ->method('getLines')
         ->will($this->returnValue(array()));

    // do your assertions
}

Zasadniczo możesz mieć aplikację PHP kompatybilną z SOLID, używając funkcji językowych, z których jedną są interfejsy.

Daniel Ribeiro
źródło
0

Interfejsy przydają się do wstrzykiwania zależności znacznie bardziej niż do betonu. Jako przykład od podstaw:

interface Istore { 
  public function save(); 
}

class Article_DB implements Istore 
{ 
  public function save($data) 
  {
    // do save to format needed.
  } 
}

class Article
{
   private $content;

   public function content($content)
   {
     $this->content = $content;
   }

   public function save(Istore $store)
   {
     $store->save($this->content);
   }
}

$article = new Article();
$article->content('Some content');

$store = new Article_DB();
$article->save($store);

Teraz powiedz, czy zmieniają się Twoje potrzeby i chcesz zapisać w formacie pdf. Możesz stworzyć w tym celu nową klasę zamiast zanieczyszczać klasę Article.

class Article_PDF implements Istore 
{ 
  public function save($data) 
  {
    // do save to format needed.
  } 
}


$article = new Article();
$article->content('Some content');

$store = new Article_PDF();
$article->save($store);

Klasa Article ma teraz kontrakt, którego klasy, których używa do zapisywania, muszą implementować interfejs Istore. Nie obchodzi go, gdzie oszczędza ani jak oszczędza.

Pete
źródło
-1

Możesz podać „fałszywe” prawdziwe obiekty, które implementują interfejs. Następnie możesz przetestować część kodu w jednostce, nie wymagając prawdziwych serwerów, systemów plików, gniazd, baz danych itp.

Martin Blore
źródło
-3

Wiele osób prawdopodobnie będzie mnie nienawidzić za odpowiedź w ten sposób, ale rozwiązanie problemów z pisaniem można łatwo naprawić za pomocą PHP. Tak PHP jest luźno wpisywane, więc typy są domyślnie zakładane, co może powodować pewne problemy, szczególnie w operacjach porównawczych, które są z nim najbardziej problematyczne. Biorąc to pod uwagę, PHP może być tak samo rygorystyczne jak każdy silnie napisany język, jeśli wrzucisz to, czego używasz, do typu, w jakim chcesz, a następnie użyjesz bitowych operatorów porównania. Oto najprostszy przykład tego, co mówię:

$ myVar = (int) 0; $ myOtherVar = „0”;

porównywanie ($ myVar == $ myVar) byłoby równe (bool) true

ale porównywanie ($ myVar === $ myVar) byłoby równe (bool) false, tak jak każde „wpisane” porównanie

Naprawdę chciałbym tylko, żeby programiści przestali się kłócić o te rzeczy, jeśli masz problem ze sposobem działania PHP, albo uruchom program w Javie i żyj i pozwól żyć, albo użyj go w sposób, w jaki zrobi to, co chcesz. A cóż z tego, że szalejesz na ten temat? Czy masz pretekst, żeby się pieprzyć przez cały dzień? Czy wyglądasz lepiej niż ktoś inny? Cóż, to wspaniale, że tak bardzo czujesz do siebie, że jesteś skłonny sprawić, że ktoś wygląda źle, ale w rzeczywistości jest to twoja preferencja i narzucanie swoich przekonań każdemu naprawdę sprawia, że ​​kodują w sposób, który nie sprawia im komfortu powodowania trzech rzeczy:

1) Będą kodować na twój sposób, ale „niechlujny” według twoich standardów (pomyśl, czy widziałeś kiedyś programistę Java, który tworzy swój pierwszy program PHP lub odwrotnie? W ten sam sposób zmieni się ich metodologia, a może nawet gorzej).

2) Znajdziesz coś innego do narzekania

3) Ich wyprodukowanie prawdopodobnie potrwa dłużej. I może sprawi, że będziesz wyglądać lepiej w perspektywie krótkoterminowej, ale zespół jako całość będzie gorzej wyglądał (pamiętaj, że możesz kodować wolniej niż ktoś inny i to niekoniecznie źle, o ile zespół spełnia wymagania w rozsądnych ramach czasowych, ale narzucenie nawyków komuś, kto zwykle wykonuje trochę szybciej, może spowolnić cały zespół, dlatego wyglądasz gorzej w bardzo wymagającym przepływie pracy)

Osobiście wolę pisać proceduralny kod PHP, chociaż mogę napisać pełne programy przy użyciu OOP w kilku różnych językach. To powiedziawszy, widziałem dobry kod OOP i zły kod OOP, a także dobry kod proceduralny i zły kod proceduralny w tym zakresie ... Naprawdę nie ma to nic wspólnego z praktyką, ale z nawykami , których używasz, a nawet wtedy, wiele rzeczy to moje interpretowane odczucia ... to nie znaczy, że będę mówić źle o tych programistach lub mówić, że chwalę się słowami „moja droga jest najlepsza” BS, to jest właśnie dla mnie, a firma, dla której pracuję, jest ładna jestem zadowolony z mojej pracy i jestem z tego dumny. Są powody, dla których należy ustanowić standard, ale to, co zawierasz w wybranym przez siebie standardzie, jest BARDZO ważne ... Dziękuję, że pozwoliłeś mi to z siebie zdjąć. Miłego dnia.

Jake Pogorelec
źródło
-4
  1. Interfejsy są częścią paradygmatu OOP. Jest to więc bardzo przydatne w wielu przypadkach, gdy próbujesz tworzyć części obiektowe lub twój system.
  2. Więc. Dlaczego nie? ;-)

Przykłady: musisz buforować swoje dane. W jaki sposób? Istnieje wiele różnych silników do buforowania, który z nich jest najlepszy? Kogo to obchodzi, jeśli masz warstwę abstrakcyjną, która ma interfejs ICacheDriver z zestawem metod takich jak klucz, pobierz, umieść, wyczyść itp. Po prostu zaimplementuj to, czego potrzebujesz w bieżącym projekcie i zmień go, gdy potrzebujesz innego. Lub proste użycie toString. Masz zestaw różnych obiektów możliwych do wyświetlenia. Po prostu implementujesz interfejs Stringable (który opisuje metodę toString [tak naprawdę nie ma takich interfejsów w PHP, ale na przykład]) i po prostu oddziałujesz na cały Twój obiekt za pomocą (string) $ obj. Jest wszystko, co musisz zrobić zamiast switch (true) {case $ obj isntanceof A1: "do 1"; złamać; ...}

Prosty. Więc nie ma pytania „Dlaczego?”. Istnieje „jak lepiej z tego korzystać?”. ;-) Powodzenia.

Alex Yaroshevich
źródło
-5

Zgaduję że.

PHP jest używane przez wielu programistów na poziomie podstawowym, programistów na poziomie podstawowym uczy się java na studiach.

Po kursie programowania 101 zaczynają dręczyć Zend, że chcą funkcji java, ponieważ w taki sposób nauczono ich myślenia, myślenie na własnych warunkach (lub rozumienie pisania kaczego) jest trudne, gdy masz zaledwie 20 lat.

Zend jest pragmatyczny, łatwiej jest dodać tę funkcję inaczej niż udawać, że ma rację przez cały czas.
To również kupuje więcej użytkowników zamiast zmuszać ich do opuszczenia, więc musi być dobrze.

Kolejny przykład tego procesu? Ludzie świeżo po kursach .NET i Java również chcą Frameworks Foundation Classes , zastanawiają się nad tym, dopóki Zend nie wypuści Zend Framework . To kupuje jeszcze więcej użytkowników. I tak dalej...

(jedyną cechą językową, z którą zmagał się zespół PHP od lat goto) jest

ZJR
źródło
W mojej wizji PHP12prawdopodobnie będzie miał wszystkie funkcje składniowe świata (mam nadzieję, że nie otrzyma środowiska wykonawczego warstwy abstrakcji, trudne, bo to właśnie zabiło perla) z mrugnięciem do funkcjonalnych i paradygmatów typu danych, i nadal nie goto.
ZJR
„trudno jest mieć 20 lat”. Jak wiek może mieć coś wspólnego ze zrozumieniem któregoś z tych pojęć?
Evicatos,
@Evicatos licealiści coś w rodzaju programu, ale zwykle mają złych nauczycieli, złe konwencje nazewnictwa i produkują nieobsługiwane obiekty blob. Uczą się programować zaraz po rozpoczęciu studiów, zanim zaczną działać, potrzeba kilku lat. Potem zaczynają odbiegać od trudnych do pisania, pobłogosławionych w branży, uznanych naukowo języków, których uczyli się w pierwszych latach, i zwracają się ku bardziej pragmatycznym, kaczym typom. Uważam, że jest to bujda dla wielu programistów. Z drugiej strony może to nie odzwierciedlać twojego doświadczenia, możesz być samoukiem. Jeśli tak, wskaż nam drogę.
ZJR