2010-08-13 6 views
5

Желая убедиться, что я правильно использую классы. Основной сценарий принимает это от пользователя:Современный способ объявить класс в php

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

Для программы, чтобы найти майкрософт события он должен запустить регулярное выражение: «(ID =) + [0-9] +» для программы найти событие linux, он должен запустить регулярное выражение: '(ID =) + [AF] +'

Создание класса Events представляется логичным способом организации кода. Я не хочу отправлять требуемое регулярное выражение в класс из основного сценария, если это возможно. Я хочу рассказать класс событий, если это событие microsoft или linux, и пусть класс возвращает обработанные данные на основе переменных, которые предварительно определены в классе для каждого типа события.

У меня есть существующий код, написанный как:

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; 
     } 
    } 

Я хочу использовать что-то вроде нескольких статических вспомогательных методов в классе событий вместо. Если я изменю существующий код на код ниже, разрешит ли я вызвать microsoft_events и linux_events независимо вне класса, и является ли это правильным способом создания класса? (Пример кода для вызова статических функций из вне класса ценится):

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 - Good p oint. Моя цель - создать класс, который использует один и тот же набор переменных для каждой статической функции. Однако каждая статическая функция предоставляет переменные класса разные статические значения. Является ли этот подход разумным решением моей цели? Надеюсь, что это не слишком расплывчато. – JMC

+1

Я могу строго рекомендовать этот отличный учебник по классам, 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: Ваше описание вместе с примером, который вы предоставили, к сожалению, имеет мало смысла для меня, и я подозреваю, что это неправильный подход. Не могли бы вы подробнее рассказать об использовании/использовании «событий класса»? – VolkerK

ответ

3

Я бы предложил другой подход к этому. При использовании разных методов для каждого четного типа вам потребуется написать повторяющийся код, что в конечном итоге приведет к дорогостоящему поддерживаемому коду и подверженности ошибкам (даже копирование/вставка подвержена ошибкам!), И я видел это в некоторых проектах, чтобы доказать это).

Во-первых, статические вызовы должны быть ограничены (или главным образом), когда методы не требуют хранения данных в классах; статический метод не должен устанавливать ничего, меньше данных, которые будут использоваться экземплярами самого класса. Поэтому вы должны использовать шаблон singleton.

Во-вторых, если у вас должно быть много типов событий, каждый из них должен иметь свой соответствующий специализированный класс. Объектно-ориентированный дизайн идет от абстрактного к конкретному, общего к специализированному. Поэтому ваш Events не должен знать, сколько или какого события он хранит, но должен оставить это вызывающему.Это позволит вам иметь более согласованный интерфейс.

Вот бы пример дизайна:

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; 
    } 

} 

Теперь у нас есть наш контейнер, мы будем нуждаться типы событий, первый у нас есть базовый класс:

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; } 
} 

Тогда просто специализировать его (мы создаем два вида специализируются событий):

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; } 
} 

Добавление новых событий

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

Получить события

// 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')); 

Как вы можете видеть, накладные расходы на дизайн класса является немного более сложным, но API является гораздо более последовательным после этого. Хорошая конструкция должна применять шаблон повторного использования, и это выполняется здесь. Надеюсь это поможет.

****** EDIT ****, так как ваш вопрос изменился, вот отредактированное решение. Это гораздо меньше, но все-таки следовать той же базовой конструкции:

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]; 
    } 

} 

Тогда наш базовый тип события класса

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); 
    } 
} 

Теперь мы специализироваться типы

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; } 
} 

Затем мы тестируем Результаты

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

Второе решение после редактирования работает хорошо. Еще не пробовал первое решение. Уровень детализации кода помог заполнить пробелы. Спасибо – JMC

+0

Ну, первое решение было тем, что, как я думал, вам нужно, прежде чем отредактировать/изменить/детализировать свой вопрос. Этот примерный код полезен, если вам нужен простой «EventStore», как предложено стереофог (его решение также хорошо кстати).Обычно вы будете использовать базу данных для хранения ваших событий и, таким образом, запрашивать Db и, следовательно, модифицировать функции getEvents() и addEvent() для запроса вашей таблицы событий. Скажите, если вам нужна дополнительная информация. –

3

$ это не может быть использован в качестве статического метода - один не может предположить, что класс будет экземпляр здесь ...

Вы должны объявить свой класс, как это:

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!'; 
     } 
} 

Calling:

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

Если вы хотите использовать все статический (что делает его по существу prettied до процедурной части кода), вы должны сделать что-то вроде этого:

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); 

Заметьте, что вы можете иметь только один экземпляр, то, каждый звонок изменяет значения для всего.

+0

Моя цель - создать класс, который использует одни и те же переменные для каждой статической функции. Однако каждая статическая функция предоставляет переменные класса разные статические значения. Является ли этот подход разумным решением моей цели? – JMC

+1

Euh no это не имеет смысла на самом деле ... Вы либо используете его статически, либо используете экземпляры :) Если вы хотите каждый раз использовать один и тот же класс с разными переменными, вы должны использовать экземпляры :) – Blizz

3

Off верхней части моей головы, я могу предложить что-то вроде

/// 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); 

Это один из многих возможных способов, конечно. Дайте мне знать, если вам нужны дополнительные комментарии.

+0

+ 1 - Это тот тип кода, который я пытался осмыслить, перейдя в проблему. Есть так много вариантов для смешивания классов, которые он запутывает быстро. Расширение события и использование абстрактного класса имеет смысл. Спасибо – JMC

Смежные вопросы