Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

PHP5 - UTILISATION DES ITÉRATEURS ET DE LA RÉFLECTION.


Information sur la source

Catégorie :Class et Objet ( POO ) Classé sous : poo, reflection, itérateur, iterator, factory Niveau : Expert Date de création : 26/03/2007 Date de mise à jour : 03/04/2007 23:06:40 Vu : 4 813

Note :
9,5 / 10 - par 4 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (24)
Ajouter un commentaire et/ou une note

Description

Pfiou, avec un titre aussi compliqué, j'imagine que je ne vais pas avoir beaucoup de gens qui vont lire une source pareil. Remarquez, je vous comprends ^^

Rentrons dans le vif du sujet.
Kesako tout ca ?

Il y a une multitude de classes ici. Je ne décris pas les classes abstraites volontairement qui sont la que pour assurer une homogéité (?) entre les classes filles.
Donc nous avons :
-> Une classe SQL
-> Une classe factory de news
-> Une classe d'interfacage SQL/factory
-> Une classe d'itération
-> 2 classes de news dont l'une étend l'autre.

Comment est ce que ce beau monde fonctionne ensemble ?
Nous instancions la classe "factory" de news et nous lui disons quelle intérface utiliser (sql, xml, fichier standard... etc).
Nous appelons les méthodes de la factory. La factory utilise l'API de reflection pour utiliser la bonne interface.
C'est cette interface qui va renvoyer la ressource exploitable (ici pour MySQL, on revoit une ressource MySQL. Pour XML c'est un peu différent).
La factory, si il y a plusieurs enregistrements, renverra un itérateur. Autrement, elle renverra une classe de news simple.

Nous allons ensuite parcourir cette itérateur (grace à l'interface Iterator de PHP) pour récupérer chaque enregistrement en nous renvoyons systématiquement un objet (l'objet contenant la news en quelque sorte).
Et par la suite, nous allons pouvoir exploiter cet objet.

Je ne sais pas si je me suis bien fait comprendre (c'est assez dur au début), mais voici le code (il est très commenté) :
 

Source

  • <?php
  • $time = microtime(true);
  • /**
  • * Interface permettant le dialogue entre une interface sortie et la/les news.
  • *
  • */
  • interface iSimpleNewsIO {
  • /**
  • * Récupère la liste entière de news.
  • *
  • */
  • public function GetAll();
  • /**
  • * Récupère une liste de news comprise entre 2 bornes.
  • *
  • * @param int $start
  • * @param int $limit
  • */
  • public function GetRange($start, $limit);
  • /**
  • * Récupère une news à partir de son ID.
  • *
  • * @param int $id
  • */
  • public function GetSingle($id);
  • /**
  • * Récupère la liste entière de news avec leurs nombres de commentaires respectifs.
  • *
  • */
  • public function GetAllWithCommentsCount();
  • /**
  • * Récupère une liste de news comprise entre 2 bornes avec leurs nombres de commentaires.
  • *
  • * @param int $start
  • * @param int $limit
  • */
  • public function GetRangeWithCommentsCount($start, $limit);
  • }
  • /**
  • * Interface permettant le dialogue entre une interface E/S et la news.
  • *
  • */
  • interface iExtendedNewsIO {
  • /**
  • * Ajoute une news.
  • *
  • * @param FullAccessNews $news
  • */
  • public function Insert(FullAccessNews $news);
  • /**
  • * Modifie une news
  • *
  • * @param FullAccessNews $news
  • */
  • public function Update(FullAccessNews $news);
  • /**
  • * Supprime une news.
  • *
  • * @param FullAccessNews $news
  • */
  • public function Delete(FullAccessNews $news);
  • /**
  • * Récupère le nombre de commentaires d'une news.
  • *
  • * @param FullAccessNews $news
  • */
  • public function GetCommentsCount(FullAccessNews $news);
  • }
  • // Classe DateTime déja posté sur PHPCS.
  • require_once ('date.php');
  • /**
  • * Classe d'itération.
  • *
  • * Permet d'utiliser les itérateurs en cas de récupération multiples d'un même éléments
  • * (ex : news, commentaires, pages, liens).
  • * Cette classe renverra un objet utilisable.
  • *
  • */
  • class IterateMe implements Iterator {
  • /**
  • * Renvoit la clé en cours (autoincrément).
  • *
  • * @var int
  • */
  • protected $key;
  • /**
  • * Sortie de la classe... renvoit un objet utilisable.
  • *
  • * @var stdClass
  • */
  • protected $output;
  • /**
  • * Classe qui sera renvoyée à l'output.
  • *
  • * @var ReflectionClass
  • */
  • protected $OutputClass;
  • /**
  • * Classe permettant de faire l'interface avec la récupération de données.
  • *
  • * @var ReflectionClass
  • */
  • protected $InterfaceClass;
  • /**
  • * Requète utilisé pour l'itération (utilisable que sous MySQLi pour le moment).
  • *
  • * @var MySQLi_stmt
  • */
  • protected $query;
  • /**
  • * Instancie l'itérateur.
  • *
  • * @param MySQLi_stmt $query
  • * @param ReflectionClass $InterfaceClass
  • * @param ReflectionClass $OutputClass
  • */
  • public function __construct($query, ReflectionClass $InterfaceClass, ReflectionClass $OutputClass) {
  • $this->key = -1;
  • $this->InterfaceClass = $InterfaceClass;
  • $this->OutputClass = $OutputClass;
  • $this->query = $query;
  • }
  • /**
  • * Retourne la clé en cours.
  • *
  • * @return int
  • */
  • public function Key() {
  • return $this->key;
  • }
  • /**
  • * Pointe vers le prochain élément.
  • *
  • */
  • public function Next() {
  • $this->output = $this->InterfaceClass->getMethod('Next')->invoke(NULL, $this->query, $this->OutputClass);
  • $this->key++;
  • }
  • /**
  • * Rembobine le pointeur.
  • *
  • */
  • public function Rewind() {
  • $this->InterfaceClass->getMethod('Rewind')->invoke(NULL, $this->query);
  • $this->Next();
  • }
  • /**
  • * Affiche l'enregistrement courant du pointeur.
  • *
  • * @return stdClass
  • */
  • public function Current() {
  • return $this->output;
  • }
  • /**
  • * Vérifie si l'output est bien défini, sinon on stop.
  • *
  • * @return bool
  • */
  • public function Valid() {
  • return isset($this->output);
  • }
  • }
  • /**
  • * Classe d'interfacage avec n'importe quel type de platforme de stockage.
  • *
  • */
  • abstract class QueryInterface {
  • /**
  • * Constructeur protégé, cette classe ne sera utilisable qu'en utilisant les namespaces.
  • *
  • */
  • protected function __construct() {
  • throw new Exception('This class can only be used with namespace.');
  • }
  • /**
  • * Methode permettant d'aller au prochain enregistrement lors d'une itération.
  • *
  • * @param resource $resource
  • * @param ReflectionClass $c
  • */
  • abstract static public function Next($resource, ReflectionClass $c);
  • /**
  • * Methode permettant de rembobiner à 0 le pointeur.
  • *
  • * @param resource $resource
  • */
  • abstract static public function Rewind($resource);
  • }
  • abstract class SQLQueryInterface extends QueryInterface {
  • /**
  • * Garde en mémoire les appels de méthodes.
  • *
  • * @var array
  • */
  • static protected $methods = array();
  • /**
  • * Redéfinition de la méthode Next.
  • *
  • * @param MySQLi_stmt $query
  • * @param ReflectionClass $c
  • * @return InstanceOf_ReflectionClass_$c
  • */
  • static public function Next($query, ReflectionClass $c) {
  • return ( $data = $query->fetch_assoc() ) ? $c->newInstance($data) : NULL;
  • }
  • /**
  • * Redéfinition de la méthode Rewind.
  • *
  • * @param MySQLi_stmt $query
  • */
  • static public function Rewind($query) {
  • $query->data_seek(0);
  • }
  • }
  • class SQLSimpleNewsInterface extends SQLQueryInterface {
  • static public function GetTotalNewsCount() {
  • $var = System::GetSQLConnection()->query('SELECT COUNT(*) FROM news')->fetch_row();
  • return (int) $var[0];
  • }
  • static public function GetAllNews() {
  • return System::GetSQLConnection()->query('SELECT * FROM news');
  • }
  • static public function GetRangedNews($start, $limit) {
  • return System::GetSQLConnection()->query('SELECT * FROM news LIMIT '.$start.','.$limit);
  • }
  • static public function GetNews($id) {
  • return System::GetSQLConnection()->query('SELECT * FROM news WHERE id = '.(int) $id)->fetch_array();
  • }
  • static public function GetNewsWithCommentsCount() {
  • return System::GetSQLConnection()->query(
  • 'SELECT news.id, news.title, news.content, news.date, COUNT(comments.id) as nbcomms
  • FROM news, comments
  • WHERE news.id = comments.news_id
  • GROUP BY news.id');
  • }
  • static public function GetRangedNewsWithCommentsCount($start, $limit) {
  • return System::GetSQLConnection()->query(
  • 'SELECT news.id, news.title, news.content, news.date, COUNT(comments.id) as nbcomms
  • FROM news, comments
  • WHERE news.id = comments.news_id
  • GROUP BY news.id
  • LIMIT '.$start.', '.$limit);
  • }
  • }
  • class SQLExtendedNewsInterface extends SQLSimpleNewsInterface {
  • static public function InsertNews(ExtendedNews $news) {
  • return System::GetSQLConnection()->query(
  • 'INSERT INTO news (title, content, date)
  • VALUES ("'.$news->title.'", "'.$news->content.'", "'.$news->date.'")')->affected_rows();
  • }
  • static public function UpdateNews(ExtendedNews $news) {
  • return System::GetSQLConnection()->query(
  • 'UPDATE news SET title = "'.$news->title.'",
  • content="'.$news->content.'", date = '.$news->date->GetTimestamp().'
  • WHERE id = '.$news->id)->affected_rows();
  • }
  • static public function DeleteNews(ExtendedNews $news) {
  • return System::GetSQLConnection()->query(
  • 'DELETE FROM news WHERE id = '.$news->id)->affected_rows();
  • }
  • static public function GetCommentsCountFromNews(ExtendedNews $news) {
  • $data = System::GetSQLConnection()->query('SELECT COUNT(*) FROM comments WHERE news_id = '.$news->id)->fetch_row();
  • return (int) $data[0];
  • }
  • }
  • /**
  • * Classe abstraite gérant toutes les fabs.
  • *
  • */
  • abstract class Factory {
  • /**
  • * Attendu dans le constructeur le nom de l'interface utilisé.
  • *
  • * @param string $InterfaceName
  • */
  • abstract public function __construct($InterfaceName);
  • }
  • class SimpleNewsFactory extends Factory implements iSimpleNewsIO {
  • /**
  • * Nom de l'interface utilisé.
  • *
  • * @var ReflectionClass
  • */
  • static protected $InterfaceClass;
  • /**
  • * Instancie la fab avec l'interface voulu.
  • *
  • * @param string $InterfaceName
  • */
  • public function __construct($InterfaceName = 'SQLSimpleNewsInterface') {
  • try {
  • self::$InterfaceClass = new ReflectionClass($InterfaceName);
  • } catch ( ReflectionException $e ) {
  • die( $e->getMessage() );
  • }
  • }
  • public function GetAll() {
  • return new IterateMe(self::$InterfaceClass->getMethod('GetAllNews')->invoke(NULL),
  • self::$InterfaceClass,
  • new ReflectionClass('ReadOnlyNews') );
  • }
  • public function GetRange($start, $limit) {
  • return new IterateMe(self::$InterfaceClass->getMethod('GetRangedNews')->invoke(NULL, $start, $limit),
  • self::$InterfaceClass,
  • new ReflectionClass('ReadOnlyNews') );
  • }
  • public function GetSingle($id) {
  • return new FullAccessNews( self::$InterfaceClass->getMethod('GetNews')->invoke(NULL, $id) );
  • }
  • public function GetAllWithCommentsCount() {
  • return new IterateMe(self::$InterfaceClass->getMethod('GetAllNewsWithCommentsCount')->invoke(NULL),
  • self::$InterfaceClass,
  • new ReflectionClass('ReadOnlyNewsWithComments') );
  • }
  • public function GetRangeWithCommentsCount($start, $limit) {
  • return new IterateMe(self::$InterfaceClass->getMethod('GetRangedNewsWithCommentsCount')->invoke(NULL, $start, $limit),
  • self::$InterfaceClass,
  • new ReflectionClass('ReadOnlyNewsWithComments') );
  • }
  • }
  • class ExtendedNewsFactory extends SimpleNewsFactory implements iExtendedNewsIO {
  • public function __construct($InterfaceName = 'SQLExtendedNewsInterface') {
  • parent::__construct($InterfaceName);
  • }
  • public function Insert(FullAccessNews $news) {
  • if ( self::$InterfaceClass->getMethod('InsertNews')->invoke(NULL, $news) !== 1 )
  • throw new Exception('Impossible to add newsitem !');
  • return true;
  • }
  • public function Update(FullAccessNews $news) {
  • if ( self::$InterfaceClass->getMethod('UpdateNews')->invoke(NULL, $news) !== 0 )
  • throw new Exception('Impossible to add newsitem !');
  • return true;
  • }
  • public function Delete(FullAccessNews $news) {
  • if ( self::$InterfaceClass->getMethod('DeleteNews')->invoke(NULL, $news) !== 1 )
  • throw new Exception('Impossible to delete newsitem !');
  • return true;
  • }
  • public function GetCommentsCount(FullAccessNews $news) {
  • return self::$InterfaceClass->getMethod('GetCommentsCountFromNews')->invoke(NULL, $news);
  • }
  • }
  • abstract class News {
  • protected $id;
  • protected $title;
  • protected $content;
  • protected $date;
  • public function __construct($params) {
  • $this->id = $params['id'];
  • $this->title = $params['title'];
  • $this->content = $params['content'];
  • $this->date = new oDate($params['date']);
  • }
  • public function __get($var) {
  • if ( property_exists($this, $var) )
  • return $this->$var;
  • else
  • throw new Exception($var.' doesn\'t exists !');
  • }
  • abstract public function __set($var, $val);
  • }
  • class ReadOnlyNews extends News {
  • public function __set($var, $val) {
  • throw new Exception('SimpleNews is a read-only class !');
  • }
  • }
  • class ReadOnlyNewsWithComments extends ReadOnlyNews {
  • protected $coms_count;
  • public function __construct($params) {
  • parent::__construct($params);
  • $this->coms_count = $params['coms_count'];
  • }
  • }
  • class FullAccessNews extends News {
  • public function __set($var, $val) {
  • if ( property_exists($var, $val) )
  • $this->$var = $val;
  • else
  • throw new Exception($var.' doesn\'t exists !');
  • }
  • }
  • class System {
  • static private $_mods = array();
  • static private $_criticals = array();
  • static public function GetModule($ModuleName, $InterfaceName=null) {
  • if ( !isset(self::$_mods[$ModuleName]) ) {
  • $ClassMod = new ReflectionClass($ModuleName);
  • if ( isset($InterfaceName) ) {
  • self::$_mods[$ModuleName]['instance'] = $ClassMod->newInstance($InterfaceName);
  • self::$_mods[$ModuleName]['interface'] = $InterfaceName;
  • } else {
  • $params = $ClassMod->getConstructor()->getParameters();
  • self::$_mods[$ModuleName]['interface'] = $params[0]->getDefaultValue();
  • self::$_mods[$ModuleName]['instance'] = $ClassMod->newInstance();
  • }
  • unset($ClassMod);
  • }
  • return self::$_mods[$ModuleName]['instance'];
  • }
  • static public function GetSQLConnection() {
  • if ( !isset(self::$_criticals['sql']) )
  • self::$_criticals['sql'] = new mysqli('localhost', 'root', '', 'blog');
  • return self::$_criticals['sql'];
  • }
  • static public function GetXMLConnection() {
  • //
  • }
  • }
  • // Instanciation de la classe.
  • $NewsFab = System::GetModule('SimpleNewsFactory');
  • // Pour une itération simple :
  • $news = $NewsFab->GetSingle(1);
  • echo $news->id.'<br />'.$news->title.'<br />'.$news->content.'<br/><br />';
  • echo '<br /><br /><br />';
  • // Pour une itération multiple :
  • $allnews = $NewsFab->GetRange(0,3);
  • foreach ( $allnews as $key=>$line) {
  • echo $line->date.' - '.$line->title.'<br />';
  • echo $line->content.'<br /><br />';
  • }
  • echo '<br /><br /><br />';
  • // Ou alors :
  • foreach ( $NewsFab->GetRange(5,5) as $key=>$line ) {
  • echo $line->date.' - '.$line->title.'<br />';
  • echo $line->content.'<br /><br />';
  • }
  • //Même technique qu'au dessus.
  • echo '<br /><br /><br />';
  • echo microtime(true)-$time;
  • ?>
<?php
$time = microtime(true);
/**
 * Interface permettant le dialogue entre une interface sortie et la/les news.
 *
 */
interface iSimpleNewsIO {
	/**
	 * Récupère la liste entière de news.
	 *
	 */
	public function GetAll();
	/**
	 * Récupère une liste de news comprise entre 2 bornes.
	 *
	 * @param int $start
	 * @param int $limit
	 */
	public function GetRange($start, $limit);
	/**
	 * Récupère une news à partir de son ID.
	 *
	 * @param int $id
	 */
	public function GetSingle($id);
	/**
	 * Récupère la liste entière de news avec leurs nombres de commentaires respectifs.
	 *
	 */
	public function GetAllWithCommentsCount();
	/**
	 * Récupère une liste de news comprise entre 2 bornes avec leurs nombres de commentaires.
	 *
	 * @param int $start
	 * @param int $limit
	 */
	public function GetRangeWithCommentsCount($start, $limit);	
}
/**
 * Interface permettant le dialogue entre une interface E/S et la news.
 *
 */
interface iExtendedNewsIO {
	/**
	 * Ajoute une news.
	 *
	 * @param FullAccessNews $news
	 */
	public function Insert(FullAccessNews $news);
	/**
	 * Modifie une news
	 *
	 * @param FullAccessNews $news
	 */
	public function Update(FullAccessNews $news);
	/**
	 * Supprime une news.
	 *
	 * @param FullAccessNews $news
	 */
	public function Delete(FullAccessNews $news);
	/**
	 * Récupère le nombre de commentaires d'une news.
	 *
	 * @param FullAccessNews $news
	 */
	public function GetCommentsCount(FullAccessNews $news);
}



// Classe DateTime déja posté sur PHPCS.
require_once ('date.php');

/**
 * Classe d'itération.
 * 
 * Permet d'utiliser les itérateurs en cas de récupération multiples d'un même éléments
 * (ex : news, commentaires, pages, liens).
 * Cette classe renverra un objet utilisable.
 *
 */
class IterateMe implements Iterator {
	
	/**
	 * Renvoit la clé en cours (autoincrément).
	 *
	 * @var int
	 */
	protected $key;
	/**
	 * Sortie de la classe... renvoit un objet utilisable.
	 *
	 * @var stdClass
	 */
	protected $output;
	/**
	 * Classe qui sera renvoyée à l'output.
	 *
	 * @var ReflectionClass
	 */
	protected $OutputClass;
	/**
	 * Classe permettant de faire l'interface avec la récupération de données.
	 *
	 * @var ReflectionClass
	 */
	protected $InterfaceClass;
	/**
	 * Requète utilisé pour l'itération (utilisable que sous MySQLi pour le moment).
	 *
	 * @var MySQLi_stmt
	 */
	protected $query;
	
	/**
	 * Instancie l'itérateur.
	 *
	 * @param MySQLi_stmt $query
	 * @param ReflectionClass $InterfaceClass
	 * @param ReflectionClass $OutputClass
	 */
	public function __construct($query, ReflectionClass $InterfaceClass, ReflectionClass $OutputClass) {
  $this->key = -1;
  $this->InterfaceClass = $InterfaceClass;
  $this->OutputClass = $OutputClass;
  $this->query = $query;
	}

	/**
	 * Retourne la clé en cours.
	 *
	 * @return int
	 */
	public function Key() {
		return $this->key;
	}
	/**
	 * Pointe vers le prochain élément.
	 *
	 */
	public function Next() {
		$this->output = $this->InterfaceClass->getMethod('Next')->invoke(NULL, $this->query, $this->OutputClass);
		$this->key++;
	}
	/**
	 * Rembobine le pointeur.
	 *
	 */
	public function Rewind() {
		$this->InterfaceClass->getMethod('Rewind')->invoke(NULL, $this->query);
		$this->Next();
	}
	/**
	 * Affiche l'enregistrement courant du pointeur.
	 *
	 * @return stdClass
	 */
	public function Current() {
		return $this->output;
	}
	/**
	 * Vérifie si l'output est bien défini, sinon on stop.
	 *
	 * @return bool
	 */
	public function Valid() {
		return isset($this->output);
	}
	
}

/**
 * Classe d'interfacage avec n'importe quel type de platforme de stockage.
 *
 */
abstract class QueryInterface {
	/**
	 * Constructeur protégé, cette classe ne sera utilisable qu'en utilisant les namespaces.
	 *
	 */
	protected function __construct() {
		throw new Exception('This class can only be used with namespace.');
	}	
	/**
	 * Methode permettant d'aller au prochain enregistrement lors d'une itération.
	 *
	 * @param resource $resource
	 * @param ReflectionClass $c
	 */
	abstract static public function Next($resource, ReflectionClass $c);
 /**
  * Methode permettant de rembobiner à 0 le pointeur.
  *
  * @param resource $resource
  */
	abstract static public function Rewind($resource);
}
abstract class SQLQueryInterface extends QueryInterface {
	/**
	 * Garde en mémoire les appels de méthodes.
	 *
	 * @var array
	 */
	static protected $methods = array();	
	
	/**
	 * Redéfinition de la méthode Next.
	 *
	 * @param MySQLi_stmt $query
	 * @param ReflectionClass $c
	 * @return InstanceOf_ReflectionClass_$c
	 */
	static public function Next($query, ReflectionClass $c) {
 	return ( $data = $query->fetch_assoc() ) ? $c->newInstance($data) : NULL;
	}
	/**
	 * Redéfinition de la méthode Rewind.
	 *
	 * @param MySQLi_stmt $query
	 */
	static public function Rewind($query) {
		$query->data_seek(0);
	}
	
}

class SQLSimpleNewsInterface extends SQLQueryInterface {
	static public function GetTotalNewsCount() {
	 $var =	System::GetSQLConnection()->query('SELECT COUNT(*) FROM news')->fetch_row();
  return (int) $var[0];
	}
	static public function GetAllNews() {
	 return System::GetSQLConnection()->query('SELECT * FROM news');
	}
	static public function GetRangedNews($start, $limit) {
		return System::GetSQLConnection()->query('SELECT * FROM news LIMIT '.$start.','.$limit);
	}
 static public function GetNews($id) {
 	return System::GetSQLConnection()->query('SELECT * FROM news WHERE id = '.(int) $id)->fetch_array();
 }
 static public function GetNewsWithCommentsCount() {
	 return	System::GetSQLConnection()->query(
	  'SELECT news.id, news.title, news.content, news.date, COUNT(comments.id) as nbcomms 
	   FROM news, comments
	   WHERE news.id = comments.news_id
	   GROUP BY news.id');

 }
 static public function GetRangedNewsWithCommentsCount($start, $limit) {
	 return	System::GetSQLConnection()->query(
	  'SELECT news.id, news.title, news.content, news.date, COUNT(comments.id) as nbcomms 
	   FROM news, comments
	   WHERE news.id = comments.news_id
	   GROUP BY news.id
	   LIMIT '.$start.', '.$limit);
 }
}
class SQLExtendedNewsInterface extends SQLSimpleNewsInterface {
	static public function InsertNews(ExtendedNews $news) {
  return System::GetSQLConnection()->query(
   'INSERT INTO news (title, content, date) 
    VALUES ("'.$news->title.'", "'.$news->content.'", "'.$news->date.'")')->affected_rows();
 }
 static public function UpdateNews(ExtendedNews $news) {
 	return System::GetSQLConnection()->query(
 	 'UPDATE news SET title = "'.$news->title.'",
 	   content="'.$news->content.'", date = '.$news->date->GetTimestamp().'
 	  WHERE id = '.$news->id)->affected_rows(); 	
 }
 static public function DeleteNews(ExtendedNews $news) {
 	return System::GetSQLConnection()->query(
 	 'DELETE FROM news WHERE id = '.$news->id)->affected_rows();
 }
 static public function GetCommentsCountFromNews(ExtendedNews $news) {
 	$data = System::GetSQLConnection()->query('SELECT COUNT(*) FROM comments WHERE news_id = '.$news->id)->fetch_row();
 	return (int) $data[0];
 }
}

/**
 * Classe abstraite gérant toutes les fabs.
 *
 */
abstract class Factory {
	/**
	 * Attendu dans le constructeur le nom de l'interface utilisé.
	 *
	 * @param string $InterfaceName
	 */
	abstract public function __construct($InterfaceName);
}

class SimpleNewsFactory extends Factory implements iSimpleNewsIO {
	/**
	 * Nom de l'interface utilisé.
	 *
	 * @var ReflectionClass
	 */
	static protected $InterfaceClass;
	
	/**
	 * Instancie la fab avec l'interface voulu.
	 *
	 * @param string $InterfaceName
	 */
	public function __construct($InterfaceName = 'SQLSimpleNewsInterface') {
	  try {
	  	self::$InterfaceClass = new ReflectionClass($InterfaceName);
	  } catch ( ReflectionException $e ) {
	  	 die( $e->getMessage() );
	  }
	}
	public function GetAll() {
	 return new IterateMe(self::$InterfaceClass->getMethod('GetAllNews')->invoke(NULL),
	                      self::$InterfaceClass,
	                      new ReflectionClass('ReadOnlyNews') );
	}
	public function GetRange($start, $limit) {
		return new IterateMe(self::$InterfaceClass->getMethod('GetRangedNews')->invoke(NULL, $start, $limit),
		 	                   self::$InterfaceClass,
		 	                   new ReflectionClass('ReadOnlyNews') );
	}
	public function GetSingle($id) {
		return new FullAccessNews( self::$InterfaceClass->getMethod('GetNews')->invoke(NULL, $id) );
	}
	public function GetAllWithCommentsCount() {
	 return new IterateMe(self::$InterfaceClass->getMethod('GetAllNewsWithCommentsCount')->invoke(NULL),
	                      self::$InterfaceClass,
	                      new ReflectionClass('ReadOnlyNewsWithComments') );
	}			
	public function GetRangeWithCommentsCount($start, $limit) {
		return new IterateMe(self::$InterfaceClass->getMethod('GetRangedNewsWithCommentsCount')->invoke(NULL, $start, $limit),
		                     self::$InterfaceClass,
		                     new ReflectionClass('ReadOnlyNewsWithComments') );
	}
	
}

class ExtendedNewsFactory extends SimpleNewsFactory implements iExtendedNewsIO {
	public function __construct($InterfaceName = 'SQLExtendedNewsInterface') {
		parent::__construct($InterfaceName);
	}
	public function Insert(FullAccessNews $news) {
		 if ( self::$InterfaceClass->getMethod('InsertNews')->invoke(NULL, $news) !== 1 )
		      throw new Exception('Impossible to add newsitem !');
	 return true;
	}
	public function Update(FullAccessNews $news) {
		 if ( self::$InterfaceClass->getMethod('UpdateNews')->invoke(NULL, $news) !== 0 ) 
		      throw new Exception('Impossible to add newsitem !');
		return true;		    
	}
	public function Delete(FullAccessNews $news) {
		 if ( self::$InterfaceClass->getMethod('DeleteNews')->invoke(NULL, $news) !== 1 )
		      throw new Exception('Impossible to delete newsitem !');
		return true;
	}
	public function GetCommentsCount(FullAccessNews $news) {
		return self::$InterfaceClass->getMethod('GetCommentsCountFromNews')->invoke(NULL, $news);
	}
}

abstract class News {
	protected $id;
	protected $title;
	protected $content;
	protected $date;

	public function __construct($params) {
		$this->id = $params['id'];
		$this->title = $params['title'];
		$this->content = $params['content'];
		$this->date = new oDate($params['date']);
	}
	
 public function __get($var) {
 	 if ( property_exists($this, $var) ) 
 	      return $this->$var;
 	 else 
 	      throw new Exception($var.' doesn\'t exists !');
 }
 
 abstract public function __set($var, $val);
 
}

class ReadOnlyNews extends News {
	
 public function __set($var, $val) {
 	throw new Exception('SimpleNews is a read-only class !');
 }
 
}
class ReadOnlyNewsWithComments extends ReadOnlyNews {
	protected $coms_count;
	
	public function __construct($params) {
		parent::__construct($params);
		$this->coms_count = $params['coms_count'];
	}
}

class FullAccessNews extends News {
	
	public function __set($var, $val) {
		 if ( property_exists($var, $val) )
		      $this->$var = $val;
		 else 
		      throw new Exception($var.' doesn\'t exists !');
	}

}

class System {
	
	static private $_mods = array();
	static private $_criticals = array();
	
	static public function GetModule($ModuleName, $InterfaceName=null) {
		 if ( !isset(self::$_mods[$ModuleName]) ) {
		      $ClassMod = new ReflectionClass($ModuleName);
		       if ( isset($InterfaceName) ) {
		 	          self::$_mods[$ModuleName]['instance'] = $ClassMod->newInstance($InterfaceName);
		 	          self::$_mods[$ModuleName]['interface'] = $InterfaceName;
		       } else {
		       	    $params = $ClassMod->getConstructor()->getParameters();
		       	    self::$_mods[$ModuleName]['interface'] = $params[0]->getDefaultValue();
		       	    self::$_mods[$ModuleName]['instance'] = $ClassMod->newInstance();
		       }
		      unset($ClassMod);
		 }    
		return self::$_mods[$ModuleName]['instance'];		 	
	}
	
	static public function GetSQLConnection() {
		 if ( !isset(self::$_criticals['sql']) )
		 	     self::$_criticals['sql'] = new mysqli('localhost', 'root', '', 'blog');
		return self::$_criticals['sql'];
	}
	
	static public function GetXMLConnection() {
		//
	}
}



// Instanciation de la classe.
$NewsFab = System::GetModule('SimpleNewsFactory');
// Pour une itération simple :
$news = $NewsFab->GetSingle(1);
echo $news->id.'<br />'.$news->title.'<br />'.$news->content.'<br/><br />';


echo '<br /><br /><br />';


// Pour une itération multiple :
$allnews = $NewsFab->GetRange(0,3);
 foreach ( $allnews as $key=>$line) {
	  echo $line->date.' - '.$line->title.'<br />';
	  echo $line->content.'<br /><br />'; 	
 }

 echo '<br /><br /><br />';
// Ou alors :
 foreach ( $NewsFab->GetRange(5,5) as $key=>$line ) {
	 echo $line->date.' - '.$line->title.'<br />';
	 echo $line->content.'<br /><br />';
 }

//Même technique qu'au dessus.
 echo '<br /><br /><br />';
 
 echo microtime(true)-$time;
?>

Conclusion

Je passe sur la classe DateTime... :)

J'ai utilisé ici un exemple de news.
Mais on peut faire la même chose pour des commentaires, ou alors pour des dossiers ( un dossier avec plusieurs pages ), ou alors pour des liens, ou pour des téléchargements !
Il suffit de créer les classes correspondantes à chaque thème et la classe d'interface qui va avec, puis mettre tout en relation avec la classe d'itération.

C'est un peu compliqué avec la reflection, je vous invite à regarder sur le site officiel de PHP :
http://fr3.php.net/manual/fr/language.oop5.reflection.php

Bonne lecture :)
 

Historique

03 avril 2007 23:06:40 :
Grosse update :) Maintenant tout fonctionne, et c'est plus jolie je trouve ^^

Commentaires et avis

signaler à un administrateur
Commentaire de FhX le 26/03/2007 18:39:02

Je n'ai pas mis de Zip... simplement parce que j'ai oublié :)

signaler à un administrateur
Commentaire de gege217 le 27/03/2007 11:22:02

On dit homogénéité ...
;-)

signaler à un administrateur
Commentaire de vilhjalms le 27/03/2007 14:20:40

"Pfiou, avec un titre aussi compliqué, j'imagine que je ne vais pas avoir beaucoup de gens qui vont lire une source pareil. Remarquez, je vous comprends ^^"

Cela m a plutot attire au dela de votre pseudo :)

Encore une bonne class :) Par contre l absence de zip :( :)

Je ne connaissais pas le principe de reflexion en php merci pour le lien et votre source

signaler à un administrateur
Commentaire de FhX le 27/03/2007 18:31:58

vi, moi et les zip on est faché :p
Jvais voir ce que je peux faire (et rajouter quelques trucs au passage)

signaler à un administrateur
Commentaire de jean84 le 28/03/2007 00:23:05

Super source mais je suis definitivement fache avec les iterateurs. Je n'y comprend vraiment rien.. :-(
Tu n'aurais pas un tuto (genre Les iterateurs pour les gros nulls) ?  Parce que je sens bien que c'est super pratique mais je n'arrive pas a saisir l'idee.

Merci

signaler à un administrateur
Commentaire de FhX le 28/03/2007 14:26:24

ouaip, jvais faire un ptit tuto :)

signaler à un administrateur
Commentaire de jean84 le 28/03/2007 20:25:47

Cool tiens moi au courant ;-)

@+

signaler à un administrateur
Commentaire de guill76 le 29/03/2007 20:33:27

Salut,
C'est une source plutôt sympa et complexe .
Mais j'ai une interrogation sur l'intérêt de la reflexion ici.
j'ai l'impression que c'est une perte en performance que d'utiliser la reflexion pour instancier les objets et invoquer leur methodes.
Personnellement je voyais plutot l'utilité de la reflexion dans la creation de documentation pour les classes, dans les outils de tests ou de debug mais pas trop dans le cadre du dev brut d'un projet.
Mais bon c'est un avis, je me plante peut-être: faudrait voir les perf :-)  

signaler à un administrateur
Commentaire de FhX le 29/03/2007 20:44:52

Le problème, c'est que si je n'utilise pas la reflection, comment je fais pour invoquer mes méthodes et instancier la bonne classe de sortie ?

C'est impossible ( à moins d'utiliser un eval() ce qui est encore plus lent ! ).
Donc il ne reste que la reflection.
Mais jvais essayer d'optimiser encore un peu ca, de toute facon c'est encore incomplet.

signaler à un administrateur
Commentaire de coucou747 le 30/03/2007 07:29:02

bien bien bien... comme je le disais, j'ai encore des progres a faire en OO
c'est joli comme code, un singleton, une factory :)
si t'as des bons trucs sur les design patterns, des trucs plus concret et qui expliquent vraiment l'interret de la chose, je suis prenneur :)

signaler à un administrateur
Commentaire de FhX le 30/03/2007 12:25:41

Disons que j'ai fais la base d'un design pattern avec ce bout de code.
Mais pour que ce soit un vrai design pattern, il me faudrait une abstraction encore plus haute pour gérer les modules (les factorys).

Par exemple, une classe 'System' qui va vérifier dans un fichier xml si le module peut être instancié ou non, renvoyer son instance etc... Un ptit exemple :

<?php
System::Init();
try {
$SQLNewsFactory = System::GetModule('NewsFactory', 'InterfaceSQL');
$XMLNewsFactory = System::GetModule('NewsFactory', 'InterfaceXML');

foreach ( $SQLNewsFactory->GetRange(0,10) as $key=>$news ) {
           $XMLNewsFactory->Add($news);
}

System::Shutdown();

} catch ( ModuleException $e ) {
  echo $e->getMessage();
}
?>

Voila par exemple comment écrire simplement des news provenant d'une base de donnée vers un fichier XML.
La classe System permet de récupérer les instances de modules (après leurs vérifications d'existances), et ensuite on fait mumuse avec.
Au mieux, on garde l'instance dans la classe System et qu'on utilise ensuite dans toute la page. La technique du Singleton dans les 'factory's que je n'ai pas codé ici. Il faudra utiliser la reflection pour faire un truc pareil... Ouh ca me tente :)

Il suffit après de faire des interfaces pour chaque 'factory' afin de pouvoir s'y retrouver facilement (autrement c'est la galère). Bien que PHP5 a quelques lacunes coté objet encore, ca peut se faire.
(exemple de lacune :
class x {
   public function MaMethode( ObjetAttendu $obj );
}
class y extends x {
   public function MaMethode( AutreObjectEtendantObjetAttendu $obj );
   // Impossible, erreur...
}
class z extends x {
   public function MaMethode( UnAutreObjetEtendantObjetAttendu $obj );
   // Impossible, erreur...
}

)

Espérons que tout cela sera réparé dans PHP6 (normalement oui...).

Je suis en train de préparer quelques améliorations au passage. Je vais étendre ma factory de news de base pour implanter des méthodes add(), delete(), update() etc... Donc, je dois aussi étendre mon interface SQL pour rajouter ces méthodes. J'ai bientot fini, je posterais (ainsi que le zip ^^) le tout une fois fini :)

Vala ^^
Si tu veux du design pattern, regarde celui de Zend. Il est assez compliqué au début à la lecture, mais intéressant.
En tout cas, le système que je présente plus haut est le miens ! Je n'ai copié sur personne :)

signaler à un administrateur
Commentaire de coucou747 le 30/03/2007 13:38:41

t'as pas de singleton pour sql ?
#  public function GetSingle($id) {
# if ( !isset(self::$Iterates[__METHOD__]) ) {
# self::$Iterates[__METHOD__] = new AdvancedNews( self::$InterfaceClass->getMethod('GetNews')->invoke(NULL, $id) );
# }
# return self::$Iterates[__METHOD__];
# }

signaler à un administrateur
Commentaire de FhX le 30/03/2007 18:09:39

Pour ma classe SQL si.
Pour ma classe d'interfaçage module/sql non. C'est une classe statique.

signaler à un administrateur
Commentaire de coucou747 le 30/03/2007 18:15:45

"classe statique"=> ce qu'on appelle namespace en cpp :) c'est plus vraiment de l'objet

signaler à un administrateur
Commentaire de FhX le 30/03/2007 19:28:40

Non mais c'est bien pratique :)
Certaines méthodes ne sont pas spécifique à une instance de classe... mais bien à la classe elle-même !

Voila pourquoi je l'utilise ^^
L'objet ne se limite pas à une classe et à son/ses instances(s) ^^ :)

signaler à un administrateur
Commentaire de malalam le 31/03/2007 10:32:23 administrateur CS

Hello,

je passe peu ici en ce moment, ou vraiment en coup de vent, je manque vraiment de temps.
Mais ça, c'est une très jolie classe FhX :-) Fallait que je le dise!
Pour répondre en partie à Guill76 et rassurer FhX, la réflexion est utilisée par les développeurs de PHP dans les classes SPL par exemple. Typiquement du design pattern. Faisons leur confiance :-) La réflexion est un très bel outil, très utile, au même titre que la SPL d'ailleurs. On perd peut-être un peu en performance (et encore, il faudrait tester), mais on gagne en simplicité, en lisibilité, en réutilisabilité, en modularité et en plei dautres trucs en "ité" ;-)
C'est le PHP nouveau ;-)

signaler à un administrateur
Commentaire de FhX le 01/04/2007 18:47:36

Merci Mala :)

Par contre, est ce que tu pourrais m'aider pour la partie XML ?
Genre par exemple, j'ai un fichier XML type :
<allnews>
<news id="1">
  <title>Mon titre</title>
  <content>Contenu de la news</content>
  <date>110110192348</date
</news>
<news id="2">
  //etc...
</news>
</allnews>

et que je puisse récupérer une news, et pourquoi pas faire comme un fetch() pour SQL (si j'appèle la fonction de fetch(), ca me renvoit la news suivante jusqu'à ce que j'en ai plus).
Parce que... XQuery :s j'ai pas encore eu le temps d'expérimenter ca correctement.

Si t'as le temps bien sur, au moins si tu pouvais me donner une piste à suivre, je pourrais ré-utiliser par la suite pour tous les modules :)

Mici :D

signaler à un administrateur
Commentaire de FhX le 03/04/2007 23:07:42

Update, les classes font encore un peu plus d'abstraction (j'ai corrigé quelques bugs avec ma classe d'itération au passage ^^)

signaler à un administrateur
Commentaire de malalam le 05/04/2007 09:09:03 administrateur CS

Ok, je te ferai un petit topo, mais faudra que tu attendes un peu : ma carte mère a grillé :-( et j'ai pas le temps de faire ça au taf.

signaler à un administrateur
Commentaire de FhX le 05/04/2007 16:48:02

ca marche, ca me laisse le temps d'améliorer un peu tout ca (quelques bugs par ci par la...)

signaler à un administrateur
Commentaire de codefalse le 22/05/2007 12:58:51 administrateur CS

FhX, aurait-tu l'amabilite de proposer des liens qui explique comment marche tout ca ??? :)
J'essaye d'apprendre les iterateurs, l'usinage et tout le tintouin, mais a voir ta source j'ai un peu de mal a suivre quand meme !!
Ou est-ce que tu apprends tout ca ? C'est de l'autodidatie ou tu vois ca a ton boulot/cours ? je suis vraiment preneur de tout document pour expliquer clairement le fonctionnement, la relation entre les differentes classes, etc. Je pense avoir compris comment marche l'abstraction, mais pas encore les interfaces, la factory, etc. Ca me ferait grandement plaisir que tu m'indique la voie a suivre. (Je ne te demande pas de faire un tuto, juste des liens, si tu en a)

Merci beaucoup !

(desole pour le manque d'accent, je suis sur un clavier qwerty)

signaler à un administrateur
Commentaire de littlewings le 21/11/2007 10:08:55

Pareil, moi aussi je suis un tes fans FhX et je ne cracherais pas sur des petits tutos là-dessus, de toi ou des des trucs simples que t'as pu lire !

signaler à un administrateur
Commentaire de littlewings le 22/10/2008 10:28:47

Je passe rarement par ici en ce moment, mais je suis fan de tes sources mister FhX, et celle-ci est particulièrement bien foutue. Beau boulot.

signaler à un administrateur
Commentaire de coucou747 le 22/10/2008 10:40:15 10/10

ouais

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Class POO retourné le nom de l'objet [ par MeTh ] Bonjour,Comment retourné le nom de l'objet déclaré?exemple :$monobjet = new GridR();comment recuperé $monobjet dans ma class?Merci templates avec poo [ par lesnes ] bonjours je reprogramme totalement mon site en poo et je souhaiterai utiliser les templates mais l'on ne peut pas faire appel a une class exterieur a Probleme en POO [ par pablor44 ] Bonjour,alors voil&#224; je vous explique mon probleme, je suis en train d'ecrire une classe en php pour mon site et je me retrouve dans la situation Gestion membres via POO [ par FhX ] Je me posais la question justement. Pour pouvoir faire une interface membre (donc : admin + membre + visiteur), dois-je faire ca en une seule classe ? logiciel POO [ par kowal2205 ] Je me pose la question de la cr&#233;ation de mes classes dans un projet de taille moyenne car je ne trouve pas de logiciel &#224; mon pied qui me per Reflexion sur un schema de POO (gestion d'emploi du temps d'une UFR) [ par Franquito ] Bonjour à tous ! Je dois réaliser un schema pour une application de programation orienté objet. L'application fait la gestion d'emploi du temps d'un Comment ca marche cette petite bete? [ par craso ] bonjour,en surfant, je suis tombé sur le site http://www.phpied.com/image-fun/ .Je souhaite qu'on m'explique comment trnsformer une image comme sur le réécriture d'un script en POO, comment faire? [ par craso ] Bonjour,j'ai développé cette petite application http://pipcorp.free.fr/Il s'agit d'une image clicable, le personnage centrale se positionne a l'endroi [POO] Développer son Framework [ par Foxhive ] Bonjour à tous, Cela fait longtemps que l'idée m'interesse mais j'ai jamais vraiment osé me jeter à l'eau. Mais là que je suis en vacance je me dis qu [POO] Avis à tous ! [ par FhX ] L'update de PHP5.2 est assez conséquent, je vous conseil de la lire :pY'a pas mal de trucs qui vont changer, surtout au niveux des interfaces (et tant


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,780 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.