2009-12-03 2 views
1

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

# Basically it's just a Registry pattern  
    class Repository { 
     private static $objects = array(); 

     public function loadObject($alias, $object) { 
      self :: $objects[$alias] = $object; 
      return true; 
     } 

     public function __get($name) { 
      if ($this->objectExists($name)) { 
       return self::$objects[$name]; 
      } else { 
       return false; 
      } 
     } 
    } 

    class Database extends Repository { 
     /* database class */ 
    } 

    class Session extends Repository { 
     public function some_func($key, $value) { 
      /* i can access database object using $this in any class that extends Repository */ 
      $this -> database -> exec (/* sql */); 
     } 
    } 

    /* =================== */ 

    # Load core objects 
    $R = new Repository :: getInstance(); 
    $R -> loadObject ('config', new Config()); 
    $R -> loadObject ('database', new Database()); 
    $R -> loadObject ('session', new Session()); 

    /* =================== */ 

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

+1

любая причина, по которой вы собираетесь с супер-интервалом вокруг '->' и '::'? Я никогда не видел, чтобы кто-то писал такой код раньше. По крайней мере для меня это очень запутанно. – nickf

+0

i believ это потому, что я использую шрифт 8px в моем редакторе: D –

ответ

0

«потому что каждый следующий класс содержит все больше и больше объектов из хранилища» - я не совсем понимаю, что вы подразумевали под этим, я думаю, что, поскольку объекты являются статичными, есть только одна копия.

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

class Repository 
{ 
    private static $instance; 
    private $objects = array(); 
    private static getInstance() 
    { 
    if (!Repository::$instance) 
     !Repository::$instance = new Repository(); 
    return !Repository::$instance(); 
    } 

    public static function loadObject($alias, $object) 
    { 
    Repository::getInstance()->objects[$alias] = $object; 
    return true; 
    } 

    public static function get($name) 
    { 
    $repository = Repository::getInstance(); 
    if (isset($repository->objects[$name] 
     return $repository->objects[$name]; 
    else 
     return false; 
} 

Вы затем использовать это в своих дочерних классах:

Repository::get('config'); 

и в загрузчике

Repository::loadObject('config', new Config()); 
Repository::loadObject('database', new Database()); 

т.д.

5

Не выдвигайте Repository:

  • База данных не хранилища, хранилище имеет базы данных
  • вашу база данных/сеанс/конфигурацию не связаны и не должно быть. Liskov substitution principle:

[...], если S является подтипом T, тогда объекты типа T в программе могут быть заменены на объекты типа S без изменения любого из желательных свойств этой программы (например, правильность).

Редактировать: пытается ответить на последующие вопросы в этом ответе.

Этот метод называется инъекцией зависимостей. Сеанс пример:

class Session { 
    // notice the clean API since no methods are carried along from a possibly huge base class 
    public function __construct(ISessionStorage $storage) { 
     $this->_storage = $storage; 
    } 
    public function set($key, $value) { 
     $this->_storage->set($key, $value); 
    } 
} 

interface ISessionStorage { 
    public function set($key, $value); 
} 

class DatabaseSessionStorage implements ISessionStorage { 
    public function __construct(Db $db) { 
     $this->_db = $db 
    } 
    public function set($key, $value) { 
     $this->_db->query("insert...."); 
    } 
} 

class CookieSessionStorage implements ISessionStorage { 
    public function set($key, $value) { 
     $_SESSION[$key] = $value; 
    } 
} 

// example where it's easy to track down which object went where (no strings used to identify objects) 
$session = new Session(new DatabaseSessionStorage(new Db())); 
$session->set('user', 12512); 
// or, if you'd prefer the factory pattern. Note that this would require some modification to Session 
$session = Session::factory('database'); 
$session->set('user', 12512); 

Конечно, вы можете хранить настройки подключения жёстко прописанные в конфиг-файле. Это означает, что другим файлам необходимо овладеть этим классом конфигурации, не проходя своих родителей. Например:

class Database { 
    // The same pattern could be used as with the sessions to provide multiple database backends (mysql, mssql etc) through this "public" Database class 
    public function __construct(Config $config) { 
     $this->_config = $config; 
     $this->_connect(); 
    } 
    private function _connect() { 
     $this->_config->getDatabaseCredentials(); 
     // do something, for example mysql_connect() and mysql_select_db() 
    } 
} 

Если вы предпочитаете хранить информацию конфигурации из PHP-файлы (для более легкого редактирования/чтения), см Zend_Config -обучения для примеров доступа к различным устройствам хранения данных, включая наиболее распространенные из них: ini, php array, xml. (Я только упоминаю Zend_Config, так как я использовал его и доволен, parse_ini_file тоже будет делать.)

Хороший & надеюсь, легко читать: Fabience Potencier - What is dependency injection?


Edit # 2:

Смотрите также слайд: Matthew Weier O'Phinney - Architecting your models

+1

Что делать, если я использую базу данных для хранения данных сеанса? Или конфигурационный класс для хранения информации о подключении к базе данных? –

+0

Обновлен с некоторыми примерами. – chelmertz

+0

О, я вижу смысл. Для моего конкретного проекта это кажется немного излишним, но спасибо за объяснение принципов и ссылок, я буду помнить об этом. На данный момент я думаю, что пойду с предложенным Томашем методом, так как мне не нужна эта абстракция. –

0

Я думаю, что это плохой пример. Невозможно сохранить объект, такой как конфигурация, база данных и сеанс во внутреннем массиве. Эти объекты должны быть явными (возможно статичными) свойствами в вашем базовом классе и должны быть доступны точным именем. Пурист, вероятно, сказал бы, что доступ к массиву также медленнее, чем прямой доступ к свойствам :-)) Я бы реализовал эти объекты как одиночные и, возможно, спрятал их в чем-то вроде класса Application. Я думаю, что переопределение __get() полезно для объектов с динамическими свойствами или когда вы хотите предотвратить доступ к несуществующим свойствам (просто исключение для исключения). Это также помогает (побочный эффект) против повышения уведомлений PHP (я их ненавижу :-)), когда какое-либо свойство не определено, но уведомления должны быть убиты явно, потому что они (маленькие, но ...) просто ОШИБКИ! Сохранять внутренние свойства массива, относящиеся к конкретным объектам (с десятками свойств). Я использую это решение интенсивно в классах, сопоставленных с записями таблицы db.

С уважением.

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