好吧,我不是一个庞大的框架人,但我一直都喜欢我听说过整个MVC运动,所以我想我会尝试用我选择的语言创建一个简单的应用程序(PHP)
所以我想问题是:我哪里出错了?我知道关于控制器/模型应该多么胖的问题存在很多争论,所以希望我们可以避免这种情况,但是我对你如何适应数据的想法特别好奇.
我还买了一个域来做一些测试,所以如果你想看到它的实际运行,你可以去www.omgmvc.com
首先,这是我的数据库模式:
CREATE TABLE `movies` ( `id` int(11) NOT NULL auto_increment, `movie_name` varchar(255) NOT NULL, `release_date` date NOT NULL, `directors_name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ); INSERT INTO `movies` VALUES (1,'Star Wars', '1977-05-25', 'George Lucas'); INSERT INTO `movies` VALUES (2,'The Godfather', '1972-03-24', 'Francis Ford Coppola'); INSERT INTO `movies` VALUES (3,'The Dark Knight', '2008-07-18', 'Christopher Nolan');
这是文件:
index.php (控制器)
id > 0) { include('views/v_movie.php'); } else { echo 'Movie Not Found'; } } else { $movies = Movie::get_all(); include('views/v_list.php'); } ?>
datatier.php (数据层)
connect(); } function __destruct() { $this->disconnect(); } function connect() { $this->database = new PDO('mysql:host=localhost;dbname=dbname','username','password'); } function disconnect() { $this->database = null; } function get_all_from_database($type) { $database = new PDO('mysql:host=localhost;dbname=dbname','username','password'); switch ($type) { case 'movie': $query = 'SELECT id FROM movies'; break; } $movies = array(); foreach ($database->query($query) as $results) { $movies[sizeof($movies)] = new Movie($results['id']); } $database = null; return $movies; } function get_from_database($type,$id) { switch ($type) { case 'movie': $query = 'SELECT movie_name,release_date,directors_name FROM movies WHERE id=?'; break; } $database_call = $this->database->prepare($query); $database_call->execute(array($id)); if ($database_call->rowCount() > 0) { return $database_call->fetch(); } else { return array(); } } } ?>
models/m_movie.php (型号)
id = 0; } else { $this->id = $id; $this->movie_name = $results['movie_name']; $this->release_date = $results['release_date']; $this->directors_name = $results['directors_name']; } } function __destruct() { parent::disconnect(); } static function get_all() { $results = parent::get_all_from_database('movie'); return $results; } } ?>
views/v_list.php (查看)
Movie List
Movie Name | Directors Name | Release Date |
---|---|---|
movie_name; ?> | directors_name; ?> | release_date; ?> |
views/v_movie.php (查看)
movie_name; ?> movie_name; ?>
Directed by directors_name; ?>
Released release_date; ?>
Michał Rudni.. 28
首先,你在保持分离方面做得很好.它会在未来回报,所以不要放弃.
数据库布局(甚至数据库本身)与MVC的本质无关.在大多数情况下,它恰好是关系数据库,但MVC并不明确要求它(您也可以使用XML存储或某些网格/云).对MVC至关重要的是将Model与其他人分开.
您的视图也与其他视图明显分开.与MVC的M部分类似,Views不仅可以呈现HTML,还可以呈现任何可表示文本的输出(XML,XML + XSL,RSS,纯文本甚至电子邮件消息),可以通过多种方式实现视图:PHP包含与您类似的内容,模板(即Smarty)或可序列化为文本的完全成熟的对象.我还没有判断哪种策略是最好的,这是个人编码风格和项目要求的问题.
您的控制器令人困惑(它比应用程序控制器更像页面控制器).可能是因为MVC架构中存在一个隐藏的部分.它被称为Front Controller或Dispatcher.由Dispatcher解析输入,实例化控制器(如在Application Controller中)并调用所请求的方法.如果你想继续使用你的自定义MVC实现,我建议你使用一些在URL中传递Controller类和方法名的常用方法,即
index.php/Movies/list index.php/Movies/details/35
然后在新的index.php中你只需解析$ _SERVER ['PATH_INFO'],实例化类Movies
并调用它的list
方法,即
$args = explode('/', ltrim($_SERVER['PATH_INFO'], '/')); $className = array_shift($args); $method = array_shift($args); require "$className.php"; call_user_func_array(array(new $className(), $method), $args);
然后,您只需将if-else
块的内容移动到Movies类中的两个单独的方法.
class Movies { // may extend generic Controller class if you wish public function list() { $movies = Movie::get_all(); include 'views/v_list.php'; } public function details($movieId) { $movie = new Movie($movieId); if ($movie->id > 0) { include 'views/v_movie.php'; } else { echo "Movie Not Found"; } }
这样,您可以拥有多个控制器,每个控制器都有多个操作.
最后的评论.
在数据库方面,使用现有的ORM框架会很方便.它们将为您节省数天的工作时间,并且可能比手工制作的数据库层更好.我还建议处理PDO实例的实例化,因为在每个Model对象中实例化PDO并不是最干净的方式.DBFactory::getConnection
会有类似的事情.
您可以考虑返回HTML而不是在控制器中回显它.如果您想实现拦截控制器,拦截其输出以及对其进行预处理或后处理的拦截过滤器,这将为您提供灵活性.拥有一个自动附加HTML页眉和页脚的过滤器非常方便.
创建自定义框架是非常有趣和有价值的教育体验,但我建议使用现有框架之一来执行更严肃的任务.
祝一切顺利.
首先,你在保持分离方面做得很好.它会在未来回报,所以不要放弃.
数据库布局(甚至数据库本身)与MVC的本质无关.在大多数情况下,它恰好是关系数据库,但MVC并不明确要求它(您也可以使用XML存储或某些网格/云).对MVC至关重要的是将Model与其他人分开.
您的视图也与其他视图明显分开.与MVC的M部分类似,Views不仅可以呈现HTML,还可以呈现任何可表示文本的输出(XML,XML + XSL,RSS,纯文本甚至电子邮件消息),可以通过多种方式实现视图:PHP包含与您类似的内容,模板(即Smarty)或可序列化为文本的完全成熟的对象.我还没有判断哪种策略是最好的,这是个人编码风格和项目要求的问题.
您的控制器令人困惑(它比应用程序控制器更像页面控制器).可能是因为MVC架构中存在一个隐藏的部分.它被称为Front Controller或Dispatcher.由Dispatcher解析输入,实例化控制器(如在Application Controller中)并调用所请求的方法.如果你想继续使用你的自定义MVC实现,我建议你使用一些在URL中传递Controller类和方法名的常用方法,即
index.php/Movies/list index.php/Movies/details/35
然后在新的index.php中你只需解析$ _SERVER ['PATH_INFO'],实例化类Movies
并调用它的list
方法,即
$args = explode('/', ltrim($_SERVER['PATH_INFO'], '/')); $className = array_shift($args); $method = array_shift($args); require "$className.php"; call_user_func_array(array(new $className(), $method), $args);
然后,您只需将if-else
块的内容移动到Movies类中的两个单独的方法.
class Movies { // may extend generic Controller class if you wish public function list() { $movies = Movie::get_all(); include 'views/v_list.php'; } public function details($movieId) { $movie = new Movie($movieId); if ($movie->id > 0) { include 'views/v_movie.php'; } else { echo "Movie Not Found"; } }
这样,您可以拥有多个控制器,每个控制器都有多个操作.
最后的评论.
在数据库方面,使用现有的ORM框架会很方便.它们将为您节省数天的工作时间,并且可能比手工制作的数据库层更好.我还建议处理PDO实例的实例化,因为在每个Model对象中实例化PDO并不是最干净的方式.DBFactory::getConnection
会有类似的事情.
您可以考虑返回HTML而不是在控制器中回显它.如果您想实现拦截控制器,拦截其输出以及对其进行预处理或后处理的拦截过滤器,这将为您提供灵活性.拥有一个自动附加HTML页眉和页脚的过滤器非常方便.
创建自定义框架是非常有趣和有价值的教育体验,但我建议使用现有框架之一来执行更严肃的任务.
祝一切顺利.
你做得很好,但我有一些建议:
既然你使用php5就不要忘记__autoload函数.
最好将数据层命名为Model.
get_all_from_database未声明为静态但您静态调用它,这会生成E_STRICT级别警告.设置error_reporting(E_ALL | E_STRICT); 你应该看到警告.
get_all()静态函数应该在Model类中(在你的情况下是Datatier),这样你就不必为每个其他模型重写它.您需要在该函数中进行的唯一更改是替换该行:
$ results = parent :: get_all_from_database('movie');
同
$results = $this->get_all_from_database(get_class($this));
这假设模型的名称必须与数据库中表的名称匹配