Quand j'ai jeté un coup d'oeil dans la documentation de PHP au sujet du InfiniteIterator de la SPL, je trouvais que ça manquait cruellement d'exemples concrets. Boucler sur des chats et des chiens, hum ? Dans quel cas réel est-ce qu'on voudrait poursuivre au début d'une liste lorsqu'on atteint la fin ? Tiens, en musique la gamme chromatique est cyclique, c'est à dire que si on énumère les douze notes possibles et qu'on ajoute un demi-ton à la dernière, la note qui suit est celle qu'on a utilisé au départ, à la différence qu'on sera un octave plus élevé.
Voyons comment on pourrait traduire cet exemple en code, d'abord par une classe simple qui contiendra l'ensemble des notes. Pour ceux moins familiers avec la notation internationale : Do = C, Ré = D, Mi = E, Fa = F, Sol = G, La = A et Si = B. Remarquez, en aucun cas je demande à revenir explicitement au début de la liste, je ne fais que lire l'élément courant ainsi que me déplacer à l'élément suivant.
class ChromaticScale{ private $_notes = array('C', 'C#/Db', 'D', 'D#/Eb', 'E', 'F', 'F#/Gb', 'G', 'G#/Ab', 'A', 'A#/Bb', 'B'); private $_infiniteIterator; public function __construct($key){ if(array_search($key, $this->_notes) === false){ throw new Exception("Key $key does not exists"); } $this->_infiniteIterator = new InfiniteIterator( new ArrayIterator($this->_notes) ); while( $key != $this->_infiniteIterator->current() ){ $this->_infiniteIterator->next(); } } public function currentNote(){ return $this->_infiniteIterator->current(); } public function add($halfSteps){ for($hs = 0; $hs < $halfSteps ; $hs++){ $this->_infiniteIterator->next(); } return $this->_infiniteIterator->current(); } }Maintenant qu'on peut faire une boucle infinie à l'intérieur de la liste de notes, ce serait intéressant de pouvoir générer les gammes majeures et mineures. Pour cela, on aura besoin de connaître les formules d'intervalles.
- Pour la gamme majeure, on choisit une note de départ à laquelle on applique la formule : ton, ton, demi-ton, ton, ton, ton, demi-ton.
- Pour la gamme mineure : ton, demi-ton, ton, ton, demi-ton, ton, ton.
DEFINE('W', 2); // whole step = 2 half steps DEFINE('H', 1); // half step // initialisation $key = 'C#/Db'; $mode = 'major'; $notes = new ChromaticScale($key); $modes = array( 'major' => array(W,W,H,W,W,W,H), 'minor' => array(W,H,W,W,H,W,W) ); $formula = $modes[$mode]; $nbNotes = count($formula); $scale = array(); foreach($formula as $halfSteps){ $scale[] = $notes->currentNote(); $notes->add($halfSteps); } echo '<h1>' . $key . ' ' . $mode . ' scale</h1>'; echo implode(' - ', $scale);Affichage:
C#/Db major scale
C#/Db - D#/Eb - F - F#/Gb - G#/Ab - A#/Bb - C