2010-09-29 17 views
7

Je connais les avantages de chaîner au sein de PHP, mais permet de dire que nous avons cette situation suivanteEffets de la méthode enchaînant

$Mail = new MailClass("mail") 
     ->SetFrom("X") 
     ->SetTo("X") 
     ->SetSubject("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->AddRecipient("X") 
     ->Send(); 

Y a-t-il des problèmes avec le retour et la réutilisation de l'objet, encore et encore, des questions telles que vitesse ou le non-respect meilleures pratiques

également une bonne lecture sur cette option si votre nouveau chez-Courant Interface: Martin Fowler on Fluent-Interfaces

Je comprends parfaitement qu'il ne ont à programmer cette façon, et peut être manipulé comme ceci:

$Mail = new MailClass("mail"); 
$Mail->AddRecipien(
    array(/*.....*/) 
); 
$Mail->SetFrom("X"); 
$Mail->SetTo("X"); 
$Mail->SetSubject("X"); 
$Mail->Send(); 

mais permet de dire que j'ai un objet comme ceci:

$Order = new Order() 
     ->With(22,'TAL') 
     ->With(38,'HPK')->Skippable() 
     ->With(2,'LGV') 
     ->Priority(); 

Remarque le ->With(38,'HPK')->Skippable(), c'est l'exemple parfait d'un Pro pour ce type de programmation

+0

Les classes doivent, IMO, valider leurs arguments pour l'instanciation et tester/contrôler les arguments de leurs méthodes. Dans ma classe mailer, is_valid_email est une méthode privée dans la classe. – AutoSponge

+0

le "-> Avec (38, 'HPK') -> Skippable()" La situation n'est pas nescecarly un problème, par exemple dans ce scénario vous/la classe peut savoir que Skippable s'applique au dernier Avec cela a été ajouté. – Hannes

+2

Oui mais le facteur de lisibilité est supérieur aux méthodes normales de compilation de ce bloc de code. C'est juste un pro pour la lisibilité – RobertPitt

Répondre

5

Si vous devez valider quelque chose, je pense qu'il est plus logique de le valider dans le AddRecipient Meth od lui-même, mais la performance devrait être à peu près la même chose. Et je ne suis pas au courant des inconvénients généraux de l'utilisation de la méthode de chaînage.

1

EDIT: Mise à jour de réponse pour correspondre à la question
Les appels de fonction sont plus lentes que les boucles, à savoir enchaînant par exemple la méthode addRecipient() dégrade les performances un peu petit par rapport à appeler une méthode addRecipients() qui prend un tableau qui est ensuite traitée dans une boucle. En outre, une méthode plus sophistiquée enchaînant aux API courantes peut nécessiter une comptabilité supplémentaire des données liées à la dernière méthode appelée afin que l'appel suivant puisse continuer à travailler sur ces données car toutes les méthodes retournent le même objet sur lequel la chaîne est construit. Jetons un coup d'oeil à votre exemple:

... 
->With(22, 'TAL') 
->With(38, 'HPK')->Skippable() 
->With(2, 'LGV') 
... 

Cela vous oblige à rappeler que Skippable() doit être appliqué à (38, 'HPK') plutôt que (22, 'TAL').

Vous remarquerez à peine une perte de performance à moins que votre code ne soit appelé très fréquemment dans une boucle ou lorsque vous avez tant de demandes simultanées à votre serveur web de sorte qu'il se rapproche de ses limites (ce qui est le cas sites Web de chargement). Un autre aspect est que le modèle de chaînage de méthode impose l'utilisation d'exceptions aux erreurs de signal (ce que je ne dis pas est une mauvaise chose, il diffère simplement du style de codage classique "appel et vérification de la fonction").

Il y aura cependant généralement des fonctions qui donnent d'autres valeurs que l'objet auquel elles appartiennent (par exemple celles qui retournent le statut de l'objet et des accesseurs). Il est important que l'utilisateur de votre API puisse déterminer quelles fonctions sont chaînables et lesquelles ne le sont pas sans avoir à se référer à la documentation chaque fois qu'il rencontre une nouvelle méthode (par exemple, une directive indiquant que tous les mutateurs et mutateurs supportent le chaînage).


réponse à la question initiale:

[...] The issues i have with chaining is the fact that you cant really perform extra validation [...]

Vous pouvez également mettre en œuvre une méthode de validation dédié que vous appelez après avoir réglé toutes les propriétés et l'ont vous retourner un tableau d'échecs de validation (qui peuvent être des chaînes de caractères ou des objets, par exemple nommés ValidationFailure).

0

Il s'agit d'une épée à double tranchant.

Le bon côté? C'est plus propre que de ré-adresser la classe et bien que ce soit principalement un changement de syntaxe, cela va accélérer un peu le traitement. Il serait préférable de boucler ce type de chaîne plutôt que de boucler chaque appel en forme longue.

Le mauvais côté? Cela causera des problèmes de sécurité lorsque les gens s'y habitueront. Soyez diligent dans votre purification des vars entrants sur ceci afin que vous ne passiez pas quelque chose là vous ne devriez pas. Ne pas trop compliquer vos cours.

  1. Pré-validez vos informations.
  2. Veuillez pré-autoriser vos utilisateurs.

Je ne vois aucun problème à enchaîner ces méthodes dans une boucle, dans le sens des performances.

2

Vous chaîne ne peut pas directement à partir de l'instanciation de classe:

$Mail = new MailClass("mail") 
      ->SetFrom("X") 
      ->SetTo("Y"); 

vous devez instancier d'abord, puis la chaîne contre l'objet instancié:

$Mail = new MailClass("mail") ; 
$Mail->SetFrom("X") 
    ->SetTo("Y"); 

Si vous validez dans les méthodes de réglage individuels (comme vous le devriez), vous devez vous assurer que vous jetez des exceptions lorsqu'une erreur de validation est rencontrée. Vous ne pouvez pas simplement renvoyer un booléen faux en cas d'erreur, sinon le chaînage essaiera d'appeler la méthode suivante par un booléen plutôt que par votre instance de classe et vous obtiendrez.

Fatal error: Call to a member function SetSubject() on a non-object in C:\xampp\htdocs\oChainTest.php on line 23

si vous jetez des exceptions, vous pouvez envelopper la chaîne dans les try ... catch

$Mail = new MailClass("mail"); 
try { 
    $Mail->SetFrom("X") 
     ->SetTo("Y") 
     ->SetSubject("Z"); 
} catch (Exception $e) { 
    echo $e->getMessage(); 
} 

mais comme un avertissement, cela laissera l'instance dans un état partiellement mis à jour, il n'y a pas rollback (sauf si vous en écrivez un vous-même) pour les méthodes qui ont validé/exécuté avec succès, et les méthodes qui suivent l'exception ne seront pas appelées.

+2

Une solution de rechange à cela est l'utilisation de méthodes d'usine pour instancier des objets et des chaînes à partir de là, par exemple 'MailClass :: create ('mail') -> setFrom ('X')'. L'inconvénient des versions de PHP antérieures à la version 5.3 est qu'elles n'ont pas de liaison statique en retard, c'est-à-dire que les méthodes statiques se réfèrent à la classe dans laquelle elles ont été définies. En outre, les appels de méthode statique sont lents. – Archimedix

+0

@Archimedix - point valide, et la liaison statique tardive sera une aubaine (une fois que je peux appliquer mes bibliothèques sont toujours exécutées sur 5.3+) –

+0

J'utilise toujours un registre abstrait avec des méthodes statiques pour instancier des objets et les stocker dans un tableau mon coming come serait 'Registry :: Use (" Mail ") -> X() -> Y-> Z();' où l'initialisation est faite au sein de la méthode: 'Registry :: Use (" Mail ")' – RobertPitt