102 votes

Avantages et inconvénients des constantes d'interface

Les interfaces PHP permettent de définir des constantes dans une interface, par exemple

interface FooBar
{
    const FOO = 1;
    const BAR = 2;
}
echo FooBar::FOO; // 1

Toute classe d'implémentation disposera automatiquement de ces constantes, par ex.

class MyFooBar implement FooBar
{
}
echo MyFooBar::FOO; // 1

Mon point de vue sur la question est le suivant que tout ce qui est mondial est diabolique . Mais je me demande s'il en va de même pour les constantes d'interface. Étant donné que Codage par rapport à une interface est considérée comme une bonne pratique en général, l'utilisation des constantes d'interface est-elle la seule acceptable en dehors du contexte d'une classe ?

Bien que je sois curieux de connaître votre opinion personnelle et de savoir si vous utilisez ou non les constantes d'interface, je cherche surtout des raisons objectives dans vos réponses. Je ne veux pas que ce soit une question de type sondage. Je suis intéressé par l'effet de l'utilisation des constantes d'interface sur la maintenabilité. Le couplage. Ou les tests unitaires. Comment cela se rapporte-t-il à SOLIDE PHP ? Est-ce qu'il viole les principes de codage qui sont considérés comme des bonnes pratiques en PHP ? Vous voyez le genre

Note : il existe un Question similaire pour Java qui a énuméré quelques bonnes raisons pour lesquelles elles sont une mauvaise pratique, mais comme Java n'est pas PHP, j'ai pensé qu'il était justifié de poser à nouveau la question dans le cadre de la balise PHP.

134voto

ircmaxell Points 74865

Eh bien, je pense que ça se résume à la différence entre bon y suffisant .

Alors que dans la plupart des cas, vous pouvez éviter l'utilisation de constantes en mettant en œuvre d'autres modèles (stratégie ou peut-être flyweight), il y a quelque chose à dire pour ne pas avoir besoin d'une demi-douzaine d'autres classes pour représenter un concept. Je pense que la question qui se pose est de savoir si l'on a besoin d'autres constantes. En d'autres termes, y a-t-il un besoin d'étendre l'ENUM fourni par les constantes de l'interface. Si vous pouvez prévoir d'avoir besoin de l'étendre, alors optez pour un modèle plus formel. Sinon, il peut suffire (il sera suffisamment bon, et donc moins de code à écrire et à tester). Voici un exemple d'une bonne et d'une mauvaise utilisation :

Mauvais :

interface User {
    const TYPE_ADMINISTRATOR = 1;
    const TYPE_USER          = 2;
    const TYPE_GUEST         = 3;
}

C'est suffisant :

interface HTTPRequest_1_1 {
    const TYPE_CONNECT = 'connect';
    const TYPE_DELETE  = 'delete';
    const TYPE_GET     = 'get';
    const TYPE_HEAD    = 'head';
    const TYPE_OPTIONS = 'options';
    const TYPE_POST    = 'post';
    const TYPE_PUT     = 'put';

    public function getType();
}

La raison pour laquelle j'ai choisi ces exemples est simple. Le site User définit un enum de types d'utilisateurs. Il est fort probable que cela s'étende au fil du temps et qu'un autre modèle conviendrait mieux. Mais le HTTPRequest_1_1 est un bon cas d'utilisation, puisque l'enum est défini par la RFC2616 et ne changera pas pendant la durée de vie de la classe.

En général, je ne vois pas le problème des constantes et des constantes de classe comme étant une mondial problème. Je le vois comme un problème de dépendance. C'est une distinction étroite, mais bien définie. Je vois mondial comme dans le cas des variables globales qui ne sont pas appliquées et qui, de ce fait, créent une dépendance globale souple. Mais une classe codée en dur crée une dépendance forcée, et en tant que telle crée une dépendance globale dure. Les deux sont donc des dépendances. Mais je considère que le mondial être bien pire puisqu'elle n'est pas appliquée... C'est pour ça que je n'aime pas mettre dans le même panier... dépendances de classe avec dépendances globales sous la même bannière...

Si vous écrivez MyClass::FOO vous êtes contraint de respecter les détails de l'implémentation de l'option MyClass . Cela crée un couplage dur, qui rend votre code moins flexible, et en tant que tel devrait être évité. Cependant, les interfaces existent pour permettre exactement ce type de couplage. Par conséquent, MyInterface::FOO n'introduit pas de couplage concret. Cela dit, je n'introduirais pas une interface juste pour y ajouter une constante.

Donc si vous utilisez des interfaces, et que vous êtes très que vous (ou n'importe qui d'autre d'ailleurs) n'aurez pas besoin de valeurs supplémentaires, alors je ne vois pas vraiment de problème avec les constantes de l'interface... Les meilleures conceptions n'incluraient pas de constantes, de conditionnels, de nombres magiques, de chaînes magiques ou de codes en dur. Cependant, cela ajoute du temps supplémentaire au développement, car vous devez envisager les utilisations. À mon avis, la plupart du temps, il vaut la peine de prendre le temps supplémentaire nécessaire pour construire une conception solide. Mais il y a des moments où suffisant est vraiment acceptable (et il faut un développeur expérimenté pour comprendre la différence), et dans ces cas-là, c'est très bien.

Encore une fois, ce n'est que mon point de vue sur la question...

10voto

umlcat Points 2025

Je pense qu'il est généralement préférable de gérer les constantes, en particulier les constantes énumérées, comme un type distinct ("classe") de votre interface :

define(TYPE_CONNECT, 'connect');
define(TYPE_DELETE , 'delete');
define(TYPE_GET    , 'get');
define(TYPE_HEAD   , 'head');
define(TYPE_OPTIONS, 'options');
define(TYPE_POST   , 'post');
define(TYPE_PUT    , 'put');

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

ou, si vous voulez utiliser une classe comme espace de nom :

class TypeHTTP_Enums
{
  const TYPE_CONNECT = 'connect';
  const TYPE_DELETE  = 'delete';
  const TYPE_GET     = 'get';
  const TYPE_HEAD    = 'head';
  const TYPE_OPTIONS = 'options';
  const TYPE_POST    = 'post';
  const TYPE_PUT     = 'put';
}

interface IFoo
{
  function /* int */ readSomething();
  function /* void */ ExecuteSomething(/* int */ param);
}

class CBar implements IFoo
{
  function /* int */ readSomething() { ...}
  function /* void */ ExecuteSomething(/* int */ param) { ... }
}

Ce n'est pas que vous n'utilisez que des constantes, vous utilisez le concept de valeurs énumérées ou d'énumérations, qui sont un ensemble de valeurs limitées, considérées comme un type spécifique, avec un usage spécifique ("domaine" ?).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X