PHP 单一入口模式

单一入口

单一入口的概念其实很好理解,我们可以把整个应用想象为一个黑色的盒子,整个盒子只有一个入口,这个入口由一个文件把守,它要求所有的请求必须通过这个入口文件检验才能进入。

在聊单一入口的应用之前,我们先来看一看传统应用的多入口模式,这里我们参考一下 ECSHOP 的网站根目录的部分目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- article.php 文章内容
- article_cat.php 文章分类
- auction.php 拍卖前台文件
- brand.php 品牌列表
- captcha.php 生成验证码
- catalog.php 列出所以分类及品牌
- category.php 商品分类
- comment.php 提交用户评论
- compare.php 商品比较程序
- cycle_image.php 轮播图片程序
- feed.php RSS Feed 生成程序
- flow.php 购物流程
- gallery.php 商品相册
- goods.php 商品详情
- goods_script.php 生成商品列表
- group_buy.php 团购商品前台文件
- index.php 首页文件
- myship.php 支付配送DEMO
- pick_out.php 选购中心
- receive.php 处理收回确认的页面
- index.php 首页文件

你可以看到上述目录就是网站的根目录,这个目录下存放着相应页面的响应代码,如果我们想要访问首页,我们就在网址中访问 index.php,如果我们想要访问商品页,那么我们就需要访问 goods.php 文件,这就是传统应用的多入口模式,我们可以通过不同的文件入口来得到应用响应。

谈到这里,你应该意识到了 网站的根目录应用的根目录 是两个不同的定义。
我们看下 Laravel 应用的根目录下包含了多个目录,其目录结构如下:

1
2
3
4
5
6
7
8
9
10
- app
- bootstrap
- config
- database
- public
- index.php
- resources
- storage
- tests
- vendor

这其中 public 目录才是网站的根目录,index.php 就是整个应用的守卫,它需要视察所有进入应用的请求。

单一入口的优势

聊到这里,你一定会有所疑惑,Laravel 为何要采用单一入口的模式,这种单一入口有什么优势?

如果说这种单一入口目录结构的优势,那么我们不得不提及应用核心代码与静态资源的分离,使用这种方式,我们可以非常完美的将服务端核心代码与静态资源完全分离开来,这就意味着如果你想要访问 public 目录外的资源都必须要经过守卫的审查。这就为统一的安全性提供了便利。

我曾经见到过这么一个有趣的情况,某人在 ECSHOP 程序的配置文件目录下拷贝了一份配置并重命名为 config.php.bak,原意可能是为了防止自己忘记数据库的密码,但是这就意味着任何用户都可以通过浏览器访问到这个文件了,因为对于 Nginx 或者 Apache 来说这些 HTTP 请求只要路径正确,如果不是 PHP 程序的话,他们就会以静态资源的方式进行输出,当然,这只是个个例,但却足以让你明白动静分离的好处了。

那么我们现在穿透到黑盒的内部看一下,如果说黑盒是一个工厂,守卫把一个请求交由工厂来处理,那么它一定需要通过一定的流程来产出一个响应。那么它的流程一般是这样的:

  • 初始化应用所需的模块资源
  • 根据不同的请求类型将其导向相应的业务
  • 业务处理
  • 返回响应

那么我们应该可以看出,其实单一入口最大的优势就是规范了开发流程。

我们可能很难想象规范化的流程能带来多大的开发效率上的提升,但是它确实能最大化的提升效率。

基于传统的多入口应用中,如果我们想要保存一个用户的认证状态,那么我们一定会使用服务端的 session 功能。所以你会在这些应用的每个牵涉到用户相关的入口页面的 PHP 文件中发现被引入了相关的 session 实现。这样,每次我们增加一个页面就要手动的引入一次,这完全背离的 DRY(Don’t Repeat Yourself) 原则。

而在单入口应用中,如果抽象度非常高的话,那么我们完全可以把 session 实现抽象为其中的一个中间件,这样,我们也完全可以在请求被守卫进行分发时由程序自动的判断是否需要启用 session 功能,这完全可以是自动化的。

再比如说,如果我们想对应用的请求启用日志功能,那么基于传统的多入口应用,我们需要在每一个入口中都加入日志功能,才能达到记录所有日志的效果,而在单入口应用中我们只需要添加一个日志中间件就可以让它来记录所有的日志了。

对于多入口的应用每当我增加一个入口页面时,我一定不能忘记引入基层的组件库。