Pull to refresh

Тонкости (странности?) работы с интефейсами

Reading time3 min
Views13K
Знаешь ли ты что такое интерфейс %username%?
Если да, то я думаю этот код не вызовет у вас вопросов. PHP тонкости (странности?) работы с интефейсами
interface someInterface{
	public function someMethod();
}
interface anotherInterface{
	public function someMethod();
}
class Foo implements someInterface,anotherInterface {
	public function someMethod(){
		echo 'someMethod() was called'.PHP_EOL;
	}
}
$foo = new Foo();
$foo->someMethod();

Итак что выведет на экран скрипт в результате своей работы.
Ответ под кaтом.
trollfaceПравильный ответ: «Fatal error: Can't inherit abstract function …» Но почему? — совершенно справедливо спросите вы. Тем же вопросом задался и я когда впервые столкнулся с этим. Как показал поиск это — причуда, достоинство, недостаток, глупость, преимущество (нужное подчеркнуть) PHP. Если мы заглянем в учебник php.net/manual/en/language.oop5.interfaces.php в котором пишут такие страшные вещи «Note: A class cannot implement two interfaces that share function names, since it would cause ambiguity.» Иными словами в PHP класс не может имплементировать несколько интерфейсов содержащих одинаковые методы, так как это порождает неоднозначность. Стоп, стоп, стоп… Давайте разберёмся. Давайте вспомним множественное наследование в С++.
class someClass {
  public:
    void someMethod(){
    };
}
class anotherClass {
  public:
    void someMethod(){
    };
}
class fooClass: someClass,anotherClass{

}
int main () {
  fooClass foo;
  foo.someMethod();
  return 0;
}

с++Тут то, как раз, и присутствует неопределённость, так как неясно какой из методов будет унаследован (ну-у почти). Интерфейсы были придуманы как раз для того, что бы разрешить коллизию возникающую при множественном наследовании классов. Ведь если говорить грубо, то интерфейс это только «набор инструкций», который говорит, что класс имплементирующий его должен реализовать такие то методы. Интерфейс не содержит реализацию метода, по этому, классу «всё равно» если ему приходится имплементировать множество интерфейсов с одинаковыми методами. Повторюсь, это всего лишь «инструкция» говорящая классу о том, что тот должен реализовать данный метод, просто этих инструкций несколько. Не совсем ясна логика разработчиков PHP, почему мы опять получили штуку, которая работает не так как везде? Почему класс не может имплементировать интерфейсы с одинаковыми методами? Почему это приводит к неоднозначности?

UPD1: почему то уже второй человек в комметариях говорит о перегрузке методов en.wikipedia.org/wiki/Method_overloading (одинаковое имя метода, но различные сигнатуры вызова: разные типы параметров передаваемых в метод, их число и прочее ...). Наверное я что то не так разъяснил, но в статье не идёт речь о оverloadin. Действительно PHP не поддерживает данный механизм. Но в данном случае к множественному имплементирования интерфейсов, этот механизм отношения не имеет.
Ещё раз в PHP класс не может имплементировать несколько интрефейсов содержащих одинаковые методы, в Java/C#/e.t.c это возможно:
public interface someInterface {
	public void someMethod();
}
public interface anotherInterface {
	public void someMethod();
}
public class fooClass implements anotherInterface,someInterface {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		fooClass fooClass = new fooClass();
		fooClass.someMethod();
	}
	@Override
	public void someMethod() {
		System.out.println("someMethod() was called");	
	}
}


UPD:2 решение той же задачи на C# habrahabr.ru/blogs/php/116916/#comment_3808966
UPD:3 проверил тот же код в D en.wikipedia.org/wiki/D_%28programming_language%29 вроде как новенький ооп язык, работает исправно файл e.d:
import std.stdio;
import std.stream;

interface D{
    void foo();
}
interface A{
    void foo();
}
class E : D, A{
	void foo(){
		writefln("foo() was called");
	}
}
void main (string[] args){
	E e = new E();
	e.foo();
}
alagar@home:~/d$ dmd  -run  e.d 
foo() was called
Tags:
Hubs:
+32
Comments119

Articles