关于框架设计的建议

Den*_*ovs 1 php frameworks design-patterns

我正在为一个项目构建某种迷你框架,并提出这个解决方案.我尝试了很多,但在我看来这非常方便(代码简化为了简化):

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

    /* =================== */
Run Code Online (Sandbox Code Playgroud)

你能看到这种方法有什么问题或缺点吗?对我来说,我可能会看到更多的内存消耗,因为每个下一个类都拥有来自Repository的越来越多的对象.在我有一个每个类都独立的设计之前,但无论如何所有这些都需要数据库,会话,配置等,所以我不必在任何类中声明它们.只是想注意,我只计划这个设计用于核心对象,而不是特定的类.

che*_*rtz 5

不要延伸Repository:

  • 数据库不是存储库,存储库具有数据库
  • 您的数据库/会话/配置不相关,不应该相关.利斯科夫替代原则:

[...]如果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);
Run Code Online (Sandbox Code Playgroud)

当然,您可以在配置文件中存储硬编码的连接设置.这只意味着其他文件需要获取该配置类而无需通过其父项.例如:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望保留配置信息不受php文件的影响(为了便于编辑/阅读),请参阅Zend_Config-classes以获取访问不同存储设备的示例,包括更常见的存储设备:ini,php array,xml.(我只是提到Zend_Config,因为我已经使用它并且很满意,parse_ini_file也会这样做.)

一个好的,希望很容易阅读:Fabience Potencier - 什么是依赖注入?


编辑#2:

另请参阅幻灯片:Matthew Weier O'Phinney - 构建您的模型