Pourquoi PHP a-t-il des interfaces?

35

J'ai remarqué que depuis PHP5, des interfaces ont été ajoutées au langage. Cependant, comme PHP est typé de manière si vague, il semble que la plupart des avantages de l’utilisation des interfaces soient perdus. Pourquoi est-ce inclus dans la langue?

GSto
la source
5
Je pense que la bonne question est, pourquoi pas?
Alberto Fernández le
5
parce qu'ils ne semblent offrir aucun avantage, alors pourquoi les inclure?
GSto
4
@HorusKol et avant leur implémentation, ils n'étaient pas utilisés, vous pouvez donc voir en quoi ils étaient inutilisés et inutiles, juste une version antérieure. Vous devez également faire valoir et soutenir l'affirmation selon laquelle leur utilisation est en quelque sorte une amélioration pour dire qu'ils sont utiles.
Rein Henrichs le
6
@HorusKol Pas spécieux du tout. Il est facile de démontrer la proposition de valeur du marteau. Cette question demande à quelqu'un de démontrer la proposition de valeur des interfaces PHP, et pas seulement de déclarer leur valeur de manière argumentative.
Rein Henrichs
3
Et rappelez-vous que les interfaces ne se limitent pas à la frappe. Une interface est un contrat stipulant qu'une classe d'implémentation doit inclure les méthodes qu'elle expose. Utile pour des choses comme les moteurs de plugins.
Michael

Réponses:

30

Le principal avantage des interfaces en 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 l'accès 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 s'avérer utiles dans diverses situations: http://php.net/manual/en/reserved.interfaces.php .

EDIT - Ajouter un exemple

Si vous avez une interface appelé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 d'effectuer les opérations suivantes:

// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
 if($obj instanceof MyInterface) {
     $obj->a();
     $obj->b();
     $obj->c();
   }
}
psychique
la source
23
En d'autres termes: "vous pouvez ignorer complètement tous les avantages des langages à typage dynamique"
Kamil Tomšík
11
@ Kamil, je pense plutôt à pouvoir tirer parti des avantages du typage statique sans subir les inconvénients lorsque vous ne le souhaitez pas.
Karl Bielefeldt
9
es-tu sérieux? exemple de? si-alors-si-alors-si-alors-tout-le-temps, ne semble-t-il pas familier? ah oui, programmation procédurale.
Kamil Tomšík
23
@Kamil Tomšík Encore une autre insulte au langage de PHP plutôt qu'aux personnes qui l'utilisent avec incompétence. PHP possède tous les outils pour une programmation complète orientée objet. Que vous les utilisiez ou non, cela revient au programmeur. En outre, la programmation procédurale n’est pas un problème en soi.
Lotus Notes
18
@ Kamil - comme c'est étrange, en lisant votre commentaire, on pourrait en venir à la conclusion qu'il n'y a pas de si-s en PO et que, d'une manière ou d'une autre, comme par magie, les choses se passent bien. Sensationnel.
Michael JV
23

PHP est typé de manière vague, mais il peut être fortement typé sur des paramètres tels que les paramètres de méthodes.

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 transmis à drive () doit implémenter l'interface Car, instance de Porsche donnée

Emanuil Rusev
la source
1
Bien sûr, c'est dommage. Vous pouvez cependant avoir une nullvaleur par défaut pour le paramètre.
Emanuil Rusev le
5
mais si cela drivenécessite un Car, passer nullne serait pas très utile quand même ...
HorusKol
7
Ne jamais passer null. Utilisez un objet "Cas spécial" (Google pour l'explication de Martin Fowler).
Martin Blore
2
@Renesis Si vous définissez la valeur par défaut sur null, vous pouvez passer null dans les méthodes à indication de type. (CAR $ car = null) vous permettrait d'appeler cette méthode avec null comme argument. Ce serait une pratique assez stupide cependant. Pourquoi voudriez-vous pouvoir faire cela?
dqhendricks
2
Exemple concret: function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);vous pourriez avoir un $methodNamemais non $securityMode.
Nicole
7

Les interfaces vous permettent de mettre en œuvre le principe d'ouverture-fermeture, de maintenir une base de code faiblement couplée et d'implémenter bon nombre des meilleurs modèles de conception de POO.

Par exemple, si une classe accepte une autre classe en argument:

class A {

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

Votre classe A et votre classe B ont maintenant un couplage étroit, et la classe A ne peut utiliser aucune autre classe que B. La spécification de type garantit que vous disposez du type d'argument correct, mais a désormais 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 (). C’est fondamentalement (mais pas tout à fait) le modèle de conception COMMAND. Pour résoudre le problème, vous devez plutôt saisir indice à l'aide d'une interface plutôt que d'une classe concrète. B voudrait qu’ils implémentent cette interface et soient acceptés en tant qu’argument pour la classe A. De cette façon, la classe A peut accepter n’importe quelle classe qui utilise cette interface en tant qu’argument pour son constructeur.

Ce type de codage est utilisé dans la plupart des modèles de conception OOP et permet de nombreux changements de code plus facilement et ultérieurement. Celles-ci font partie des principes fondamentaux de la programmation AGILE.

dqhendricks
la source
1
Ou toute sous-classe de B
Mez
7

@pjskeptic a une bonne réponse et @Kamil Tomšík a un bon commentaire sur cette réponse.

L'avantage des langages à typage dynamique tels que PHP est que vous pouvez essayer d'utiliser des méthodes sur des objets et que cela ne vous hurle pas sauf si la méthode n'existe pas.

Le problème avec les langages à typage dynamique tels que PHP est que vous pouvez essayer d’utiliser des méthodes sur des objets et que cela vous hurle dessus quand 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 présentes (pas nécessairement qu’elles sont correctes ou qu’elles vont fonctionner). Ce n'est pas une partie nécessaire d'un langage, mais cela rend le codage plus pratique. Il permet aux développeurs OOP fortement typés d'écrire du code PHP fortement typé, qui peut ensuite fonctionner aux côtés de code PHP faiblement typé écrit par un développeur PHP différent.

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 IMHO simple, le code lisible est un meilleur code.

zzzzBov
la source
1
ce que vous faites à la place est simplement de ne pas vérifier la méthode, de planter et de graver lorsque quelqu'un appelle votre fonction avec les mauvaises données. Ce n'est pas ton problème si quelqu'un utilise mal ta fonction.
Raynos
non exactement - votre exemple est un cauchemar pour ceux qui veulent passer n'importe quel "canard" dynamique, comme un proxy, un adaptateur, un décorateur, etc.
Kamil Tomšík
1
@ Kamil? Comment. Un proxy serait une classe wrapper pour quelque chose qui n'implémenterait pas l'interface pour pouvoir être utilisé avec cette fonction.
Tylermac
@tylermac proxy dynamique utilisant __call () - et si __call est la seule méthode, il ne peut tout simplement pas implémenter IBar, ce qui signifie que vous ne pouvez pas le transmettre à foo (IBar $ bar)
Kamil Tomšík le
5

Ils sont complètement inutiles si vous êtes un typeur de canard. En fait, lorsque vous effectuez un typage de canard, il est assez ennuyant de travailler avec des bibliothèques / framework qui utilisent n'importe quel indice de type.

Ceci s'applique également à toutes sortes de méta-programmation dynamique (méthodes magiques).

Kamil Tomšík
la source
3

PHP n'est pas fortement ou faiblement, mais typé dynamiquement .

Au sujet des interfaces, la première chose à laquelle vous devriez vous poser est la suivante: quels sont les avantages de la plupart des interfaces?

En POO, les interfaces ne concernent pas uniquement les types, mais également le comportement.

Etant donné que PHP possède également une fonctionnalité d'indication de type , vous pouvez utiliser des interfaces exactement comme dans un langage simple, 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 l'implémentation d'interface PHP, vous pouvez également créer des simulacres pour des classes abstraites utilisant PHPUnit .

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

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

    // do your assertions
}

En gros, vous pouvez donc avoir une application compatible SOLID en PHP en utilisant les fonctionnalités du langage, l’un d’eux étant les interfaces.

Daniel Ribeiro
la source
0

Les interfaces sont utiles pour l'injection de dépendances beaucoup plus que le béton. Par exemple, à nu:

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

Maintenant, dites si vos besoins changent et que vous souhaitez enregistrer au format PDF. Vous pouvez créer une nouvelle classe à cette fin 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 a maintenant un contrat que les classes qu'elle utilise pour sauvegarder doivent implémenter l'interface Istore. Peu importe où il enregistre ou comment il enregistre.

Pete
la source
-1

Vous pouvez fournir des "vrais" objets réels qui implémentent l'interface. Vous pouvez ensuite tester un peu une partie de votre code sans avoir besoin de vrais serveurs, systèmes de fichiers, sockets, bases de données, etc.

Martin Blore
la source
-3

Beaucoup de gens vont probablement me détester pour avoir répondu de cette façon, mais la solution à vos problèmes de frappe peut être facilement résolue avec PHP. Oui, PHP est typé de manière vague, donc les types sont supposés par défaut, ce qui peut poser certains problèmes, en particulier dans les opérations de comparaison qui posent problème à la plupart des gens. Cela dit, PHP peut être aussi strict que n'importe quel langage fortement typé si vous transposez ce que vous utilisez dans le type que vous souhaitez, puis utilisez des opérateurs de comparaison au niveau du bit. Voici l'exemple le plus simple auquel je puisse penser de ce que je dis:

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

comparer ($ myVar == $ myVar) serait égal à (bool) true

mais comparer ($ myVar === $ myVar) équivaudrait à (bool) false, comme toute comparaison "typée"

J'espère vraiment que les développeurs arrêteront de se disputer à propos de ces choses, si vous avez un problème avec la façon dont PHP fonctionne, programmez-vous en java et restez live et laissez-le vivre, ou utilisez-le de la manière dont il fera ce que vous voulez. Qu'est-ce que le fait de se plaindre à ce sujet fait pour vous? Vous donnez une excuse pour faire la fête toute la journée? Vous faire paraître mieux que quelqu'un d'autre? C'est bien que vous vous sentiez tellement attaché à vous-même que vous vouliez mettre quelqu'un d'autre en mauvais état, mais en réalité c'est votre préférence et imposer vos croyances à quiconque ne fait que les coder de manière à ne pas être à l'aise avec trois causes:

1) Ils vont coder votre chemin mais "en désordre" selon vos normes (pensez, avez-vous déjà vu un programmeur java créer son premier programme PHP ou vice versa? Ce sera la même façon de changer leur méthodologie ou peut-être même pire.)

2) Vous trouverez autre chose pour vous plaindre

3) Il leur faudra probablement plus de temps pour produire. Et peut-être que cela vous donnera une meilleure apparence à court terme, mais l’ensemble de l’équipe semblera pire (rappelez-vous que vous pouvez coder plus lentement que quelqu'un d’autre et que ce n’est pas nécessairement mauvais si l’équipe répond aux résultats attendus dans un délai raisonnable, mais imposer des habitudes à quelqu'un qui a généralement fait un peu plus vite peut finir par ralentir toute votre équipe et donc paraître pire dans un flux de travail très exigeant)

Personnellement, je préfère écrire du code PHP procédural bien que je puisse et ai écrit des programmes complets en utilisant la POO dans différentes langues. Cela étant dit, j’ai vu un bon code OOP et un mauvais code OOP, ainsi qu’un code procédure et un code procédure également erronés ... Cela n’a vraiment rien à voir avec la pratique, mais avec les habitudes que vous utilisez et même alors, beaucoup de choses sont mes sentiments interprétés ... cela ne veut pas dire que je vais parler mal de ces développeurs ou me vanter de "mon chemin est meilleur" BS, c'est juste pour moi, et la société pour laquelle je travaille est jolie heureux de mon travail et j'en suis fier. Il y a des raisons pour lesquelles une norme devrait être établie mais ce que vous incluez dans la norme que vous choisissez est TRÈS important ... Merci de m'avoir permis de m'en vider la poitrine. Passez une bonne journée.

Jake Pogorelec
la source
-4
  1. Les interfaces font partie du paradigme de la programmation orientée objet. C'est donc très utile dans de nombreux cas lorsque vous essayez de créer des pièces orientées objet ou votre système.
  2. Alors. Pourquoi pas? ;-)

Exemples: Vous devez mettre vos données en cache. Comment? Il y a beaucoup de moteurs différents pour la mise en cache, lequel est le meilleur? Qui se soucie de savoir si vous avez une couche abstraite qui a une interface ICacheDriver avec un ensemble de méthodes comme clé, get, put, clear, etc. Mettez-y simplement en œuvre ce dont vous avez besoin dans le projet en cours et modifiez-le quand vous en avez besoin. Ou simple utilisation de toString. Vous avez un ensemble d'objets différents pouvant être affichés. Vous venez d'implémenter l'interface Stringable (qui décrit la méthode toString [il n'y a pas vraiment d'interfaces comme celle-ci en PHP, mais par exemple]) et d'interagir avec votre objet avec (string) $ obj. Il y a tout ce que vous devez faire au lieu de switch (true) {case $ obj isntanceof A1: "do 1"; Pause; ...}

Simple. Donc, il n'y a pas de question "Pourquoi?". Il y a "comment utiliser cela mieux?". ;-) Bonne chance.

Alex Yaroshevich
la source
-5

Je suppose.

PHP est utilisé par de nombreux programmeurs débutants, mais ceux-ci apprennent java au collège.

Après avoir suivi le cours de Programmation 101, ils commencent à harceler Zend. Ils recherchent des fonctionnalités java, car c’est ainsi que l’on leur a appris à penser. Penser à la manière dont vous le faites (ou comprendre le dactylographie) est difficile, à 20 ans.

Zend est pragmatique, il est plus facile d’ajouter cette fonctionnalité que de prétendre qu’elle est exacte depuis le début.
Cela achète également plus d'utilisateurs au lieu de les faire partir, donc ça doit être bon.

Une autre instance de ce processus? Les personnes qui viennent de suivre des cours .NET et Java veulent aussi des Frameworks of Foundation Classes , elles en parlent jusqu'à ce que Zend se développe dans Zend Framework . Cela achète encore plus d'utilisateurs. Et ainsi de suite...

(la seule fonction de la langue de l'équipe PHP est connu pour avoir lutté contre , au fil des ans, est goto)

ZJR
la source
Dans ma vision, PHP12aura probablement toutes les fonctionnalités de syntaxe du monde (j'espère que cela ne deviendra pas une couche d'abstraction, difficile, car c'est ce qui a tué Perl) avec un clin d'œil aux paradigmes fonctionnels et de type de données, et toujours non goto.
ZJR
"C'est difficile, quand tu n'as que 20 ans" Comment l'âge pourrait-il avoir quelque chose à voir avec la compréhension de ces concepts?
Evicatos
Les lycéens de @Evicatos sont en quelque sorte des programmes, mais ils ont généralement de mauvais enseignants, de mauvaises conventions de dénomination, et produisent des blobs impossibles à maintenir. Ils apprennent à programmer dès le début de leurs études, il faut quelques années pour le mettre en place. Ensuite, ils commencent à se démarquer des langues enseignées au cours de leurs premières années d’enseignement, bénies par l’industrie, acclamées par l’académie, et se tournent vers des langues plus pragmatiques et dactylographiées. Je crois que c'est un bushido partagé par de nombreux programmeurs. Là encore, cela pourrait ne pas refléter votre expérience, vous pourriez être un savant autodidacte. Si oui, montre-nous le chemin.
ZJR