Почему в PHP есть интерфейсы?

35

Я заметил, что в PHP5 интерфейсы были добавлены в язык. Тем не менее, поскольку PHP так свободно набран, кажется, что большинство преимуществ использования интерфейсов потеряно. Почему это включено в язык?

GSto
источник
5
Я думаю, что правильный вопрос, почему бы и нет?
Альберто Фернандес
5
потому что они, кажется, не предлагают никакой выгоды, так зачем включать их?
GSto
4
@HorusKol и до того, как они были реализованы, они не использовались, так что вы можете увидеть, как они были неиспользованы и бесполезны только в предыдущей версии. Вы также должны заявить и поддержать утверждение, что их использование является каким-то улучшением, чтобы сказать, что они полезны.
Рейн Хенрикс
6
@HorusKol Ничего особенного. Легко продемонстрировать ценностное предложение молотка. Этот вопрос требует от кого-то продемонстрировать ценностное предложение интерфейсов PHP, а не просто заявить, что они ценны аргументированным образом.
Рейн Хенрикс
3
И помните, что интерфейсы не только о наборе текста. Интерфейс - это контракт, утверждающий, что реализующий класс должен включать методы, которые он разрабатывает. Полезно для таких вещей, как плагины двигателей.
Майкл

Ответы:

30

Основным преимуществом интерфейсов в PHP является то, что классы могут реализовывать несколько интерфейсов. Это позволяет группировать классы, которые совместно используют некоторые функции, но не обязательно совместно используют родительский класс. Некоторые примеры могут включать кэширование, вывод или доступ к свойствам класса определенным образом.

В своем коде вы можете проверить, реализует ли класс данный интерфейс, вместо проверки имени класса. Тогда ваш код будет работать при добавлении новых классов.

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

РЕДАКТИРОВАТЬ - Добавление примера

Если у вас есть интерфейс с именем 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();
   }
}
pjskeptic
источник
23
Другими словами: «вы можете полностью игнорировать все преимущества языков с динамической типизацией»
Камиль Томшик
11
@Kamil, я думаю, что это больше, чем возможность использовать преимущества статической типизации, не испытывая недостатков, когда они вам не нужны.
Карл Билефельдт
9
ты серьезно? экземпляр? если-то-если-тогда-если-то-все-время, разве это не звучит знакомо? ах, да, процедурное программирование.
Камиль Томшик
23
@Kamil Tomšík Еще одно оскорбление языка PHP, а не людей, которые используют его некомпетентно. PHP имеет все инструменты для полного объектно-ориентированного программирования. Независимо от того, используете ли вы их, зависит от программиста. Кроме того, нет ничего плохого в процедурном программировании само по себе.
Lotus Notes
18
@Kamil - как странно, прочитав ваш комментарий, можно прийти к выводу, что в ООП нет if-s и что каким-то образом, волшебным образом - все становится на свои места. Вау.
Michael JV
23

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

Рассмотрим следующий пример:

interface Car { function go(); }

class Porsche { function go() {} }

function drive(Car $car) {}

$porsche = new Porsche();

drive($porsche);

Приведенный выше код будет выводить:

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

Эмануил Русев
источник
1
Конечно, это очень плохо. Вы можете иметь nullзначение по умолчанию для параметра, хотя.
Эмануил Русев
5
но если driveтребуется Car, то прохождение nullне будет очень полезно в любом случае ...
HorusKol
7
Никогда не пропускай ноль. Используйте объект «Особый случай» (Google для объяснения Мартина Фаулера).
Мартин Блур
2
@Renesis Если вы установите значение по умолчанию в null, вы можете передать null в подсказки типа. (CAR $ car = null) позволит вам вызвать этот метод с нулем в качестве аргумента. Это было бы довольно глупо, однако. С какой стати вы хотели бы иметь возможность сделать это?
dqhendricks
2
Конкретный пример: у function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);вас может быть, $methodNameно нет $securityMode.
Николь
7

Интерфейсы позволяют реализовывать принцип «открыто-закрыто», поддерживать слабосвязанную кодовую базу и реализовывать многие из лучших шаблонов проектирования ООП.

Например, если один класс принимает другой класс в качестве аргумента:

class A {

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

Ваш класс A и класс B теперь имеют тесную связь, и класс A не может использовать какой-либо другой класс, кроме B. Подсказка типа гарантирует, что у вас есть правильный тип аргумента, но теперь укрепила связь между A и B.

Допустим, вы хотите, чтобы класс A мог использовать все типы классов, имеющих метод run (). Это в основном (но не совсем) шаблон проектирования КОМАНДЫ. Чтобы решить эту проблему, вы должны вместо этого ввести подсказку, используя интерфейс вместо конкретного класса. B будет реализовывать этот интерфейс и будет принят в качестве аргумента для класса A. Таким образом, класс A может принять любой класс, который использует этот интерфейс в качестве аргумента для своего конструктора.

Этот тип кодирования используется в большинстве шаблонов проектирования ООП и позволяет значительно упростить изменения кода в более позднее время. Это часть основ программирования AGILE.

dqhendricks
источник
1
Или любой подкласс B
Мез
7

У @pjskeptic хороший ответ , а у @Kamil Tomšík хороший комментарий к этому ответу.

Самое замечательное в динамически типизированных языках, таких как PHP, заключается в том, что вы можете пытаться использовать методы для объектов, и вас это не будет кричать, если метода нет.

Проблема с динамически типизированными языками, такими как PHP, заключается в том, что вы можете пытаться использовать методы для объектов, и он будет кричать на вас, когда метода нет.

Интерфейсы добавляют удобный способ вызова методов для неизвестного объекта и уверенности в том, что методы есть (не то, что они обязательно правильные или собираются работать). Это не обязательная часть языка, но она делает кодирование более удобным. Это позволяет разработчикам ООП со строгой типизацией писать строго типизированный код 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!');
  }
  ...
}

и ИМХО простой, читаемый код лучше кода.

zzzzBov
источник
1
вместо этого вы просто не проверяете метод, а аварийно завершаете работу, когда кто-то вызывает вашу функцию с неверными данными. Это не ваша проблема, если кто-то неправильно использует вашу функцию.
Райнос
точно нет - ваш пример - кошмар для тех, кто хочет передать любую динамичную «утку», такую ​​как прокси, адаптер, декоратор и т. д.
Камил Томшик
1
@Kamil? Как же так. Прокси был бы классом-оболочкой для чего-то, что не реализует интерфейс, позволяющий использовать его с этой функцией.
Tylermac
Динамический прокси @tylermac, использующий __call () - и если __call является единственным методом, он просто не может реализовать IBar, а это значит, что вы не можете передать его в foo (IBar $ bar)
Камиль Томшик
5

Они совершенно бесполезны, если вы типизирующий утку, на самом деле, когда вы выполняете типизацию с утиным типом, работать с библиотеками / фреймворком, которые используют любые подсказки типов, довольно раздражает.

Это относится также ко всем видам динамического метапрограммирования (магические методы).

Камил Томшик
источник
3

PHP не свободно или сильно, но динамически типизирован .

Что касается интерфейсов, первое, что вы должны спросить себя: каковы большинство преимуществ интерфейсов?

В ООП интерфейсы - это не только типы, но и поведение.

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

Таким образом, в основном, вы можете иметь SOLID- совместимое приложение в PHP, используя языковые функции, одной из которых является интерфейс.

Даниэль Рибейро
источник
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) true

но сравнение ($ myVar === $ myVar) будет равно (bool) false, как любое «типизированное» сравнение

Мне бы очень хотелось, чтобы разработчики прекратили спорить об этих вещах, если у вас возникнут проблемы с тем, как работает PHP, или запустите программу на Java и живите и дайте жить, или используйте ее так, как она сделает то, что вы хотите ... Что хорошего в этом случае для вас? Есть ли у вас оправдание, чтобы крутить весь день? Выглядишь лучше, чем кто-то еще? Что ж, это здорово, что вы так сильно относитесь к себе, что вы хотите, чтобы кто-то другой выглядел плохо, но на самом деле это ваше предпочтение, и навязывание своих убеждений кому-то на самом деле просто заставляет их кодировать таким образом, что им неудобно вызывать три вещи:

1) Они будут кодировать ваш путь, но «грязно» по вашим стандартам (подумайте, вы когда-нибудь видели, чтобы Java-программист создавал свою первую программу на PHP или наоборот? Это будет так же, как изменение их методологии или, может быть, даже хуже).

2) Вы найдете что-то еще, чтобы скулить о

3) Это, вероятно, займет больше времени для их производства. И, возможно, в краткосрочной перспективе это поможет вам выглядеть лучше, но команда в целом будет выглядеть хуже (помните, что вы можете писать код медленнее, чем кто-либо другой, и это не обязательно плохо, если команда встречает результаты в разумные сроки, но навязывание ваших привычек кому-то, кто обычно работал немного быстрее, может в конечном итоге замедлить всю вашу команду, таким образом, выглядят хуже в очень требовательном рабочем процессе)

Лично я предпочитаю писать процедурный код PHP, хотя могу и написал полные программы с использованием ООП на нескольких разных языках. При этом я видел хороший ООП-код и плохой ООП-код, а также хороший процедурный код и плохой процедурный код в этом отношении ... Это действительно не имеет ничего общего с практикой, но с привычками, которые вы используете, и даже тогда, многие вещи - мои интерпретированные чувства ... это не значит, что я буду плохо говорить об этих разработчиках или говорить, что хвастаюсь "моим способом лучше" BS, это как раз для меня, и компания, в которой я работаю, довольно Я доволен своей работой, и я горжусь этим. Есть причины, по которым должен быть установлен стандарт, но то, что вы включаете в стандарт, который вы выбираете, ОЧЕНЬ важно ... Спасибо, что позволили мне снять это с моей груди Хорошего дня.

Джейк Погорелец
источник
-4
  1. Интерфейсы - это часть парадигмы ООП. Так что это очень полезно во многих случаях, когда вы пытаетесь создать объектно-ориентированные части или свою систему.
  2. Так. Почему бы нет? ;-)

Примеры: вам нужно кэшировать ваши данные. Как? Существует множество разных движков для кеширования, какой из них лучший? Кому интересно, если у вас есть абстрактный слой, у которого есть некоторый интерфейс ICacheDriver с набором методов, таких как key, get, put, clear и т. Д. Просто внедрите в него то, что вам нужно в текущем проекте, и измените его, когда вам понадобится другой. Или простое использование toString. У вас есть набор различных отображаемых объектов. Вы просто реализуете интерфейс Stringable (который описывает метод toString [на самом деле таких интерфейсов нет в PHP, но, например,]) и просто взаимодействуете со всем вашим объектом с помощью (string) $ obj. Есть все, что вам нужно сделать вместо switch (true) {case $ obj isntanceof A1: "do 1"; перемена; ...}

Просто. Так что нет вопроса «почему?». Существует «как использовать это лучше?». ;-) Удачи.

Алекс Ярошевич
источник
-5

Мое предположение.

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

После курса «Программирование 101» они начинают ворчать из-за того, что Zend хотят использовать функции java, потому что так их учили думать, думать по-своему (или понимать утки) сложно, когда тебе всего 20 лет.

Zend прагматичен, проще добавить функцию, чем притворяться, что они все время были правы.
Это также покупает больше пользователей вместо того, чтобы заставить их уйти, поэтому это должно быть хорошо.

Еще один пример этого процесса? Людям, начинающим изучать курсы .NET и Java, также нужны фреймворки базовых классов , они болтают об этом, пока Zend не вырастет из Zend Framework. . Это покупает еще больше пользователей. И так далее...

(единственный язык особенность команды PHP , как известно, боролись , на протяжении многих лет, является goto)

Zjr
источник
На мой взгляд, PHP12вероятно , будет иметь все синтаксические особенности мира (я надеюсь, что он не получит время выполнения уровня абстракции, жесткое, как то, что убило Perl) с подмигиванием функциональным парадигмам и парадигмам типов данных, и до сих пор нет goto.
ZJR
«Трудно, когда тебе только 20». Как возраст может иметь какое-либо отношение к пониманию любой из этих концепций?
Evicatos
@Evicatos - своего рода программа для старшеклассников, но у них обычно плохие учителя, плохие соглашения по присвоению имен и они создают не поддерживаемые двоичные объекты. Они учатся программировать прямо во время учебы в колледже, и для этого требуется пара лет. Затем они начинают расходиться с жестко типизированными, блаженными в отрасли, общеизвестными языками, которым их учили в те первые годы, и превращаются в более прагматичные, утконосные. Я полагаю, что это бушидо, которое разделяют многие программисты. Опять же, это может не отражать ваш опыт, вы можете быть самоучкой. Если так, покажи нам путь.
ZJR