Accueil > Forum > > > > Interface Iterator et problème de conception.
Interface Iterator et problème de conception.
mardi 27 novembre 2007 à 23:11:16 |
Interface Iterator et problème de conception.

LocalStone
|
Salut à tous, Alors voilà ... Un nouveau post, un nouveau problème  ! Mais par contre, on continue avec l'interface Iterator. Pour un projet, j'ai du coder une classe Map qui a la donnée d'une clé de n'importe quel type (string, int, object, etc.) retourne une valeur. Le fait que la clé soit de n'importe quelle type m'empêche d'utiliser un tableu associatif. Lorsque j'ai codé la classe tout allait bien jusqu'à ce que je me rende compte d'un soucis assez problématique avec la méthode Map::removeValue($mxdKey) ... Mais je ne sais pas s'il vient de ma manière de faire ou bien de PHP. Histoire de bien comprendre le soucis, je vais vous expliquer concrêtement le problème à l'aide d'une classe d'exemple que j'appellerais Conteneur à laquelle on impose les contraintes suivantes : - on doit pouvoir la parcourir avec un foreach() ;
- on doit pouvoir supprimer des élements.
Pour cela, je propose la solution suivante : la classe possède un attribut $Elements du type array() et implémente l'interface Iterator. De plus, la classe possède une méthode Conteneur::supprimerElement($strIndice) qui permet de supprimer l'entrée correspondant à la clé passée en paramètre. Voici donc le code produit ici. Le soucis est le suivant, imaginons ce code ci ... Et bien ça ne marche pas du tout ... Le foreach est cassé lors de la suppression d'un element du tableau ... Et j'ai essayé un tas de truc (mais j'en parle pas pour l'instant, histoire d'induire personne en erreur et de laisser libre cours à votre imagination), mais rien n'y fait. De plus, dans l'exemple que je propose, on essaye de supprimer le premier élement du tableau, donc c'est un cas particulier qui pose problème, mais il y a un problème quelque soit la position de l'élement. Donc voilà ... Si quelqu'un à une idée, une solution, etc. ... Je suis preneur, encore une fois  ! LocalStone
|
|
mardi 27 novembre 2007 à 23:18:08 |
Re : Interface Iterator et problème de conception.

LocalStone
|
Le site où j'ai posté le code les supprime au bout de 24 heures, donc je les remets là aussi, au cas où : La classe Conteneur<?php
class Conteneur implements Iterator { private $Elements = array(); public function __construct($arrElements = array()) { $this -> Elements = $arrElements; } public function supprimerValeur($strIndice) { unset($this -> Elements[$strIndice]); } public function recupererValeur($strIndice) { return $this -> Elements[$strIndice]; } public function key() { return key($this -> Elements); } public function current() { return current($this -> Elements); } public function next() { next($this -> Elements); } public function rewind() { reset($this -> Elements); } public function valid() { return current($this -> Elements) !== false; } }
?> L'exemple
<?php
$arrTableau = array( 'Indice n°1' => 'Salut', 'Indice n°2' => 'Les', 'Indice n°3' => 'Amis', 'Indice n°4' => 'Comment', 'Indice n°5' => 'Allez', 'Indice n°6' => 'Vous' );
$objConteneur = new Conteneur($arrTableau); foreach ($objConteneur as $strIndice => $strValeur) { if ($strIndice == 'Indice n°1') { $objConteneur -> supprimer($strIndice); } else { echo'$arrTableau[' . $strIndice . '] = ' . $strValeur . ';<br />'; } }
?> LocalStone
|
|
mardi 27 novembre 2007 à 23:56:29 |
Re : Interface Iterator et problème de conception.

neigedhiver
|
Salut,
Tu dis :
"De plus, la classe possède une méthode Conteneur::supprimerElement($strIndice)"
Dans le code de ta classe :
public function supprimerValeur($strIndice) {
unset($this -> Elements[$strIndice]);
}
Dans le code exemple :
$objConteneur -> supprimer($strIndice);
Mets-toi d'accord avec toi-même : comment tu veux l'appeler cette méthode ?
En fait, ce sur quoi tu itères, c'est un Array... Utilise simplement la classe ArrayIterator, qui permet déjà de supprimer un élément du tableau avec ArrayIterator::OffsetUnset()
A moins que ta classe n'ait besoin de quelque chose de plus complexe, mais d'après ton exemple, ça ne semble pas être le cas... Ou alors ton exemple n'est pas approprié...
Parce qu'en plus dans ton code, y'a des erreurs.
current ne doit pas retourner le tableau sur lequel tu itères (c'est ce que tu fais) mais l'élément sur lequel le pointeur est positionné.
current() doit donc faire ce que tu fais dans recupererValeur()
Sauf que si à recupererValeur tu passes en argument l'indice de l'élément à récupérer, ta classe n'est plus seulement un itérateur, mais aussi un accesseur.
C'est dommage, ArrayIterator est déjà un accesseur, puisqu'elle implémente ArrayAccess.
Donc je pense que tu te compliques la vie pour pas grand chose ;)
|
|
mercredi 28 novembre 2007 à 00:09:14 |
Re : Interface Iterator et problème de conception.

LocalStone
|
Exacte pour les noms de méthode ... J'ai pas trop vérifier lorsque j'ai viré les 25000 tests. On va l'appeller Conteneur::supprimerValeur() ! Ensuite, je suis bien conscient que ArrayIterator existe et c'est pourquoi j'ai précisé que ma classe d'exemple est naze. Mais dans le problème que j'ai est un peu plus compliqué, et j'aimerais éviter d'utiliser ArrayIterator, même si - au final - cette classe d'exemple risque d'être vraiment semblable a celle de la SPL. Pour être consi, c'est à cause du fait que la clé d'un iterateur ne peut pas être un objet. Dans la classe que je poste, il n'y a pas cette gestion des objets en temps que clé puisqu'ellle sert vraiment d'exemple, mais une fois ce problème résolu, j'ajouterais la possibilité. Bref, en effet, la classe est à la fois un iterateur, mais aussi un accesseur ... Au niveau de l'iterateur, je vois pas trop le soucis. En fait, parcourir mon objet revient au final à parcourir le tableau d'élement ... Donc je pense que les méthodes sont appropriées ... Non ? LocalStone
|
|
mercredi 28 novembre 2007 à 00:32:22 |
Re : Interface Iterator et problème de conception.

malalam
|
Hello,
ce n'est pas la clef d'un itérateur qui ne peut pas être un objet : c'est la clef d'un tableau. Nuance. Tu auras donc exactement le même problème avec ton code, puisque tu utilises...un tableau. Si tu veux vraiment aller vers là -je ne sais pas si c'est possible, et il est un peu tard pour que j'essaye là, même à la va vite-, tu dois implémenter Iterator et ArrayAccess. Ce sont des interfaces. Et gérer ton "tableau" différemment, sans utiliser un vrai tableau. Il y a plein de possibilité en fait, mais il faut tester la plus efficace (et celle qui marche lol).
|
|
mercredi 28 novembre 2007 à 00:40:46 |
Re : Interface Iterator et problème de conception.

LocalStone
|
Ralalala ... Bon, vous ne me laissez pas le choix. En fait, le problème que je présente là, je l'ai rencontré lors du codage de ces classes : <?php /* -------------------- */ class Map implements Iterator, Countable { private $Keys = array(); private $Values = array(); public function put($mxdKey, $mxdValue) { if (!$this -> containsKey($mxdKey)) { array_push($this -> Keys, $mxdKey); array_push($this -> Values, $mxdValue); } else { $this -> Values[$this -> getKeyIndex($mxdKey)] = $mxdValue; } } private function getKeyIndex($mxdKey) { $intIndex = array_search($mxdKey, $this -> Keys); return ($intIndex === false) ? -1 : $intIndex; } public function containsKey($mxdKey) { return in_array($mxdKey, $this -> Keys); } public function containsValue($mxdValue) { return in_array($mxdValue, $this -> Values); } public function getValue($mxdKey) { $intIndex = $this -> getKeyIndex($mxdKey); return ($intIndex < 0) ? null : $this -> Values[$intIndex]; } public function removeValue($mxdKey) { //echo 'Map::removeValue(' . $mxdKey . ')'; $intKeyIndex = $this -> getKeyIndex($mxdKey); if ($intKeyIndex != -1) { unset($this -> Keys[$intKeyIndex]); //prev($this -> Keys); //$this -> Keys = array_values($this -> Keys); unset($this -> Values[$intKeyIndex]); //prev($this -> Values); //$this -> Values = array_values($this -> Values); } } private function getEntryByIndex($intIndex) { //echo 'Map::getEntryByIndex(' . (string)$intIndex . ') == ' . new MapEntry($this -> Keys[$intIndex], $this -> Values[$intIndex], $this) . '<br />'; return new MapEntry($this -> Keys[$intIndex], $this -> Values[$intIndex], $this); } public function current() { $objEntry = $this -> getEntryByIndex($this -> key()); //echo 'Map::current() == ' . $objEntry . '<br />'; return $objEntry;//$this -> getEntryByIndex($this -> key()); } public function key() { return key($this -> Values); } public function next() { //next($this -> Keys); next($this -> Values); } public function rewind() { //reset($this -> Keys); reset($this -> Values); } public function valid() { return current($this -> Values) !== false; } public function __toString() { $arrEntries = $this -> getEntries(); return "{\n\t" . implode(", \n\t", $arrEntries) . "\n}"; } public function getEntries() { $arrEntries = array(); foreach ($this as $objEntry) { array_push($arrEntries, $objEntry); } return $arrEntries; } public function count() { return count($this -> Values); } public function getKeys() { return new Set( array_values( $this -> Keys ) ); } public function getValues() { return new Set( array_values( $this -> Values ) ); } } /* -------------------- */ ?>Je voulais éviter de les poster parce que le code était trop long ... Mais le problème est le même, lors de la suppression d'un élement, lors d'un foreach, le parcour part en freestyle, et ça, bah ça va pas du tout ... Bon, je vais me coucher aussi ... Trop prise de tête  ! Mais j'espère que l'on pourra continuer l'échange dès demain ! LocalStone
|
|
mercredi 28 novembre 2007 à 01:24:50 |
Re : Interface Iterator et problème de conception.

malalam
|
Hello,
avec le foreach() tu ne pourras sans doute jamais : l'offset (foreach($array as $offset => $value) ne peut pas être un objet, à priori. Mais tu peux quand même, foreach() mis à part (mais je peux me tromper sur ce point hein) simuler largement un tableau. J'ai repris ton principe en le simplifiant un peu, avec des exemples (ouais finalement je ne me suis pas couché de suite donc j'ai décidé de te montrer un peu ;-) ) : <?php
class Map implements Iterator, ArrayAccess, Countable { protected $aKeys = array(); protected $aValues = array(); protected $iPos; public function __construct() { $this->rewind(); } public function append($offset, $value) { $this->aKeys[] = $offset; $this->aValues[] = $value; return true; } public function offsetExists($offset) { return in_array($mKey, $this->aKeys); } public function offsetGet($offset) { if(false !== ($mFound = array_search($offset, $this->aKeys))) { return $this->aValues[$mFound]; } return false; } public function offsetSet($offset, $value) { $this->aKeys[] = $offset; $this->aValues[] = $value; return true; } public function offsetUnset($offset) { if(false !== ($mFound = array_search($offset, $this->aKeys))) { unset($this->aValues[$mFound]); unset($this->aKeys[$mFound]); return true; } return false; } public function current() { return $this->aValues[$this->iPos]; } public function key() { return $this->aKeys[$this->iPos]; } public function next() { $this->iPos ++; } public function rewind() { $this->iPos = 0; } public function valid() { return isset($this->aKeys[$this->iPos]); } public function count() { return count($this->aKeys); } }
class A { public function say() { return 'I am a A<br />'; } public function __toString() { return $this->say(); } }
class B { public function say() { return 'I am a B<br />'; } public function __toString() { return $this->say(); } }
$map = new Map; $Ak = new A; $Bv = new B; $Av = new A; $Bk = new B; $map->append($Ak, $Bv); $map->append($Bk, $Av); echo $map[$Ak]; echo '<hr />'; while($map->valid()) { echo $map->key()->say(); echo $map->current()->say(); $map->next(); } ?>
|
|
mercredi 28 novembre 2007 à 01:31:57 |
Re : Interface Iterator et problème de conception.

neigedhiver
|
@Malalam : arrête-moi (si tu peux... non c'est un film ça) si je me trompe, mais l'idée ne serait-elle pas de wrapper l'objet à itérer avec une classe qui permet de simuler un ArrayAccess ?
|
|
mercredi 28 novembre 2007 à 01:42:13 |
Re : Interface Iterator et problème de conception.

malalam
|
C'était mon idée première, mais là j'ai calqué son code. D'ailleurs j'ai oublié un truc dans mon code, essentiel. C'est peut-être le problème rencontré par LocalStone d'ailleurs : quand on supprime une valeur, il FAUT réindexer les 2 tableaux (et de la même manière), parce que sinon on a un trou, et on ne peut plus itérer correctement, forcément, je viens de voir que j'avais oublié ça en relisant mon code. Mais ce n'est pas sorcier, il suffit d'une petite méthode dédiée, pour faire ça.
|
|
mercredi 28 novembre 2007 à 10:55:46 |
Re : Interface Iterator et problème de conception.

LocalStone
|
Pour les offset objet, j'ai abandonné l'idée. Du coup, à la place, le Map::current() retourne une instance de la classe MapEntry qui contient 2 méthodes : MapEntry::getKey() et MapEntry::getValue() qui font ... Bah je vous laisse deviner :P Ok ... Donc au final, si j'ai bien compris, il ne faut pas que j'utilise les pointeurs interne d'un tableau pour itérer la map, mais que j'utilise un attribut spécial qui stocke l'état d'itération (l'équivalent de ton $iPos, Malalam). C'est bien ça ? LocalStone
|
|
Cette discussion est classée dans : problème, classe, clé, interface, iterator
Répondre à ce message
Sujets en rapport avec ce message
[SPL] Une variable objet comme clé de l'interface Iterator [ par LocalStone ]
Salut à tous, Alors voilà ma question : est-il possible d'utiliser l'interface Iterator (ou tout interface qui permettent le parcours d'un objet avec
Méthodologie de codage ... [ par LocalStone ]
Salut à tous ! Alors voilà, j'ai un petit problème de méthodologie ... Je m'explique : Imaginons que l'on ait une classe Cookie, qui modélise - comme
Interface et __toString() [ par syndrael ]
Savez vous s'il est possible d'utiliser __toString() dans une classe qui utilise une interface ?Mon problème est que j'obtiens suite à mon __toString(
Problème avec les quotes [ par Toya78 ]
Bonjour,je suis chargé depuis quelques mois de la réalisation du site Web d'une association.J'ai créé une interface d'administration qui permet de met
Problème variable externe a une classe [ par destiny ]
Bonjour,Ma question est simple, comment recuprer dans une classe un variable constante ? Exemple :define("DEFAULT_PAGE", "welcome");class initPage {
Problème d'insertion de clé étrangère [ par samir1988 ]
BonjourDans ma base de données, j'ai une table 'temperature' et une table 'enceinte'.Dans la table 'enceinte' j'ai une clé primaire appelée : 'idencei
N'êtes vous tous pas suffisamment costaud en PHP ? [ par badjouane ]
Pour solutionner mon problème ?Désolé, mais il me fallait un titre accrocheur et provocateur comme celui-la, pour être certain d'obtenir une certaine
formation clé primaire [ par didou8513 ]
Bonjour, J'espère que je vais ètre assez clair sur mon problème car c'est assez difficile à expliquer.Je possède une base de données oracle et je dois
Problème de variables [ par WaNoU ThE EpSyLoN ]
Bonjours à tous et à toutes,Comment faire pour qu'une variable définie dans une méthode d'une classe soit utilisable dans une autre méthode de cette m
Concaténation d'entier pour clé primaire... [ par stevenleferran ]
Bonjour, voilà mon problème :- chaque client a un numéro unique (100 pour client A , 200 pour client B...).- pour chaque demande d'un client, lors de
Livres en rapport
|
Derniers Blogs
POUR RAPPEL ! LES SPéCIFICATIONS DES PROTOCOLES OFFICE ET SHAREPOINT SONT DISPONIBLES SUR MSDNPOUR RAPPEL ! LES SPéCIFICATIONS DES PROTOCOLES OFFICE ET SHAREPOINT SONT DISPONIBLES SUR MSDN par neodante
Quelle est le point commun entre : Microsoft il y a 10 ans et Apple aujourd'hui ? Réponse: avoir une politique de protocoles propriétaires et fermés :) Car pour rappel (si si je vous assure c'est important de le rappeler), la majorité des spécifications e...
Cliquez pour lire la suite de l'article par neodante JOYEUX ANNIVERSAIRE NIXJOYEUX ANNIVERSAIRE NIX par ebartsoft
Souhaitons un bon et joyeux anniversaire à notre hôte à tous, Nix.
Je ne le répéterais jamais assez mais sans lui rien ne serait possible. Il défit en permanence les lois de la gravité et comme il le dit si bien, si tu lui fais confiance ça devra...
Cliquez pour lire la suite de l'article par ebartsoft IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|