Page 1 sur 2

Ma classe membre respecte-t-elle le modèle Objet

Posté : 14 déc. 2008, 03:50
par saturn1
Bonjour je débute en poo.
J'ai commencé par faire brièvement 2 classes pour la gestion du contenu de mon site.
Voici mes classes
<?php
abstract class Membre {
	/** 
	 * Déclarations des membres de la table
	 **/
	private $_pseudo;
	private $_pass;
	private $_xp;
	private $_signature;
	private $_nom;
	private $_prenom;
	private $_age;
	private $_ville;
	private $_departement;
	private $_presentation;
	private $_rang;
	private $_validation;
	private $_banni;
	private $_mail;
	private $_avatar;
	private $_f_sujet_page;
	private $_f_msg_page;
	private $_mp_msg_page;
	private $_mp_mail;
	private $_afficher_signature;
	private $_afficher_msg_cache;
	/**
	 * Déclaration des membres gérant l'administration
	 **/
	 private _canWriteNews = FALSE;
	 private _accessAdmin = FALSE;
	 private _posterCom = TRUE;
	 private _noter = TRUE;
	/**
	 * __construct qui hydrate les membres de la classe.
	 **/
	public function __construct($array) {
		foreach ($array as $key => $value) {
			$key2 = explode('_',$key);
			if (property_exists(get_class(), '_'.$key2[1])) {
				$this->_$key2[1] = $value;
			} else {
				echo '_'.$key2[1]. 'n\'existe pas.'
			}
		}
	}
	
	
	
	/**
	 * Getters Admins
	 **/
	public function getCanWriteNews() {
	  return $this->_canWriteNews;
	}
	public function getAccessAdmin() {
	  return $this->_accessAdmin;
	}
	public function getPosterCom() {
	  return $this->_posterCom;
	}
	public function getNoter() {
	  return $this->_noter;
	}
	/**
	 * Getters membres
	 **/
	public function getPseudo() {
	  return $this->_pseudo;
	}
	public function getXp() {
	  return $this->_xp;
	}
	public function getSignature() {
	  return $this->_signature;
	}
	public function getNom() {
	  return $this->_nom;
	}
	public function getPrenom() {
	  return $this->_prenom;
	}
	public function getAge() {
	  return $this->_age;
	}
	public function getVille() {
	  return $this->_ville;
	}
	public function getDepartement() {
	  return $this->_departement;
	}
	public function getPresentation() {
	  return $this->_presentation;
	}
	public function getRang() {
	  return $this->_rang;
	}
	public function getValidation() {
	  return $this->_validation;
	}
	public function getBanni() {
	  return $this->_banni;
	}
	public function getMail() {
	  return $this->_mail;
	}
	public function getAvatar() {
	  return $this->_avatar;
	}
	public function getFSujetPage() {
	  return $this->_f_sujet_page;
	}
	public function getFMsgPage() {
	  return $this->_f_msg_page;
	}
	public function getMpmsgPage() {
	  return $this->_mp_msg_page;
	}
	public function getMpMail() {
	  return $this->_mp_mail;
	}
	public function getAfficherSignature() {
	  return $this->_afficher_signature;
	}
	public function getAfficherCache() {
	  return $this->_afficher_cache;
	}
	//SET
	public function setPseudo($Pseudo) {
		$this->_pseudo=$Pseudo;
	}
	public function setXp($Xp) {
		$this->_xp=$Xp;
	}
	public function setSignature($Signature) {
		$this->_signature=$Signature;
	}
	public function setNom($Nom) {
		$this->_nom=$Nom;
	}
	public function setPrenom($Prenom) {
		$this->_prenom=$Prenom;
	}
	public function setAge($Age) {
		$this->_age=$Age;
	}
	public function setVille($Ville) {
		$this->_ville=$Ville;
	}
	public function setDepartement($Departement) {
		$this->_departement=$Departement;
	}
	public function setPresentation($Presentation) {
		$this->_presentation=$Presentation;
	}
	public function setRang($Rang) {
		$this->_rang=$Rang;
	}
	public function setValidation($Validation) {
		$this->_validation=$Validation;
	}
	public function setBanni($Banni) {
		$this->_banni=$Banni;
	}
	public function setMail($Mail) {
		$this->_mail=$Mail;
	}
	public function setAvatar($Avatar) {
		$this->_avatar=$Avatar;
	}
	public function setFSujetPage($FSujetPage) {
		$this->_f_sujet_page=$FSujetPage;
	}
	public function setFMsgPage($FMsgPage) {
		$this->_f_msg_page=$FMsgPage;
	}
	public function setMpMsgPage($MpMsgPage) {
		$this->_mp_msg_page=$MpMsgPage;
	}
	public function setMpMail($MpMail) {
		$this->_mp_mail=$MpMail;
	}
	public function setAfficherSignature($AfficherSignature) {
		$this->_afficher_signature=$AfficherSignature;
	}
	public function setAfficherMsgCache($AfficherMsgCache) {
		$this->_afficher_msg_cache=$AfficherMsgCache;
	}	
}


?>
et une classe dérivée
<?php
include 'Membre.php';
class MembreSimple extends Membre {
	public function __construct() {
		parent::__construct($array);
	}
	/**
	 * Poster un commentaire
	 **/
	public function posterCom() {
		if($this->getPosterCom()) {
			//On poste un new com...
		}
	}

}
?>
Quels sont vos avis?
merci !!

Posté : 14 déc. 2008, 12:09
par katagoto
Bonjour,

Je pense qu'il y a un bon début, mais il y a beaucoup trop de méthode et d'attribut, regarde du côté de __get() et __set(), si non, je ne vois pas l'intéret d'avoir membre en parent seulement pour poster un message, voilà mon avis ^^

re re re

Posté : 14 déc. 2008, 14:19
par saturn1
Nan mais c'est le début.
Sinon pour les __get et __set on m'a déconseiller de les utiliser pour
1. Les IDEs et les éditeurs de texte comme VIM, Eclipse, Netbeans... ont besoin des noms de méthodes explicitement définis dans les corps de classe pour assurer l'auto complétion du code. Avec les méthodes magiques, on perd cette fonctionnalité...

2. Ca t'oblige à faire tous les tests de set / get dans une seule et même méthode. Quand tu dois contrôler 3 paramètres ça reste jouable mais lorsque tu as plein d'attributs c'est impensable. Tu te retrouves avec une méthode __set() de plusieurs dizaines, voire centaine de lignes de code. C'est vite inmaintenable.

3. Le debug est moins aisé forcément quand une erreur est généré dans __set() car il faut te replonger dans une méthode de 50 km de long pour localiser l'erreur et la débugger. Avec une bonne vieille méthode setTruc() tu sais où est l'erreur et tu la corriges illico.

4. Les méthodes magiques sont moins performantes que les méthodes explicites.

Le seul avantage à les utiliser c'est pour coder vite sans se prendre la tête, mais là c'est mal...
Sinon la classe MembreSimple est simpliste car un membre à part poster un com,note et parler dans le forum sa s'arrête la.
Mais mes classes dérivés d'administration seront plus costaud!
Merci

Posté : 14 déc. 2008, 18:21
par Sékiltoyai
Enfin, si on va par là, j'aurais tendance à dire :
Pourquoi ne pas supprimer toutes les méthodes get/set et mettre les attributs en public ? Parce que bon, c'est tout de même ultra useless de mettre des setter et des getter pour simplement implémenter l'affectation…

Donc, si on va par là :
1. Les IDEs et les éditeurs de texte comme VIM, Eclipse, Netbeans... ont besoin des noms de méthodes explicitement définis dans les corps de classe pour assurer l'auto complétion du code. Avec les méthodes magiques, on perd cette fonctionnalité...
Dans les IDE, il font aussi super bien l'auto-complétion des attributs…
2. Ca t'oblige à faire tous les tests de set / get dans une seule et même méthode. Quand tu dois contrôler 3 paramètres ça reste jouable mais lorsque tu as plein d'attributs c'est impensable. Tu te retrouves avec une méthode __set() de plusieurs dizaines, voire centaine de lignes de code. C'est vite inmaintenable.
Utiliser des getters/setters donne un code de 500 lignes tout aussi illisible alors que 100 seulement sont utiles…
3. Le debug est moins aisé forcément quand une erreur est généré dans __set() car il faut te replonger dans une méthode de 50 km de long pour localiser l'erreur et la débugger. Avec une bonne vieille méthode setTruc() tu sais où est l'erreur et tu la corriges illico.
Tu peux tout aussi bien te planter lorsque tu fais un getter ou un setter.
4. Les méthodes magiques sont moins performantes que les méthodes explicites.
Quand on utilise une méthode pour accéder à ses attributs, c'est que l'on a déjà prévu de pourrir les performances…

re re re

Posté : 14 déc. 2008, 19:16
par saturn1
Lol lol lol...
Je ne sais plus quoi penser.
Sur un forum on me dit de les déclarer en privé...Et sur un autre en public :D^^

Posté : 14 déc. 2008, 21:20
par Sékiltoyai
Ouais, on a tous nos opinions…
Personnellement je pars du principe que les getters/setters sont un détournement du modèle objet. Si un attribut doit pouvoir être accédé et modifié sans autre condition, il doit être mis en public. Si on se met à changer la manière d'utiliser les objets, c'est qu'ils ne sont plus appropriés et qu'il faut faire évoluer l'outil, pas son utilisation…

Posté : 14 déc. 2008, 21:55
par AB
Ouais, on a tous nos opinions…
Personnellement je pars du principe que les getters/setters sont un détournement du modèle objet. Si un attribut doit pouvoir être accédé et modifié sans autre condition, il doit être mis en public...
Ah bah ça me rassure ne n'être pas le seul à penser ça :wink:

re re re

Posté : 14 déc. 2008, 21:57
par saturn1
Je ne sais que guère penser , je n'ai pas assez d'experience en objet :S.
En tout cas vive ElePHPant

Posté : 15 déc. 2008, 22:51
par Hywan
Hey :),

Il y a autre chose à considérer : l'utilisateur (il faut imaginer une grosse musique à l'américaine qui fait bien peur).

Pourquoi avoir une visibilité (public, protégée, privée) ? C'est au niveau de l'accès aux données pour le programme, pour l'application. On protège les données, donc pas de risques théoriques de se faire avoir. Car, le but de l'objet, c'est de rassembler des données que plusieurs méthodes peuvent manipuler, et personne d'autre (dans la théorie). Donc comment définir les données ? Via des setters. Et comment les obtenir ? Via des getters.

Pourquoi utiliser des méthodes et pas tout mettre en public directement ? L'utilisateur, encore une fois. C'est lui qui nous fait peur. S'il ne connaît pas l'API par cœur, il va mettre un entier à la place d'un booléen, ou une chaîne à la place d'un tableau. Et là, quand on veut manipuler les données dans des méthodes particulières, mince, des erreurs en chaîne !

Alors que si on passe à travers des setters et getters, non seulement on abstrait encore plus la manipulation des données (et plus c'est abstrait, mieux c'est), mais on protège la bonne forme et on assure le bon fonctionnement de l'application.
Par exemple : je veux définir un âge. J'ai un test à faire : l'âge doit appartenir à l'intervalle [0; 150] par exemple. Si on définit publiquement l'âge, on n'a aucun contrôle. On perd donc la bonne forme des données, et on n'est nettement moins assuré du bon fonctionnement de l'application.
Autre exemple, mais pour les getters cette fois : on souhaite obtenir un tableau qui nous « résume » plusieurs données de l'objet. Si on devait à chaque fois tout faire à la main, ce sera long et pénible, alors que là, la méthode le fait pour nous. Encore une fois, on est sûr du résultat de la méthode, tout le monde a le même résultat.

Le principe de l'objet quand même, c'est en partie d'encapsuler les données, et que seul l'objet peut les manipuler. Les données lui appartiennent et si on veut en connaître un petit bout, on doit le demander à l'objet, on doit l'interroger.
Si on ne voit pas trop l'attrait des getters et setters c'est peut-être qu'on n'atomise (ou classifie) pas bien ses données. Si on a toujours de gros traitements à faire, c'est qu'il y a un problème quelque part.

Donc on préfère déclarer les données en protégée ou privée dès le début (par défaut quoi). Moi je choisis de le mettre en protégé pour permettre à l'utilisateur d'étendre mes classes quand il veut. Si on est plus maniaque et restrictif, on aura tendance à tout mettre en privé.
En revanche, si j'ai une classe mère qui a des données que même les enfants ne doivent pas manipuler, évidemment, je mets tout en privé.
Par contre, je mets très rarement des données en publique, pour les raisons évoquées précédemment : la bonne forme des données et l'assurance du bon fonctionnement de l'application. C'est principalement pour la qualité (si on doit voir ça d'un point de vue sécurité).

Je ne vois pas en quoi les getters et setters sont un détournement du modèle objet, c'est un peu … je n'irais pas jusqu'à dire la base, mais c'est incontournable tout de même. Sinon, comment manipuler les données protégées et privées ?

Je vois parfois des gens programmer de cette façon (mais ils viennent de langages dérivés du C++) : ils effectuent les traitements de données protégées ou privées et les mettent dans un attribut public. Bon, … pourquoi pas, ça évite un appel de méthode. C'est pas plus bête, c'est à peine plus rapide, mais il faut être prévenu, c'est un peu bizarre quand on ne s'y attend pas ou qu'on ne connaît pas.

Enfin, pour terminer, ta classe de membre est juste énorme … Dans une logique PHP (si on peut parler ainsi), on aurait tendance à faire un tableau et une méthode qui va chercher dans ce tableau. C'est plus rapide qu'une méthode magique (qui ne sert pas à ça …), plus ordonné pour la maintenance, et plus facile à manipuler (car les données vont sûrement provenir d'une base de données, j'attends avec impatience l'assignation des valeurs provenants d'un fetch assoc, ô joie des tests multiples …).

Petite parenthèse, avant de terminer, sur les méthodes magiques comme __set() et __get(). Elles servent à rendre l'objet plus dynamique, donc soit les données n'existent pas et on les crée à la volée, soit on fait des redirections (attribut vers tableau) etc. Il existe plusieurs possibilités, mais si les attributs existent, le __set ou __get ne sera de toute façon pas appeler …

Autre parenthèse après relecture (mais j'arrête, promis ;-)) : plus c'est abstrait, mieux c'est. J'explique ou tout le monde voit pourquoi ? Pour moi, c'est l'évidence même, mais peut-être pas pour tout le monde …

Posté : 16 déc. 2008, 02:51
par Sékiltoyai
Pourquoi utiliser des méthodes et pas tout mettre en public directement ? L'utilisateur, encore une fois. C'est lui qui nous fait peur. S'il ne connaît pas l'API par cœur, il va mettre un entier à la place d'un booléen, ou une chaîne à la place d'un tableau. Et là, quand on veut manipuler les données dans des méthodes particulières, mince, des erreurs en chaîne !
Soit, mais :
- Tu as vu une seule vérification dans ses setters ?
- Tu as déjà vu dans un setter (à part peut être dans les tiens) des gens qui s'amusaient à faire du contrôle de type ?
- Quand eclipse te génère tes getters/setters (c'est un truc qui revient souvent, à tel point que je me demande pourquoi eclipse ne code pas à notre place s'il est si malin que cela), il te fait ton contrôle de type ?
Et sur la génération de code, beaucoup de monde l'utilise en fait, sauf qu'ils laissent le code généré tel quel. Il est généré donc il est bon hein… Personne ne s'amuse à aller modifier sa méthode parce que la génération de code est en fait pourrie…
Alors que si on passe à travers des setters et getters, non seulement on abstrait encore plus la manipulation des données (et plus c'est abstrait, mieux c'est), mais on protège la bonne forme et on assure le bon fonctionnement de l'application.
Ok, alors continuons sur ma lancée. A savoir que personne ne se fait chier à du contrôle de données (je suis désolé mais c'est le cas). Quelle est la différence entre ces deux codes ?
<?php

class class1
{

    private field;

    public function getField()
    {
        return $this->field;
    }

    public function setField($field)
    {
        $this->field = $field;
    }

}

$class1 = new class1();
$class1->setField('machin');

?>
<?php

class class2
{

    public $field;

}

$class2 = new class2();
$class2->field = 'machin';

?>
Mis à part que j'ai mis quelques secondes à écrire le second…
Je ne vois pas en quoi les getters et setters sont un détournement du modèle objet, c'est un peu … je n'irais pas jusqu'à dire la base, mais c'est incontournable tout de même. Sinon, comment manipuler les données protégées et privées ?
Bah simplement que si les attributs publics existent, ce n'est pas pour rien. Le détournement c'est de recoder exactement le comportement des membres publics, et ce par simple principe que c'est le mal incarné que de laisser l'utilisateur modifier des attributs. Alors si c'est le mal, on ne fait pas de setters.
Petite parenthèse, avant de terminer, sur les méthodes magiques comme __set() et __get(). Elles servent à rendre l'objet plus dynamique, donc soit les données n'existent pas et on les crée à la volée, soit on fait des redirections (attribut vers tableau) etc. Il existe plusieurs possibilités, mais si les attributs existent, le __set ou __get ne sera de toute façon pas appeler …
C'est pour le moins inexact. Le __set ou le __get ne seront pas appelés si l'attribut existe dans la portée de l'appelant. Si l'attribut existe mais qu'il est privé, ils seront appelés…

Posté : 16 déc. 2008, 02:57
par AB
Hey :)... plus c'est abstrait, mieux c'est. J'explique ou tout le monde voit pourquoi ? Pour moi, c'est l'évidence même, mais peut-être pas pour tout le monde …
J'aimerais bien un petit exemple concret notamment pour les setters. Pourquoi ne pas déclarer un attribut public et l'afficher directement ?

Et puis si je contrôle bien l'acquisition des données, je vois pas pourquoi je me méfierais du visiteur pour l'affichage ? Si quand bien même le visiteur trouve un moyen pour modifier l'affichage - d'ailleurs lequel dans la mesure où l'on a contrôlé l'acquisition avant - , à la limite c'est son problème, il peut aussi bien éteindre son ordi pour provoquer un bug. Donc pour moi le côté sécurisé de ce principe est assez mystérieux.

Mais bon ce doit être une histoire de contexte...

Posté : 16 déc. 2008, 11:35
par Hywan
Alors alors,

L'avantage de passer à travers une méthode est tout de même de faciliter l'utilisation par l'utilisateur. Si le setter ne fait que :
$this->attribut = $attribut;
c'est un peu bidon, je vous l'accorde. Ça peut arriver, oui, dans la foulée des autres setters.
Voici ce que je fais systématiquement au minimum :
visibility function setArgument ( $argument = null ) {

    // Test de la bonne forme ou type.
    if(null === $argument)
        throw Exception('This argument must not be null.');

    // On récupère l'ancienne valeur.
    $old            = $this->argument;
    $this->argument = $argument;

    // On retourne l'ancienne valeur.
    return $old;
}
Ici, les setters ont comme fonctionnalité d'être des switches. Ils définissent une nouvelle valeur, mais retourne l'ancienne. C'est une façon de les utiliser, et je l'applique systématiquement. Ne serait-ce que pour ça, c'est très pratique d'avoir une méthode.

Si personne ne fait de contrôle de type dans les setters en PHP, ce n'est pas de ma faute … Les gens trompent leur(s) femme(s) aussi, c'est pas une raison. Ils devraient faire des contrôles de type, de forme etc. Sinon, ça n'a pas plus d'autre intérêt que l'abstraction (qui reste à mes yeux un argument encore assez fort).

Eclipse génère n'importe quoi aussi. Comme tu le dis Sékil', tout code généré est … hum hum. Donc il faut changer d'outils ou le re-programmer, c'est tout. C'est pas un outil qui va décider comment programmer.

Mettre un attribut en public et y accéder directement n'est pas mal, c'est normal, oui. Le problème n'est pas le setter ou le getter : le problème est de mettre un attribut en public. C'est trop dangereux à mes yeux. L'utilisateur peut faire n'importe quoi. Oui, on fait ça en C, mais heureusement que c'est plus fortement typé que PHP et les compilateurs savent trouver des erreurs de typage, sinon, il y aurait le même problème sur les structures, les utilisateurs se trompent énormément (et c'est normal dans une certaine mesure). Mettre les données en protégée, c'est pour les protéger justement ;-).

Pour __set() et __get(), je connais leur utilisation, on ne rentre pas dans les détails, c'est hors-sujet :).


L'importance de l'abstraction.

Pourquoi est-ce important de toujours abstraire l'accès à ses données ?
Oui c'est plus long et lent, c'est évident. Tout comme l'objet est plus lent que le bas-niveau. Mais ça nous offre plus de souplesse, une maintenance facilité, une modulation encore jamais atteinte et un raisonnement proche de réalité.
En Scheme par exemple, c'est très très souvent que l'on voit ceci :

Code : Tout sélectionner

(define head car)
(c'est pour manipuler les streams, super sympa). C'est simplement un alias : si on appelle head, on peut tout aussi bien appeler car, c'est identique ! Oui mais. Pour l'utilisateur, c'est déjà plus parlant (point pas très important mais quand même). Pour la maintenance et la pérennité du code : je change car en :

Code : Tout sélectionner

(define head (lambda (x) (car (force x))))
, l'utilisateur va toujours utiliser head, sans savoir ce qu'y se passe derrière. Pour lui, la mise à jour va rester invisible, sans conséquence immédiate, mais pas seulement pour lui : pour le reste du programme.
C'est aussi le but ici des setters et getters qui participe à l'abstraction de manipulation de données. Si jamais, on décide de regrouper plusieurs attributs dans un tableau. On modifie seulement les méthodes set et get et toute l'application (aussi bien la bibliothèque, que l'application de l'utilisateur etc.) vont s'adapter, et aucune modification à faire.
L'abstraction découple ou casse les liens entre les données, ou du moins : entre l'interface et le fonctionnement. C'est très important, encore une fois, pour moi. Ça peut ne pas l'être pour d'autres, oui, bah chacun fait comme il veut. J'explique pourquoi il est préférable d'utiliser des méthodes et ne pas tout lier ou forcer.

Je dois filer en cours, 'suis déjà super en retard, je mettrai un exemple en PHP (s'il m'en vient) plus tard ;-).

re re re

Posté : 16 déc. 2008, 14:31
par saturn1
Intéressant même si je ne rentrerais pas dans le débat par manque de connaissance.
Sinon tu m'as dit
Enfin, pour terminer, ta classe de membre est juste énorme … Dans une logique PHP (si on peut parler ainsi), on aurait tendance à faire un tableau et une méthode qui va chercher dans ce tableau. C'est plus rapide qu'une méthode magique (qui ne sert pas à ça …), plus ordonné pour la maintenance, et plus facile à manipuler (car les données vont sûrement provenir d'une base de données, j'attends avec impatience l'assignation des valeurs provenants d'un fetch assoc, ô joie des tests multiples …).
Grâce à cela
	public $array = array();
	public function __construct($array) {
		if(sizeof($array) != 0) {
			foreach ($array as $key => $value) {
				$key2 = explode('_',$key);
				$key3 = '_'.$key2[1];
				if (property_exists(get_class(), $key3)) {
					$this->$key3 = $value;
				} else {
					echo '_'.$key2[1]. 'n\'existe pas.';
				}
			}
		}
	}
J'hydrate automatiquement mes propriétés , mais je suis curieux de voir comment tu ferais avec un tableau comme tu me le conseil !
Merci

Posté : 16 déc. 2008, 17:33
par AB
@HyWan
J'avais lu trop vite et on ne parlait pas de la même chose...
Je pensais que tu parlais de la sécurité du code vis à vis de l'extérieur, alors qu'il s'agit de protéger le programmeur lui-même contre une utilisation incorrecte de certaines méthodes.

Posté : 16 déc. 2008, 18:37
par Hywan
@saturn1 :
Ta technique est un peu particulière et pas très performante. Déjà, si ton tableau est vide, la boucle foreach ne fera rien, donc tu peux enlever ton test avec sizeof() (soit dit en passant, sizeof() est un alias de count(), donc préfère utiliser count() directement). Ensuite, tu vérifies si la propriété existe etc. C'est mieux d'utiliser directement un tableau.
Tu aurais un setter qui prendrait en argument un tableau et qui définirait (si l'entrée existe) une valeur. Tu aurais des autres setters moins généraux qui définiraient des valeurs une par une (setAge, setName etc.). Pour le getter, soit tu récupères tout le tableau, soit tu récupères un élément (donc deux getters). Tu veux du code ou c'est bon ?

@AB :
Quand tu parles de l'extérieur, tu parles de quel contexte ?
On distingue 3 contextes : public, qui correspond à partout dans le programme ; protégé, qui correspond à la classe et à sa famille ; et privé, qui correspond à la classe seule. On ne parle pas ici du contexte statique ou global qui ne corresponde pas aux notions abordées en ce moment, ce n'est pas la même chose (et public, protégé ou privé s'appliquent aux statique, dynamique et global).
Tu veux que je re-explique quelque chose ?