Polymorphie ist eine Voraussetzung für Mocks in Unittests oder Proxies in Remote-Diensten. Ohne Interface gibt's in den mir bekannten statischen Sprachen keine Polymorphie, daher sehe ich dort Interfaces als Voraussetzung für Unittests und Remote-Proxies an.
Generic Types kennst du bestimmt auch, damit realisiert man in OO Sprachen parametrische Polymorphie. In funktionalen Sprachen entsprechen Typeclasses ungefähr Interfaces und Union-Types ungefähr den Generics. Alle Features dienen der Realisierung von statisch typgecheckter Polymorphie. Das nur um meine Perspektive darauf nochmal zu erläutern, und wieso ich denke dass Polymorphie der kleinste gemeinsame Nenner ist und Interfaces nur ein Spezialfall.
In PHP gibt es die "magischen" __get- und __set-Methoden, damit kannst du Zugriff auf Eigenschaften regeln.
Ja sicher. Aber das nennst Du doch wohl nicht Implementierung. Das ist eine armseliger, laufzeitverschwendender Notlösung. Für Unit-Tests wäre das wohl akzeptabel. Für Proxies z.B. nicht.
Naja, wenn du von Netzwerk-Proxies spricht, wie in deinem ersten Beispiel, kann man den Laufzeit-Overhead für das ausführen einer magischen Methode wohl vernachlässigen. Da ist mit Sicherheit Netzwerk-IO dein Flaschenhals. Aber natürlich gibt es einen Overhead.
Dein Argument mit dem Mock kann ich nicht nachvollziehen. Wieso solltest du Abhängigkeiten von Eigenschaften nicht auflösen können?
Weil das eine Syntax-Eigenschaft vieler Programmierersprachen, auch PHP, ist. Aus $a->Dings generiert er einen Zugriff auf ein Field, und keinen Methodenaufruf getDings(). Und den kannst du nur mit magischen Methoden umleiten.
Vielleicht, kannst du mir an folgendem (notwendigerweise pathologischem) Beispiel mal das Problem erklären:
interface Persistable {
$database : PDO;
function persist ();
}
class Model implements Persistable {
// ...
}
class PersistenceTest extends \PHPUnit\Framework\TestCase {
public function testPersistence () {
// Mock a database-connection
$pdo = $this->getMockBuilder(\PDO::class)->setMethods(['commit'])->getMock();
// Expect that the commit-method is called on the connection
$pdo->expects($this->once())->method('commit');
// Inject the mocked database-connection into our test-candidate
$model = new Model();
$model->database = $pdo;
$model->persist();
}
}