2010-08-13 4 views
5

Voulant s'assurer que j'utilise correctement les classes. Le script principal accepte ce de l'utilisateur:Une façon moderne de déclarer une classe en php

1. month 
2. year 
3. the type of event they want to find (microsoft or linux) 

Pour le programme pour trouver un événement Microsoft, il doit exécuter l'expression régulière: « (ID =) + [0-9] + » Pour que le programme trouver un événement linux, il doit exécuter l'expression régulière: '(ID =) + [AF] +'

Créer une classe d'événements semble une façon logique d'organiser le code. Je ne veux pas envoyer l'expression régulière requise dans la classe à partir du script principal si possible. Je souhaite indiquer à la classe d'événements s'il s'agit d'un événement Microsoft ou Linux et laisser la classe retourner les données traitées en fonction de variables prédéfinies dans la classe pour chaque type d'événement.

J'ai le code existant écrit:

class Events 
    { 
      var $month; 
      var $year; 
      var $event_identifier_expression; 

     public function events($month, $year) 
     { 
     $this->month = $month; 
     $this->year = $year; 
     return $this->event_identifier_expression.$month.$year; 
     } 
    } 

Je veux utiliser quelque chose comme plusieurs méthodes statiques dans la classe des événements à la place. Si je change le code existant pour le code ci-dessous, cela me permettra-t-il d'appeler microsoft_events et linux_events indépendamment de l'extérieur de la classe, et est-ce la façon correcte de créer la classe? (Exemple de code pour appeler les fonctions statiques à partir de l'extérieur de la classe est appréciée):

class Events 
    { 
      public function __construct() 
      {var $month; 
      var $year; 
      var $event_identifier_expression; 
      } 

     public static function microsoft_events($month, $year) 
     { 
     $this->month = $month; 
     $this->year = $year; 
     $this->event_identifier_expression = '(ID=)+[0-9]+'; 
     return $this->event_identifier_expression.$month.$year; 
     } 
     public static function linux_events($month, $year) 
     { 
     $this->month = $month; 
     $this->year = $year; 
     $this->event_identifier_expression = '(ID=)+[A-F]+'; 
     return $this->event_identifier_expression.$month.$year; 
     } 
    } 
+0

@stereofrog - Bon p oint. Mon but est de faire une classe qui utilise le même ensemble de variables pour chaque fonction statique. Chaque fonction statique fournira cependant un ensemble différent de valeurs statiques aux variables de classe. Cette approche est-elle une solution raisonnable à mon objectif? J'espère que ce n'est pas trop vague. – JMC

+1

Je peux recommander vivement cet excellent manuel sur les cours, http://www.amazon.co.uk/Objects-Patterns-Practice-Experts-Source/dp/143022925X/ref=wl_it_dp_o?ie=UTF8&coliid=I2NUYS3JDGG7PU&colid=1478EBZ835RZN –

+0

@ acidjazz: Votre description et l'exemple que vous avez donné ne me semblent malheureusement pas très sensés et je pense que c'est la mauvaise approche. Pouvez-vous préciser le cas d'utilisation/d'utilisation de 'class Events'? – VolkerK

Répondre

3

Je suggère une approche différente à ce sujet. Avoir des méthodes différentes pour chaque type pair vous obligera à écrire du code répétitif, ce qui conduira éventuellement à un code maintenable coûteux et sujettes aux erreurs (même le copier/coller est sujet aux erreurs et je l'ai vu dans certains projets pour le prouver). Tout d'abord, les appels statiques doivent être limités uniquement (ou principalement) lorsque les méthodes et ne nécessitent pas de stocker des données dans les membres de classe; une méthode statique ne doit rien définir, moins de données à utiliser par les instances de la classe elle-même. Vous devriez donc utiliser le motif singleton. Deuxièmement, si vous deviez avoir plusieurs types d'événements, chacun devrait avoir sa propre classe spécialisée. La conception orientée objet va de l'abstrait au concret, du général au spécialisé. Par conséquent, votre Events ne devrait pas savoir combien ou quel événement il stocke, mais devrait laisser cela à l'appelant.Cela vous permettra d'avoir une interface plus cohérente.

serait ici un design exemple:

class Events { 

    static private $_instance; 

    static public function getInstance() { 
     // lazy loading of the class instance will not use unnecessary resources 
     if (null === self::$_instance) { 
     self::$_instance = new self(); // <-- valid PHP declaration 
     } 
     return self::$_instance; 
    } 

    // class members 

    protected $_events;  // protected allows inheritance, use private to forbid it 

    // private constructor prohibit external instances to be created 
    private function __construct() { 
     $this->_events = array(); 
    } 

    // (GETTER: methods that starts with 'get'...) 
    // use $year before $month for priority order ($month is more precise than $year) 
    public function getEvents($type, $year = null, $month = null) { 
     $_values = array(); 

     // if we have any event of that type... 
     if (array_key_exists($type, $this->_events)) { 
     foreach ($this->_events[$type] as $event) { 
      // filter events to return... (if $year is null, $month is ignored) 
      if ((null === $year 
       || (($year == $event->getYear()) 
       && (null === $month || $month == $event->getMonth())))) { 

       $_values[] = $event; 
      } 
     } 
     } 

     return $_values; 
    } 

    // (SETTER: methods that starts with 'add', 'set', etc.) 
    public function addEvent(AbstractEvent $event) { 
     if (!array_key_exists($event->getType(), $this->_events)) { 
     $this->_events[$event->getType()] = array(); 
     } 
     $this->_events[$event->getType()][] = $event; 

     // returning $this allows chaining. 
     // While some argue the design of this, I personally like it 
     return $this; 
    } 

} 

Maintenant que nous avons notre conteneur, nous aurons besoin de types d'événements, d'abord, nous avons notre classe de base:

abstract class AbstractEvent { 
    protected $_year; // again, protected to enable inheritance 
    protected $_month; 

    public function __construct($year, $month) { 
     // TODO : perform some argument check here 
     $this->_year = $year; 
     $this->_month = $month; 
    } 

    abstract public function getType(); 
    public function getYear() { return $this->_year; } 
    public function getMonth() { return $this->_month; } 
} 

Ensuite, se spécialisent simplement (nous créons deux types d'événements specialize):

class MicrosoftEvent extends AbstractEvent { 
    const TYPE = 'Microsoft'; 
    public function getType() { return self::TYPE; } 
} 

class LinuxEvent extends AbstractEvent { 
    const TYPE = 'Linux'; 
    public function getType() { return self::TYPE; } 
} 

Ajout de nouveaux événements

Events::getInstance() 
    ->addEvent(new LinuxEvent(2010, 7)) 
    ->addEvent(new MicrosoftEvent(2008, 8)) 
    ->addEvent(new MicrosoftEvent(2010, 2)) 
    ->addEvent(new LinuxEvent(2009, 1)) 
    // ... 
; 

Obtenir des événements

// 1. get ALL Microsoft events 
var_export(Events::getInstance()->getEvents(MicrosoftEvent::TYPE)); 
// 2. get all events for 'Linux' in 2010 
var_export(Events::getInstance()->getEvents('Linux', 2010)); 
// 3. same as 1; $month will be ignored, because $year is not specified 
var_export(Events::getInstance()->getEvents('Microsoft', null, 6)); 
// 4. returns empty array because unknown event type 
var_export(Events::getInstance()->getEvents('Foo')); 

Comme vous pouvez le voir, les frais généraux pour la conception de classe est un peu plus complexe, mais l'API est beaucoup plus cohérente par la suite. Une bonne conception doit appliquer le modèle réutilisable et ceci est accompli ici. J'espère que cela t'aides.

****** EDITER **** puisque votre question a changé, voici une solution éditée. Il est beaucoup plus petit, mais toujours suivre la même conception de base:

class Events { 

    static private $_events = array(); 

    // GETTER 
    static public function getEventType($type) { 
     // if we have any event of that type... 
     if (!array_key_exists($type, self::$_events)) { 
     $eventClass = $type . 'Event'; 
     self::$_events[$type] = new $eventClass(); 
     } 

     return self::$_events[$type]; 
    } 

} 

Ensuite, notre classe type d'événement de base

abstract class AbstractEvent { 
    abstract public function getType(); 
    public function getIdentifier($year, $month) { 
     return $this->getType().str_pad((int) $month, 2, '0', STR_PAD_LEFT).str_pad((int) $year, 4, '0', STR_PAD_LEFT); 
    } 
} 

Maintenant, nous nous spécialisons les types

class MicrosoftEvent extends AbstractEvent { 
    const TYPE = 'Microsoft'; 
    public function getType() { return self::TYPE; } 
} 

class LinuxEvent extends AbstractEvent { 
    const TYPE = 'Linux'; 
    public function getType() { return self::TYPE; } 
} 

Ensuite, nous testons la Résultats

var_export(Events::getEventType(MicrosoftEvent::TYPE)->getIdentifier(2008, 6)); 
var_export(Events::getEventType(LinuxEvent::TYPE)->getIdentifier(2010, 2)); 
var_export(Events::getEventType('Microsoft')->getIdentifier('2009', '08')); 
+0

La deuxième solution après l'édition fonctionne bien. Je n'ai pas encore essayé la première solution. Le niveau de détail du code a aidé à combler les lacunes. Merci – JMC

+0

Eh bien, la première solution était ce que je pensais que vous vouliez avant d'éditer/modifié/détaillé votre question. Cet exemple de code n'est utile que si vous voulez un simple "EventStore", comme stereofrog l'a proposé (sa solution est également bonne).Habituellement, vous utiliserez une base de données pour stocker vos événements et ainsi interroger le Db, et donc modifier les fonctions getEvents() et addEvent() pour interroger votre table d'événements. Dites-moi si vous avez besoin de plus d'informations à ce sujet. –

3

$ this- ne peut pas être utilisé dans une méthode statique - on ne peut pas supposer que la classe sera instanciée ici ...

Vous devrez déclarer votre classe comme ceci:

class Events 
    { 
     public static $month; 
     public static $year; 

     public function __construct(){ } 

     public static function microsoft_events($month, $year) 
     { 
      self::month = $month; 
      self::year = $year; 
     } 

     public static function linux_events($month, $year) 
     { 
      self::month = $month; 
      self::year = $year; 

      //do something? 

      if(self::month == 'March' && self::year == '2010'){ 
       return 'Linux horoscope looks great'; 
      } 
      return self::month . ' ' . self::year . ' is even better!'; 
     } 
} 

Vocation:

$returnedVar = Events::linux_events('March', '2010'); 
4

Si vous souhaitez utiliser tout statiquement (ce qui en fait essentiellement une enjolivée pièce de procédure de code), vous aurez à faire quelque chose comme ceci:

class Events 
{ 
    static protected $month; 
    static protected $year; 

    public static function microsoft_events($month, $year) 
    { 
     self::$month = $month; 
     self::$year = $year; 
    } 
    public static function linux_events($month, $year) 
    { 
     self::$month = $month; 
     self::$year = $year; 
    } 
} 

Events::microsoft_events(12, 2010); 

Notez que vous ne pouvez avoir une seule instance puis, chaque appel va changer les valeurs pour tout.

+0

Mon but est de créer une classe qui utilise les mêmes variables pour chaque fonction statique. Chaque fonction statique fournira cependant un ensemble différent de valeurs statiques aux variables de classe. Cette approche est-elle une solution raisonnable à mon objectif? – JMC

+1

Euh non ça n'a pas de sens en fait ... Vous l'utilisez soit statiquement soit vous utilisez des instances :) Si vous voulez pouvoir utiliser la même classe avec des variables différentes à chaque fois, vous devez utiliser des instances :) – Blizz

3

Du haut de ma tête, je peux suggérer quelque chose comme

/// Raw event data, e.g. database 
class EventStore { 
    function getRawDataMatching($pattern) { 
     // query the db 
    } 
} 

/// Mother of all Event types 
abstract class Event { 
    static function getSearchPattern() { 
     // return the search pattern for the concrete event class 
    } 
    function __construct($rawData) { 
     // initialize from the raw data 
    } 
} 

/// Concrete event classes 
class MicrosoftEvent extends Event {...} 
class LinuxEvent extends Event {...} 

/// Find events in the stream 
class EventFinder 
{ 
    function __construct(EventStore $store) { ... } 

    function classFor($type) { 
     // return event class name for the given type 
    } 

    function find($date, $type) { 
     $klass = $this->classFor($type); 
     $pattern = $klass::getSearchPattern(); 
     foreach($this->store->getRawDataMatching($pattern) as $data) 
      $result[] = new $klass($data) 

    } 
} 

// main code 
$store = new EventStore($connectInfo); 
$finder = new EventFinder($store); 
$foundEvents = $finder->find($input->date, $input->type); 

Ceci est l'une des nombreuses façons possibles, bien sûr. Faites-moi savoir si vous avez besoin de plus de commentaires.

+0

+ 1 - C'est le genre de code que j'essayais de conceptualiser en allant dans le problème. Il y a tellement d'options pour mélanger les classes que cela devient confus rapidement. L'extension d'un événement et l'utilisation d'une classe abstraite sont parfaitement sensées. Merci – JMC

Questions connexes