Pourquoi PHP Trait ne peut pas implémenter d'interfaces?

je me demande pourquoi PHP Trait (PHP 5.4) ne peut pas implémenter d'interfaces.

mise à Jour de user1460043 réponse => ...ne peut pas exiger la classe qui l'utilise pour implémenter une interface spécifique

je comprends qu'il pourrait être évident, parce que les gens pourraient penser que si un Class A utilise un Trait T qui met en œuvre un interface I , que le Class A devrait mettre en œuvre le interface I indirectement (et ce n'est pas vrai parce que Class A pourrait renommer les méthodes trait).

dans mon cas, mon trait appelle les méthodes à partir de l'interface que la classe utilisant le trait implémente.

le trait est en fait une implémentation de certaines méthodes de l'interface. Donc, je veux "concevoir" dans le code que chaque classe qui veut utiliser mon trait doit implémenter l'interface. Cela permettrait au Trait d'utiliser les méthodes de classe définies par l'interface et être sûr qu'ils existent dans la classe.

65
demandé sur Leto 2013-02-03 00:08:29

3 réponses

la version vraiment courte est plus simple parce que vous ne pouvez pas. Ce n'est pas comme ça que ça marche.

quand vous écrivez use SomeTrait; en PHP vous dites (effectivement) au compilateur de copier et coller le code du Trait dans la classe où il est utilisé.

parce que le use SomeTrait; est dans la classe, il ne peut pas ajouter implements SomeInterface à la classe, parce que cela doit être en dehors de la classe.

"pourquoi ne pas Les types de Traits en PHP? "

parce qu'ils ne peuvent pas être instanciés. Les Traits sont vraiment juste un construction de langage (dire au compilateur de copier et coller le code de trait dans cette classe) par opposition à un objet ou un type qui peut être référencé par votre code.

donc, je veux "concevoir" dans le code que chaque classe qui veulent utiliser mon trait doit implémenter l'interface.

qui peut être appliqué en utilisant une classe abstraite à use le trait et en étendant ensuite les classes à partir de celui-ci.

interface SomeInterface{
    public function someInterfaceFunction();
}

trait SomeTrait {
    function sayHello(){
        echo "Hello my secret is ".static::$secret;
    }
}

abstract class AbstractClass implements SomeInterface{
    use SomeTrait;
}

class TestClass extends AbstractClass {
    static public  $secret = 12345;

    //function someInterfaceFunction(){
        //Trying to instantiate this class without this function uncommented will throw an error
        //Fatal error: Class TestClass contains 1 abstract method and must therefore be 
        //declared abstract or implement the remaining methods (SomeInterface::doSomething)
    //}
}

$test = new TestClass();

$test->sayHello();

cependant - si vous avez besoin d'imposer que toute classe qui utilise un Trait a une méthode particulière, je pense que vous pouvez utiliser des traits où vous auriez dû être des classes abstraites en premier lieu.

Ou que vous avez votre logique à l'envers. Vous êtes censé exiger des classes qui mettent en œuvre les interfaces ont certaines fonctions, non pas que si elles ont certaines fonctions, elles doivent se déclarer comme implémentant une interface.

Modifier

en fait, vous pouvez définir des fonctions abstraites à L'intérieur de Traits pour forcer une classe à mettre en œuvre la méthode. par exemple

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

cependant cela ne vous permet toujours pas d'implémenter l'interface dans le trait, et sent toujours comme une mauvaise conception, comme les interfaces sont beaucoup mieux que les traits pour définir un contrat qu'une classe doit remplir.

77
répondu Danack 2017-05-23 11:54:30

il y a un RFC: Traits avec interfaces suggère ce qui suit pour être ajouté à la langue:

trait SearchItem implements SearchItemInterface
{
    ...
}
Les méthodes

requises par l'interface peuvent être soit implémentées par le trait, soit déclarées comme abstraites, auquel cas on s'attend à ce que la classe qui utilise le trait l'implémente.

cette caractéristique n'est actuellement pas prise en charge par le langage, mais elle est à l'étude (état actuel de la RFC est: Sous La Rubrique ).

14
répondu Ilija 2017-07-21 23:16:18

[...] pour la "conception" dans le code que chaque classe qui souhaite utiliser mon trait doivent implémenter l'interface. Cela permettrait au Trait d'utiliser des méthodes de classe défini par l'interface et être sûr qu'ils existent dans la classe.

cela semble très raisonnable et je ne dirais pas qu'il doit y avoir quelque chose de mal avec votre conception. Des Traits ont été suggérés avec cette idée à l'esprit, voir le deuxième point ici:

  • d'Un trait offre un ensemble de méthodes qui mettent en œuvre des comportements.
  • d'Un trait exige un ensemble de méthodes qui servent de paramètres de la condition de comportement.
  • [...]

Schärli et al, Traits: Composable Units of Behaviour, ECOOP' 2003, LNC 2743, pp. 248-274, Springer Verlag, 2003, Page 2

donc il serait peut-être plus approprié de dire que vous voulez un trait à exiger une interface, pas de" l'implémenter".

Je ne vois pas pourquoi il devrait être impossible d'avoir ce" trait nécessite (ses classes de consommateurs pour implémenter) une interface " dans PHP, mais il semble actuellement manquer.

comme le note @Danack dans sa "réponse , vous pouvez utiliser fonctions abstraites dans le trait pour les "exiger" des classes qui utilisent le trait. Malheureusement, vous ne pouvez pas faire cela avec fonctions privées .

7
répondu user1460043 2017-05-23 12:09:57