Différentes méthodes communes a différentes classes

Eléphant du PHP | 185 Messages

07 sept. 2008, 17:28

Bonjour,

Je vous expose mon problème.

Je suis en train de faire une petite gestion de formulaire en objet. Je vais expliquer avec un exemple, sinon vous ne comprendrez jamais.
Je me sers de cette page comme référence : http://www.w3.org/TR/html401/interact/f ... edef-INPUT

Comme on peut le voir, les boutons radios et checkboxes peuvent se voir appliquer "checked". Les input text, password et textarea peuvent se voir appliquer "maxlength". De même pour readonly.

Je me demandais comment j'allais faire sans répéter le code de chacune des méthodes utiles à ces fonctions dans chacune des classes.

En fait, j'ai une classe Form_Field.
Form_Input, Form_Textarea héritent de Form_Field.
Form_Text, Form_Checkbox, Form_Password héritent de Form_Input.
etc.

Des méthodes comme setMaxLength() s'appliqueraient à Form_Text, Form_Textarea, Form_Password. D'autres comme setChecked() à Form_Checkbox et Form_Radio. Ces méthodes seraient identiques dans toutes ces classes, d'où je ne veux pas les répéter dans chaque classe...

Y a-t-il un moyen sans passer par ce truc immonde et lent qu'est __call() dans Form_Field.

D'avance merci pour vos réponses.

ViPHP
ViPHP | 2287 Messages

07 sept. 2008, 21:58

Si je comprends bien, ta solution s'appelle l'héritage, non ?
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 185 Messages

08 sept. 2008, 02:50

Hum... Oui, ça marcherait bien. Sauf que chaque classe héite déjà de quelque chose...

ViPHP
ViPHP | 2287 Messages

08 sept. 2008, 10:09

Toutes tes classes n'héritent t-elles pas (directement ou indirectement) de Form_Field ? Dans ce cas, qu'est ce qui t'empêche d'ajouter tes méthodes à Form_Field directement ?
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 185 Messages

08 sept. 2008, 11:10

Rien, c'est juste que dans ce cas on pourrait cocher un textarea... Pas vraiment valide ni propre. C'est pourquoi je cherche une solution "propre".

ViPHP
ViPHP | 2287 Messages

08 sept. 2008, 12:03

Rien, c'est juste que dans ce cas on pourrait cocher un textarea... Pas vraiment valide ni propre. C'est pourquoi je cherche une solution "propre".
Peut-être que tu te poses trop de questions. Je ne vois pas de lien logique évident entre l'existence d'une méthode setChecked() par exemple et le fait qu'on puisse cocher le textarea en question (une simple propriété binaire de l'objet suffirait à différencier les deux cas).
class Checkbox extends form_field{
  public $checkable=true;
  // [...]
}

class Textarea extends form_field{
  public $checkable=false;
  // [...]
}

if($field->checkable){
  $field->setChecked($value);
} else {
  $field->setValue($value);
}
Et c'est tout à fait propre :-)
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 185 Messages

08 sept. 2008, 12:34

Eh bah voilà une solution élégante. :) C'est ce que je cherchais, merci bien.

Je vais juste devoir trouver des jolis noms, parce que maxlengthable ça le fait pas trop. xD

Un grand merci à toi, toutes les 2 solutions que j'avais trouvées passaient par un __call() (que je déteste car c'est super lent).

ViPHP
ViPHP | 2287 Messages

08 sept. 2008, 16:17

Content d'avoir pu t'aider ;-)

Je t'ai donné ici la solution la plus évidente, mais je viens de penser qu'il existe au moins deux autres solutions pour que ton textarea ne soit pas checkable sans même avoir à déclarer de propriété. Tu peux protéger directement la méthode isChecked comme ceci :
class form_field{
  function setChecked($checked){
    //Si l'objet courant n'est pas d'une classe correspondant à un élément cochable,
    //on soulève une exception
    if( ($this instanceof Checkbox) || ($this instanceof Radio) ) {
      $this->checked=$checked;
    } else {
      throw new Exception(__CLASS__.'->'.__METHOD__.'() a été appelée sur un champ non cochable.');
    }
  }

  // [...]
}
Ou bien si l'idée de répertorier les noms de certaines classes filles au niveau de la classe form_field (créant artificiellement des dépendances croisées entre les classes) te parait sale, tu peux aussi utiliser une interface pour déclarer comme cochables uniquement les classes qui le sont et déplacer la condition sur cette interface :
interface Checkable{
    public function setChecked($checked);
}

class Checkbox extends form_field implements Checkable{
  // [...]
}

class Textarea extends form_field{
  // [...]
} 

class form_field{
  public function setChecked($checked){
    //Si l'objet courant n'est pas d'une classe correspondant à un élément cochable,
    //on soulève une exception
    if($this instanceof Checkable) { // instanceof fonctionne aussi avec les interfaces
      $this->checked=$checked;
    } else {
      throw new Exception(__CLASS__.'->'.__METHOD__.'() a été appelée sur un champ non cochable.');
    }
  }

  // [...]
}
if(!@work()){ Nespresso(); } else { what(); }
______________________________

Eléphant du PHP | 185 Messages

08 sept. 2008, 16:33

J'aime pas trop la première version, un peu verbeuse... Mais le coup de l'interface me plaît vraiment ! Je pense que je vais l'adopter. En plus on peut implémenter plusieurs interfaces, donc c'est cool !

J'avais pensé à un __call() dans Form_Field, mais c'est moche.
J'avais pensé à un genre d'interface, mais plus version décorateur en fait. Une classe Checkable qui prend en paramètre une autre classe et qui implémente setChecked() + toutes les méthodes de la classe passée en paramètre via __call(). Encore une fois, pas super joli...

Eléphanteau du PHP | 25 Messages

26 nov. 2008, 23:35

certes l'héritage multiple n'est pas autorisé en php, mais vous pouvez implémenter une interface en utilisant le mot clé implements, mais sachez que ce n'est valable qu'à partir de php5