Чому PHP має інтерфейси?


35

Я помітив, що станом на PHP5 до мови додано інтерфейси. Однак, оскільки PHP настільки слабко набраний, здається, що більшість переваг використання інтерфейсів втрачається. Чому це включено в мову?


5
Я думаю, що правильне питання: чому б і ні?
Альберто Фернандес

5
оскільки вони, здається, не пропонують ніякої користі, то навіщо їх включати?
GSto

4
@HorusKol і до того, як вони були впроваджені, вони не використовувалися, тож ви можете бачити, як вони були невикористаними та марними лише попередньою версією. Ви також повинні висловити та підтримати твердження, що їх використання - це якось покращення, щоб сказати, що вони корисні.
Рейн Генріхс

6
@HorusKol Зовнішньо. Це легко продемонструвати ціннісну пропозицію молотка. Це питання просить когось продемонструвати ціннісну пропозицію інтерфейсів PHP, а не просто заявити, що вони цінні аргументовано.
Рейн Генріхс

3
І пам’ятайте, що інтерфейси стосуються не лише введення тексту. Інтерфейс - це договір, в якому зазначено, що клас реалізації повинен включати методи, які він викладає. Корисно для таких речей, як плагіни.
Майкл

Відповіді:


30

Основна перевага інтерфейсів у PHP полягає в тому, що класи можуть реалізувати декілька інтерфейсів. Це дозволяє групувати класи, які поділяють певну функціональність, але не обов'язково поділяють батьківський клас. Деякі приклади можуть включати кешування, вихід чи доступ до властивостей класу певним чином.

У своєму коді ви можете перевірити, чи реалізує клас заданий інтерфейс, а не ім'я класу. Тоді ваш код все ще буде працювати, коли додаються нові класи.

PHP надає деякі заздалегідь задані інтерфейси, які можуть стати в нагоді в різних ситуаціях: http://php.net/manual/en/reserved.interfaces.php .

EDIT - Додавання прикладу

Якщо у вас є інтерфейс з іменем MyInterface і ви працюєте з декількома об'єктами різних класів, які можуть або не мають певної функціональності, інтерфейси дозволяють зробити щось подібне:

// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
 if($obj instanceof MyInterface) {
     $obj->a();
     $obj->b();
     $obj->c();
   }
}

23
Іншими словами: "Ви можете повністю ігнорувати всі переваги мов, що динамічно вводяться"
Каміль Томшик

11
@Kamil, я вважаю, що це може скористатися перевагами статичного набору тексту, не зазнаючи недоліків, коли ти їх не хочеш.
Карл Білефельдт

9
ти серйозно? instanceof? якщо-то-якщо-то-якщо-то-все-таки, це не звучить знайомо? ах, так, процедурне програмування.
Каміль Томшик

23
@Kamil Tomšík Ще одна образа мови PHP, а не людей, які некомпетентно вживають її. PHP має всі інструменти для повноцінного об'єктно-орієнтованого програмування. Незалежно від того, використовуєте ви їх чи ні, залежить від програміста. Крім того, немає нічого поганого в процедурному програмуванні саме по собі.
Lotus Notes

18
@Kamil - як це не дивно, прочитавши ваш коментар, можна прийти до висновку, що в OOP немає if-s, і це якось магічно - справи діють. Ого.
Майкл СП

23

PHP набрано слабко, але він може бути сильно набраний щодо таких речей, як параметри методу.

Розглянемо наступний приклад:

interface Car { function go(); }

class Porsche { function go() {} }

function drive(Car $car) {}

$porsche = new Porsche();

drive($porsche);

Вищенаведений код виведе:

Аргумент 1, переданий диску (), повинен реалізувати інтерфейс Car, екземпляр даного Porsche


1
Звичайно, це дуже погано. nullОднак для параметра можна мати значення за замовчуванням.
Емануїл Русєв

5
але якщо driveвимагає Carпроходження, то проходження все nullодно не буде дуже корисним ...
HorusKol

7
Ніколи не пропускайте нуль. Використовуйте об’єкт "Особливий випадок" (пояснення Google для Мартіна Фаулера).
Мартін Блор

2
@Renesis Якщо встановити значення за замовчуванням на null, ви можете передати null у підказки типу. (CAR $ car = null) дозволить вам викликати цей метод як null як аргумент. Однак це було б досить нерозумно. Чому на землі ви хотіли б це зробити?
dqhendricks

2
Конкретний приклад: у function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);вас може бути, $methodNameале ні $securityMode.
Ніколь

7

Інтерфейси дозволяють реалізувати принцип відкритого закритого типу, підтримувати слабко пов'язану базу коду та реалізувати багато найкращих моделей дизайну OOP.

Наприклад, якщо один клас приймає інший клас як аргумент:

class A {

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

Тепер ваш клас A і клас B мають щільне з'єднання, а клас A не може використовувати жоден інший клас, крім B. Натяк на тип гарантує, що ви маєте правильний тип аргументу, але тепер цементував зв'язок між A і B.

Скажімо, що ви хочете, щоб клас A міг використовувати всі типи класів, у яких є метод run (), однак. Це в основному (але не зовсім) модель дизайну COMMAND. Щоб вирішити, замість конкретного класу слід набрати підказку, використовуючи інтерфейс. B вони реалізують цей інтерфейс і будуть прийняті як аргумент для класу A. Таким чином клас A може прийняти будь-який клас, який використовує цей інтерфейс як аргумент для свого конструктора.

Цей тип кодування використовується в більшості моделей дизайну OOP, і дозволяє значно пізніше змінити код у наступний час. Це частина основ програмування AGILE.


1
Або будь-який підклас B
Mez

7

@pjskeptic має хорошу відповідь , і @Kamil Tomšík має хороший коментар до цієї відповіді.

Чудова річ у динамічно набраних мовах, як PHP, це те, що ви можете спробувати використовувати методи на об’єктах, і він не кричить на вас, якщо методу немає.

Проблема з динамічно набраними мовами, такими як PHP, полягає в тому, що ви можете спробувати використовувати методи на об'єктах, і він буде кричати на вас, коли методу немає.

Інтерфейси додають зручний спосіб виклику методів на невідомому об’єкті, впевнені, що методи існують (не те, що вони обов'язково правильні або працюють). Це не є необхідною частиною мови, але робить кодування більш зручним. Це дозволяє сильно набраним розробникам OOP писати сильно набраний код PHP, який може потім працювати поряд із слабко набраним кодом PHP, написаним іншим розробником PHP.

така функція, як:

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

зручніше ніж:

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

а IMHO простий, читабельний код - краще код.


1
те, що ви робите замість цього, це просто не перевіряти метод, а виходити з ладу та записувати, коли хтось викликає вашу функцію з неправильними даними. Це не ваша проблема, якщо хтось неправильно використовує вашу функцію.
Райнос

точно не - ваш приклад - кошмар для тих, хто хоче пройти будь-яку динамічну "качку", як-от проксі, адаптер, декоратор тощо.
Каміль Томшик

1
@Kamil? Як так. Проксі - це клас обгортки для чогось, що не реалізує інтерфейс, щоб дозволити його використовувати з цією функцією.
tylermac

@tylermac динамічний проксі-сервер, що використовує __call () - і якщо __call - єдиний метод там, він просто не може реалізувати IBar, а це означає, що ви не можете передати його foo (IBar $ bar)
Каміль Томшик

5

Вони абсолютно марні, якщо ти набираєш качок, насправді, коли ти набираєш качок, дуже прикро працювати з бібліотеками / рамками, які використовують будь-які натяки на тип.

Це стосується також усіх видів динамічного метапрограмування (магічні методи).


3

PHP не є сильно або сильно, але динамічно набирається .

Щодо інтерфейсів, перше, що ви повинні запитати у себе, це: у чому полягають переваги інтерфейсів?

В OOP інтерфейси стосуються не лише типів, а й поведінки.

Оскільки PHP також має функцію підказки типу , ви можете використовувати інтерфейси так само, як у чистому мові oo, наприклад 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
        }
    }
}

З реалізацією інтерфейсу PHP ви також створюєте макети для абстрактних класів за допомогою PHPUnit - і це пекла особливість:

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

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

    // do your assertions
}

Таким чином, ви можете мати в програмі PHP сумісну програму SOLID , використовуючи мовні функції, одним з яких є інтерфейси.


0

Інтерфейси корисні для введення залежності набагато більше, ніж конкретні. Як приклад босоніжок:

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);

Тепер скажіть, якщо ваші потреби змінюються, і ви хочете зберегти їх у форматі PDF. Для цього ви можете створити новий клас замість забруднення класу 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);

Клас Article тепер має контракт, що класи, які він використовує для збереження, повинні реалізовувати інтерфейс Istore. Не байдуже, де економить чи як економить.


-1

Ви можете надати "Підроблені" реальні об'єкти, які реалізують інтерфейс. Потім ви можете перевірити частину свого коду, не вимагаючи реальних серверів, файлових систем, сокетів, баз даних тощо.


-3

Багато людей, ймовірно, ненавиджу мене за відповідь таким чином, але рішення ваших проблем із набором тексту можна легко виправити за допомогою PHP. Так, PHP є типово типізованим, тому типи приймаються за замовчуванням, що може спричинити деякі проблеми, особливо в порівнянні з операціями, з якими це стосується більшість людей. Якщо говорити, PHP може бути настільки ж строгим, як і будь-яка сильно набрана мова, якщо ви передаєте те, що ви використовуєте, у потрібний вам тип, а потім використовуєте оператори побітного порівняння. Ось найпростіший приклад, який я можу придумати, про що я говорю:

$ myVar = (int) 0; $ myOtherVar = '0';

порівняння ($ myVar == $ myVar) було б рівним (bool) правдою

але порівняння ($ myVar === $ myVar) було б рівним (bool) помилковим, як і будь-яке "набране" порівняння

Я дуже хочу, щоб розробники перестали сперечатися з приводу цих речей, якщо у вас є проблеми з тим, як працює PHP або перейти на програму Java, і жити, і нехай жити, або використовувати її так, як вона буде робити те, що ви хочете. . Яке користь приносить суті в цьому випадку для вас? Дайте виправдання, щоб викручуватися цілий день? Змусиш виглядати краще, ніж хтось інший? Добре, що ви так високо ставитесь до себе, що ви готові змусити когось іншого виглядати погано, але насправді це ваші уподобання і змушувати свої переконання на когось насправді просто змушує їх кодувати таким чином, що їм не зручно викликати три речі:

1) Вони будуть кодувати ваш шлях, але "безладно" за вашими мірками (подумайте, ви коли-небудь бачили, як програміст java створює свою першу програму PHP чи навпаки? Це буде аналогічно змінити їх методологію чи, можливо, навіть гірше).

2) Ви знайдете щось інше, щоб скуголити

3) Виробництво, ймовірно, займе більше часу. І, можливо, це змусить вас виглядати краще за короткий термін, але команда в цілому буде виглядати гірше за це (пам’ятайте, що ви можете кодувати повільніше, ніж хтось інший, і це не обов'язково погано, якщо команда відповідає розумним результатам, але примушувати свої звички до того, хто зазвичай працює трохи швидше, це може призвести до того, що вся ваша команда сповільниться, таким чином, виглядайте гірше в дуже вимогливому робочому процесі)

Я особисто вважаю за краще писати процедурний PHP-код, хоча я можу і маю написані повні програми, використовуючи OOP на кількох різних мовах. Попри це, я бачив хороший код OOP і поганий код OOP, хороший процесуальний кодекс і поганий процесуальний код з цього приводу ... Це насправді не має нічого спільного з практикою, але з звичками, якими ви користуєтесь і навіть тоді, багато речей - це мої інтерпретовані почуття ... це не означає, що я буду говорити погано про тих розробників або сказати похвалитися "мій шлях найкращий" BS, це мені просто підходить, і компанія, в якій я працюю, досить задоволений своєю роботою і пишаюся цим. Є причини, за якими слід встановити стандарт, але те, що ви включаєте в обраний вами стандарт, ДУЖЕ важливо ... Дякую за те, що дозволили мені вийняти це з грудей. Хорошого дня.


-4
  1. Інтерфейси є частиною парадигми OOP. Тому це дуже корисно у багатьох випадках, коли ви намагаєтеся зробити об'єктно-орієнтовані частини або вашу систему.
  2. Так. Чому ні? ;-)

Приклади: потрібно кешувати свої дані. Як? Є багато різних двигунів для кешування, який з них найкращий? Кому байдуже, якщо у вас є абстрактний шар, який має якийсь інтерфейс ICacheDriver з набором методів, таких як ключ, get, put, clear та ін. Просто реалізуйте для нього те, що вам потрібно в поточному проекті, і змініть його, коли вам потрібно інший. Або просте використання ToString. У вас є набір різних об'єктів, що відображаються Ви просто реалізуєте Stringable-інтерфейс (який описує метод toString (у PHP немає насправді таких інтерфейсів, як, наприклад,)) та просто взаємодієте над усім вашим об'єктом з (string) $ obj. Є все, що вам потрібно зробити замість перемикача (true) {case $ obj isntanceof A1: "do 1"; перерву; ...}

Простий. Тож питання "Чому?" Не виникає. Є "як краще це використовувати?". ;-) Удачі.


-5

Моя здогадка.

PHP використовується багатьма програмістами початкового рівня, програмістів початкового рівня навчають Java в коледжі.

Після курсу програмування 101 вони починають нудити Зенда, вони хочуть можливості Java, тому що саме так їх вчили думати, мислити за власними умовами (або розуміти набирання качок) важко, коли вам лише 20 років.

Зенд прагматичний, простіше додати особливість, іншу, ніж робити вигляд там, де все правильно.
Це також купує більше користувачів, а не змушує їх піти, тому це повинно бути добре.

Ще один примірник цього процесу? Люди, що знаходяться на курсах .NET та Java, також хочуть , щоб вони складали рамки фундаментальних класів , і вони не хочуть це доти, доки Zend не виведе Zend Framework . Це купує ще більше користувачів. І далі, і далі ...

(Єдиною мовною особливістю, з якою команда PHP боролася протягом багатьох років, є goto)


На моє бачення, PHP12напевно, будуть усі синтаксичні особливості світу (я сподіваюся, що він не отримає тривалості шару абстрагування, жорсткий, як це вбило перл) з підморгненням до функціональних і типів парадигм, і досі немає goto.
ZJR

"важко, коли тобі лише 20". Як вік може мати щось спільне з розумінням будь-якої з цих концепцій?
Евікатос

@Evicatos сортування програми, але вони, як правило, мають поганих викладачів, погані умови іменування та створюють незрозумілі краплі. Вони вчаться програмувати прямо під час навчання в коледжі, на те, щоб продовжити це, потрібно кілька років. Потім вони починають відходити від твердо типових, галузевих, академічно відомих мов, яких вони викладали в перші роки, і переходять до, більш прагматичних, качкоподібних. Я вважаю, що це багато хто з програмістів. Знову ж таки, це може не відображати ваш досвід, ви можете бути саваном-самоучкою. Якщо так, покажіть нам шлях.
ZJR
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.