循序渐进编写 PHP 框架

循序渐进编写 PHP 框架

Chris Yue No Comment
Posts

其实很早就想写这样的文章了,一来是分享这几年自己总结的知识,二来是这也算在做笔记,能看到自己的成长。

本篇文章主要是将一步一步向大家展示如何从 0 开始制作一个 PHP 框架。我认同或自己总结的编程思想也会在文章中被谈到,比如“不要重复发明轮子”,围绕此思想,框架当中的一些功能模块,我将尽可能的使用 PHP 自带的方法或者模块,或者大家熟悉的库文件,这样可以降低学习曲线,也可以让大家熟悉 PHP 内置的或者一些优秀的库文件的用法。

本篇系列并不打算完结,因为有另一篇译文《使用Symfony组件创建自己的PHP框架》我觉得写得比我自己深入和精彩多了

因为是循序渐进,一开始从最一般的写代码的方式编写一个程序。假如有一个需求:列出文章表里的所有文章,那么以下代码便可以实现这个需求:

<?php

// article-list.php

// $dbh为database handler的缩写
// you_db_name以及your_db_host等需要替换成你的数据库名称和主机地址
// $user和$password也需要是对应的数据库帐号和密码
// 本文章主旨在于如何设计框架而非如何使用框架,所以此类非重点问题后面不再赘述,并且将略写非重点部分
$dbh = new PDO('mysql:dbname=your_db_name;host=your_db_host', $user, $password);
$sth = $dbh->prepare('SELECT id, title, created_at FROM article');
$sth->execute();
?>
<table><tbody>
<?php
while ($article = $sth->fetch(PDO::FETCH_ASSOC)) {
  echo "<tr><td>{$article['id']}</td><td>{$article['title']}</td><td>{$article['created_at']}</td></tr>";
}
?>
</tbody></table>

这段代码虽然可以用了,但是从团队合作的目的来说,这段代码很难同时被几个人维护。因为无论是数据获取代码还是页面显示代码都写在了一个文件里,这个文件将不能同时被多个人修改(就算是用 SVN 也很容易冲突),而且还要求维护该文件的人必须同时熟悉数据获取以及数据显示,这显然是违反“术业有专攻”的团队合作精神的。

为了解决分工的问题,只能将此文件分成几个文件,分别交给几个人来维护。考虑到让负责数据获取以及负责页面显示的程序员只负责自己应该负责的部分,我们可以尝试将上面代码作如下分割:

<?php

// article-list.php
// 此文件由负责数据获取的程序员维护
$dbh = new PDO('mysql:dbname=your_db_name;host=your_db_host', $user, $password);
$sth = $dbh->prepare('SELECT id, title, created_at FROM article');
$sth->execute();
$articles = $sth->fetchAll(PDO::FETCH_ASSOC);
include '/path/to/template/article_list.php';

<?php

// /path/to/template/article_list.php
// 此模版文件由负责显示的程序员维护
<table><tbody>
<?php foreach ($articles as $article): ?>
  <tr>
    <td><?php echo $article['id'] ?></td>
    <td><?php echo $article['title'] ?></td>
    <td><?php echo $article['created_at'] ?></td>
  </tr>
<?php endforeach ?>
</tbody></table>

故事到此为止还没有结束,设想除了 article-list.php 需要 articles 数据以外可能还有其他页面也需要。为了实现代码复用,数据获取的代码需要单独从 article-list.php 里面独立出来。代码复用体现了另外一个编程思想 DRY(Don’t repeat yourself),后面对程序的很多改进都会围绕 DRY 来进行,是非常重要的思想之一:

<?php

// /path/to/model/article.php
// 此文件由负责数据获取的程序员维护

function createDbh()
{
  return new PDO('mysql:dbname=your_db_name;host=your_db_host', $user, $password);
}

function getAllArticles()
{
  $sth = createDbh()->prepare('SELECT id, title, created_at FROM article');
  $sth->execute();
  return $sth->fetchAll(PDO::FETCH_ASSOC);
}

此时 article-list.php 的代码将会变得非常简单明了:

// article-list.php
// 此文件由负责“哪些数据通过哪个模版来展现”的程序员维护(此程序员理论上是工作最轻松的:))

require '/path/to/model/article.php';
$articles = getAllArticles();
include '/path/to/template/article_list.php;

到目前为止,上面提到的需求可以被分成三个部分,并被三个与之对应的专业人员进行维护。这三个部分中数据获取部分被称为 M(Model),模版部分被称为 V(View),而连接他们的部分被称之为 C(Controller)。将一个需求分为更细的多个部分,让每个部分都能有专业的人员进行维护是我自己总结的思想之一(相比较于按需求走的纵向分工,横向分工能更好做到专业对口),而 MVC 作为经典的解决分工合作的模式,更是我个人鼓励在需要合作的项目中使用的模式。

关于 MVC 我觉得有必要提出一个常见的错误。我发现国内很多介绍 MVC 的文章或者帖子,都是用各种框架来描述的,让人有一种错觉,使用了框架就是使用了 MVC,反过来就肯定不是 MVC。我面试过一些小程序员,知道 MVC 的定义却说不出它的好处,究其原因是他们都尝试或者用过框架,知道框架的“形”,但都是 MVC 三层层层都参与编码与维护,感觉跟传统式编码没有太大差别,而且因为框架相对复杂却又必须的各种规则,反而觉得 MVC 不但没带来什么好处,反而把事情搞麻烦了。我想会出现这种情况,跟网上很多的文章,以及一些“软件设计师”,“项目经理”的不负责任有关,当然也更国内很多 PHPer 缺乏自我判断与独立思考能力,喜欢人云亦云的浮躁心理有关。我已写过很多关于 MVC 的文章,这里也不再多说,总之简单说来,MVC 不是一个固定的编程套路,它更多是一种分工的思想。如果使用了一个支持 MVC 的框架,却没有按照 MVC 应该有的分工进行开发工作,那么也不能叫使用了 MVC 模式做开发;如果没有使用任何框架甚至就像上面的代码一样都使用 PHP 自带的方法,但只要能做到三层分工,那么也叫使用了 MVC 的开发模式。

在 MVC 三层中,M 层和 V 层是还能做到继续细分的从而更进一步达到分工以及 DRY 编程思想,下一篇文章我将继续介绍 M 层如何再细分。

循序渐进编写 PHP 框架 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

如果觉得文章还不错,就请扫码鼓励一下作者吧
天使打赏人

发表评论

7 + 3 =