Çerçeve tasarımı Önerileri

3 Cevap php

Ben şu anda bir proje için mini çerçeve çeşit inşa, ve bu çözüm ile gelip ediyorum. Ben çoğu denedi, ama bu (kod basitlik için kısaltılır) benim için çok rahat görünüyor:

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

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

Can you see any problems or drawbacks with this approach? For me i see maybe i little more memory consumption, because each next class holds more and more objects from Repository. Before i had a design where each class was independent, but anyway all of them require database, session, config etc, no i had to declare them in any class. Just wanted to note that i'm planning this design only for core objects, not for specific classes.

3 Cevap

"Sonraki her sınıf Depodan daha fazla nesne tutar çünkü" - Ben tam olarak neyi kastettiğini anlamıyorum, ben nesneleri sadece bir kopya var, statik olarak düşünüyorum.

Ben singleton deseni birleştirerek, sakıncayı önlemek için biraz farklı bir yaklaşım kullanabilirsiniz düşünüyorum.

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

Daha sonra çocuk sınıflar içinde kullanacağız:

Repository::get('config');

ve bootstrap içinde

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

vb

Uzatmayın Repository:

  • Bir veritabanı is not a depo, bir depo has a veritabanı
  • Sizin veritabanı / oturumu / config ilgili değildir ve olmamalıdır. Liskov substitution principle:

S T bir alt tipi olup olmadığını [...], daha sonra bir program T türü nesneleri o programa (örneğin, doğruluğu) ve istenen özelliklerinden herhangi birini değiştirmeden türü S nesneleri ile değiştirilebilir.

Düzenleme: Bu cevapta takip soruları yanıtlamaya çalışırken.

Bu teknik, bağımlılık enjeksiyon olarak adlandırılır. Bir oturum örneği:

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

Tabii bir yapılandırma dosyası kodlanmış bağlantı ayarlarını saklamak olabilir. Bu sadece diğer dosyaları ebeveynleri geçmeden bu yapılandırma sınıfın ele almak gerekir demektir. Örneğin:

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

Eğer (daha kolay düzenleme / okuma için) php dosyaları üzerinden yapılandırma bilgilerini tutmak için tercih ederseniz, Zend_Config -classes for examples of accessing different storage devices including the more common ones: ini, php array, xml. (I'm only mentioning Zend_Config since I've used it and am satisfied, parse_ini_file de yapardı bkz.)

İyi bir & umarım kolay okunur: Fabience Potencier - What is dependency injection?


# 2 düzenleyin:

Ayrıca slayt bakın: Matthew Weier O'Phinney - Architecting your models

I think it's a bad example. Keeping object such as config, database and session in internal array is unsuitable. These objects should be explicit (probably static) properties in Your base class and should be accessed by exact name. Purist probably would say that accessing array this is also slower than directly accessing properties :-)) I would implement these objects as singletons and maybe hide them in something like Application class. I think overriding __get() is good for objects that have dynamic properties, or when You want to prevent accessing non-existent properties (just throw exception). This also helps (side effect) against rising notices by PHP (I hate them :-)) when any property is undefined, but notices should be killed explicitly because they are (small but...) just BUGS! Keep in internal array properties that belong to specific objects (with tens of properties). I use this solution intensively in classes mapped to db table records.

Saygılar.