J'ai remarqué qu'à partir de PHP5, des interfaces ont été ajoutées au langage. Cependant, comme PHP est si peu typé, il semble que la plupart des avantages de l'utilisation des interfaces soient perdus. Pourquoi est-ce inclus dans le langage?
Le principal avantage des interfaces dans PHP est que les classes peuvent implémenter plusieurs interfaces. Cela vous permet de regrouper des classes qui partagent certaines fonctionnalités mais ne partagent pas nécessairement une classe parente. Certains exemples peuvent inclure la mise en cache, la sortie ou accéder aux propriétés de la classe d'une certaine manière.
Dans votre code, vous pouvez vérifier si une classe implémente une interface donnée au lieu de vérifier le nom de la classe. Ensuite, votre code fonctionnera toujours lorsque de nouvelles classes seront ajoutées.
PHP fournit des interfaces prédéfinies qui peuvent être utiles dans diverses situations: http://php.net/manual/en/reserved.interfaces.php .
EDIT - Ajout d'un exemple
Si vous avez une interface nommée MyInterface et que vous travaillez avec plusieurs objets de classes différentes qui peuvent ou non partager certaines fonctionnalités, les interfaces vous permettent de faire quelque chose comme ceci:
// 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 est typé de manière lâche, mais il peut être fortement typé sur des choses comme les paramètres de méthode.
Prenons l'exemple suivant:
interface Car { function go(); }
class Porsche { function go() {} }
function drive(Car $car) {}
$porsche = new Porsche();
drive($porsche);
Le code ci-dessus afficherait:
L'argument 1 passé à drive () doit implémenter l'interface Car, instance de Porsche donnée
Les interfaces vous permettent d'implémenter le principe ouvert-fermé, de maintenir une base de code faiblement couplée et d'implémenter bon nombre des meilleurs modèles de conception OOP.
Par exemple, si une classe accepte une autre classe comme argument:
class A {
public function __construct(B $class_b) {
// use class b
$class_b->run();
}
}
Vos classes A et B ont maintenant un couplage étroit, et la classe A ne peut utiliser aucune autre classe que B et ses sous-classes. L'indication de type garantit que vous avez le bon type d'argument, mais a maintenant cimenté la relation entre A et B.
Disons que vous voulez que la classe A puisse utiliser tous les types de classes qui ont une méthode run () cependant. Il s'agit essentiellement (mais pas tout à fait) du modèle de conception COMMAND. Pour résoudre, vous devez plutôt taper hint en utilisant une interface au lieu d'une classe concrète. B implémenterait alors cette interface et sera accepté comme argument pour la classe A. De cette façon, la classe A peut accepter n'importe quelle classe qui utilise cette interface comme argument pour son constructeur.
Ce type de codage est utilisé dans la plupart des modèles de conception OOP, et permet de modifier BEAUCOUP plus facilement le code ultérieurement. Ceux-ci font partie des principes fondamentaux de la programmation AGILE.
class A {
public function __construct(C $interface_c) {
// use any class that implements interface C
$interface_c->run();
}
}
interface C {
public function run();
}
class B implements C {
public function run() {
// do something
}
}
@pjskeptic a ne bonne réponse , et @Kamil Tomšík a un bon commentaire sur cette réponse.
La grande chose au sujet des langages typés dynamiquement comme PHP est que vous pouvez essayer d'utiliser des méthodes sur des objets et cela ne vous hurlera pas à moins que la méthode ne soit pas là.
Le problème avec les langages typés dynamiquement comme PHP est que vous pouvez essayer d'utiliser des méthodes sur des objets et il vous hurlera lorsque la méthode n'est pas là.
Les interfaces ajoutent un moyen pratique d'appeler des méthodes sur un objet inconnu et d'être certain que les méthodes sont là (pas qu'elles soient nécessairement correctes ou qu'elles fonctionnent). Ce n'est pas une partie nécessaire d'une langue, mais cela rend le codage plus pratique. Il permet aux développeurs fortement typés OOP d'écrire du code fortement typé PHP, qui peut ensuite fonctionner avec du code vaguement écrit PHP code écrit par un autre développeur PHP.
une fonction comme:
foo( IBar $bar )
{
$baz = $bar->baz();
...
}
est plus pratique que:
foo( $bar )
{
if ( method_exists( $bar, 'baz' ) )
{
$baz = $bar->baz();
}
else
{
throw new Exception('OMGWTF NO BAZ IN BAR!');
}
...
}
et à mon humble avis, un code simple et lisible est un meilleur code.
Ils sont complètement inutiles si vous êtes un type de canard, en fait lorsque vous faites de la frappe de canard, c'est assez ennuyeux de travailler avec des bibliothèques/framework qui utilisent n'importe quel indice de type.
Cela s'applique également à toutes sortes de méta-programmation dynamique (méthodes magiques).
PHP n'est pas lâche ou fortement, mais typé dynamiquement .
Concernant les interfaces, la première chose que vous devez vous demander est: quels sont les avantages principaux des interfaces?
Dans la POO, les interfaces ne concernent pas seulement les types, mais aussi le comportement.
Étant donné que PHP a également un type hint feature , vous pouvez utiliser des interfaces comme vous le feriez dans un langage purement oo, tel que 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
}
}
}
Avec PHP, vous pouvez également créer des maquettes pour les classes abstraites en utilisant PHPUnit - et c'est une sacrée fonctionnalité:
public function testSomething()
{
$mock = $this->getMockForAbstractClass('File');
$mock->expects($this->once())
->method('getLines')
->will($this->returnValue(array()));
// do your assertions
}
Donc, en gros, vous pouvez avoir une application compatible SOLIDE dans PHP en utilisant les fonctionnalités du langage, l'une d'entre elles étant des interfaces .
Les interfaces sont beaucoup plus utiles pour l'injection de dépendances que pour le béton. À titre d'exemple barebones:
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);
Dites maintenant si vos besoins changent et que vous souhaitez enregistrer au format PDF. Vous pouvez créer une nouvelle classe à cet effet au lieu de polluer la classe 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);
La classe Article dispose désormais d'un contrat que les classes qu'elle utilise pour enregistrer doivent implémenter l'interface Istore. Peu importe où il enregistre ou comment il enregistre.