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?
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?
Odpowiedzi:
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();
}
}
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
null
domyślną wartość parametru.
drive
wymaga Car
, to i tak podanie null
nie byłoby bardzo pomocne ...
function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);
możesz mieć, $methodName
ale nie $securityMode
.
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.
@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.
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).
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.
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.
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.
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.
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.
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
PHP12
prawdopodobnie 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
.