PHP如何封装项目框架达到高可用、高性能、高并发
很多初创公司为了快速上线业务,开发时间由本来的6个月压缩到3个月甚至2个月。开发人员只能根据时间及业务需求去git上找现有的项目二次开发或者是一个空框架根据业务一点一点的去做,上述两种方案虽然也可以上线但是对于业务本身存在的问题也是很大的,第一种基于他人项目二次开发需要熟悉框架在上手去修改然后在开发会遇到一些底层问题或者是不兼容的问题,第二种不适用于团队协作开发且重复代码较多复用较低不便于后期维护。
在这里小w建议根据需求及时间自主封装框架(这里仅限初创公司为了快速实现业务一些成型的公司项目都是可以复用的),在这里会有些大佬说哪有时间,这里小w就不得不说相信开完项目会会有时间去思考整体业务。
梳理业务看完需求技术大佬们就该思考以下问题
一、选择框架
分析需求,根据需求大小选择框架php常用框架Laravel、ThinkPHP两种还有hyperf这种基于swool的框架这一类型在现今使用的场景大部分都是公司项目稳定、项目臃肿时间较长的重构使用该类似框架,还有一些yill、phapi、ci等老式框架当前新开项目也不会首选。当前就谈谈laravel、tp当前市场较为普遍的两种业务框架。
再谈而二者优缺点之前,我们应先了解框架的生命周期 请求生命周期 | Laravel中文文档 | ThinkPHP官方手册
Laravel生命周期概述
第一步
Laravel 应用程序的所有请求的入口点都是
public/index.php
文件。所有请求都由你的web
服务器(Apache/Nginx)配置定向到此文件。那个index.php
文件不包含太多代码。相反,它是加载框架其余部分的起点。该
index.php
文件将加载Composer
生成的自动加载器定义,然后从bootstrap/app.php
中检索Laravel
应用程序的实例。Laravel
本身采取的第一个操作是创建应用 / 服务容器 的实例。HTTP / Console 内核
接下来,根据进入应用的请求类型,传入的请求将被发送到
HTTP
内核或者Console
内核。这两个内核充当所有请求流经的中心位置。现在,我们只关注位于app/Http/Kernel.php
中的HTTP
内核。
HTTP
内核继承了Illuminate\Foundation\Http\Kernel
类,该类定义了一个将在执行请求之前运行的bootstrappers
数组。这个数组用来在实际处理请求之前完成:配置异常处理、配置日志、检测应用程序环境,以及其它需要完成的任务。HTTP 内核还定义了一个 HTTP 中间件 列表,所有请求在被应用程序处理之前都必须通过该列表。这些中间件处理读写 HTTP 会话,确定应用程序是否处于维护模式,校验 CSRF 令牌 等等。我们接下来会做详细的讨论。
HTTP 内核的
handle
方法的签名非常简单:它接收Request
接口并返回Response
接口。把内核想象成一个代表整个应用程序的大黑匣子。向它提供 HTTP 请求,它将返回 HTTP 响应。服务提供者
最重要的内核引导操作之一是为应用程序加载 服务提供者 。应用程序的所有服务提供程序都在
config/app.php
文件中的providers
数组。Laravel 将遍历这个提供者列表并实例化它们中的每一个。实例化提供程序后,将在所有提供程序上调用 register 方法。然后,一旦所有的提供者都被注册了,就会对每个提供程序调用
boot
方法。服务提供者可能依赖于在执行boot
方法时注册并可用的每个容器绑定。服务提供者负责引导框架的所有不同组件,如数据库、队列、验证和路由组件。基本上,Laravel 提供的每个主要功能都是由服务提供商引导和配置的。由于它们引导和配置框架提供的许多特性,服务提供者是整个 Laravel 引导过程中最重要的部分。
路由
应用程序中最重要的服务提供者之一是
App\Providers\RouteServiceProvider
。此服务提供者加载应用程序的routes
目录中包含的路由文件。继续,打开RouteServiceProvider
代码,看看它是如何工作的!一旦应用程序被引导并且所有服务提供者都被注册,「请求」将被传递给路由器进行调度。路由器将请求发送到路由或控制器,并运行任何路由特定的中间件。
中间件为过滤或检查进入应用程序的 HTTP 请求提供了一种方便的机制。例如,Laravel 包含一个这样的中间件,用于验证应用程序的用户是否经过身份验证。如果用户未通过身份验证,中间件将用户重定向到登录页。但是,如果用户经过身份验证,中间件将允许请求进一步进入应用程序。一些中间件被分配给应用程序中的所有路由,比如那些在 HTTP 内核的
$middleware
属性中定义的路由,而一些只被分配给特定的路由或路由组。您可以通过阅读完整的 中间件文档 来了解关于中间件的信息。如果请求通过了所有匹配路由分配的中间件,则执行路由或控制器方法,并通过路由的中间件链路返回路由或控制器方法的响应。
最后
一旦路由或控制器方法返回一个响应,该响应将通过路由的中间件返回,从而使应用程序有机会修改或检查传出的响应。 最后,一旦响应通过中间件返回,HTTP 内核的
handle
方法将返回响应对象,并且index.php
文件在返回的响应上调用send
方法。send
方法将响应内容发送到用户的 web 浏览器。至此,我们已经完成了整个 Laravel 请求生命周期的旅程!
ThinkPHP请求流程
对于一个HTTP应用来说,从用户发起请求到响应输出结束,大致的标准请求流程如下:
- 载入
Composer
的自动加载autoload
文件- 实例化系统应用基础类
think\App
- 获取应用目录等相关路径信息
- 加载全局的服务提供
provider.php
文件- 设置容器实例及应用对象实例,确保当前容器对象唯一
- 从容器中获取
HTTP
应用类think\Http
- 执行
HTTP
应用类的run
方法启动一个HTTP
应用- 获取当前请求对象实例(默认为
app\Request
继承think\Request
)保存到容器- 执行
think\App
类的初始化方法initialize
- 加载环境变量文件
.env
和全局初始化文件- 加载全局公共文件、系统助手函数、全局配置文件、全局事件定义和全局服务定义
- 判断应用模式(调试或者部署模式)
- 监听
AppInit
事件- 注册异常处理
- 服务注册
- 启动注册的服务
- 加载全局中间件定义
- 监听
HttpRun
事件- 执行全局中间件
- 执行路由调度(
Route
类dispatch
方法)- 如果开启路由则检查路由缓存
- 加载路由定义
- 监听
RouteLoaded
事件- 如果开启注解路由则检测注解路由
- 路由检测(中间流程很复杂 略)
- 路由调度对象
think\route\Dispatch
初始化- 设置当前请求的控制器和操作名
- 注册路由中间件
- 绑定数据模型
- 设置路由额外参数
- 执行数据自动验证
- 执行路由调度子类的
exec
方法返回响应think\Response
对象- 获取当前请求的控制器对象实例
- 利用反射机制注册控制器中间件
- 执行控制器方法以及前后置中间件
- 执行当前响应对象的
send
方法输出- 执行HTTP应用对象的
end
方法善后- 监听
HttpEnd
事件- 执行中间件的
end
回调- 写入当前请求的日志信息
至此,当前请求流程结束。
其次应了解框架目录
熟悉框架目录是封装框架的重中之重,两者目录就不再这里给各位大佬详细讲解了二者目录结构相似也有一些不同点。各位大佬请移步官方文档仔细阅读。
目录结构 | Laravel中文文档 | ThinkPHP官方手册
1、laravel、tp的优缺点
Laravel的优缺点
优点:
- 优雅的语法:Laravel的语法设计简洁、直观且易于理解,使得代码更加整洁和可维护。
- 丰富的功能:Laravel提供了许多内置功能,如身份验证、授权、路由、缓存、队列、事件/监听器等,这些功能都经过精心设计和实现,可以满足大多数Web开发需求。
- 优秀的文档和社区支持:Laravel拥有详细的官方文档和活跃的社区,这使得开发者能够快速找到解决方案和资源,同时也能够与其他开发者交流和学习。
- 强大的ORM:Laravel的Eloquent ORM提供了一种优雅且高效的方式来操作数据库,支持多种数据库类型,并提供了丰富的查询构建器功能。
- 安全性:Laravel内置了多种安全机制,如CSRF保护、密码哈希、加密等,可以有效地保护应用程序的安全性。
- 灵活的路由系统:Laravel的路由系统非常灵活,支持RESTful风格的路由、命名空间路由等,可以满足不同应用程序的需求。
- Artisan命令行工具:Laravel自带了一个强大的命令行工具Artisan,可以帮助开发者执行各种任务,如生成控制器、模型、迁移文件等,提高了开发效率。
缺点:
- 学习曲线:对于初学者来说,Laravel的学习曲线可能相对较陡,需要花费一定的时间和精力来掌握其各种功能和概念。
- 性能问题:虽然Laravel在大多数情况下性能表现良好,但在某些特定场景下,由于其复杂的功能和依赖关系,可能会导致性能下降。
- 内存占用:Laravel应用程序在运行时可能会占用较多的内存,特别是在处理大量数据或复杂请求时。这可能会对服务器资源造成一定压力。
- 依赖管理:Laravel使用Composer进行依赖管理,虽然这带来了便利,但也可能导致依赖冲突或版本不兼容的问题。
- 调试难度:Laravel的代码结构和抽象层次较高,这在一定程度上增加了调试的难度。当遇到问题时,可能需要花费更多的时间和精力来定位和解决问题。
TP(ThinkPHP)的优缺点
优点:
- 中文文档丰富:ThinkPHP提供了详细的中文文档,使得国内开发者更容易上手和学习。
- 社区活跃:ThinkPHP拥有活跃的社区,开发者可以在其中交流经验、分享资源,并快速找到解决方案。
- 易于学习和上手:相对于Laravel等框架,ThinkPHP的语法和概念更加简单易懂,适合初学者快速上手。
- 在国内应用广泛:由于ThinkPHP的易用性和丰富的功能,它在国内得到了广泛的应用和认可。
缺点:
- 性能表现:在某些复杂场景下,ThinkPHP的性能可能不是最优的。这可能与框架的设计和实现方式有关。
- 安全性问题:虽然ThinkPHP提供了基本的安全机制,但开发者仍需注意安全问题,如防止SQL注入、XSS攻击等。此外,一些旧版本的ThinkPHP可能存在已知的安全漏洞,需要及时更新和修复。
- 扩展性和灵活性:相对于Laravel等框架,ThinkPHP在扩展性和灵活性方面可能稍逊一筹。这可能会限制开发者在某些特定场景下的开发需求。
综上所述,Laravel和TP(ThinkPHP)都是优秀的PHP开发框架,它们各自具有独特的优缺点。在选择框架时,开发者应根据具体项目需求、团队技能和个人喜好来评估哪个框架更适合自己的项目。
2、根据项目二者之间应如何快速选择
一、项目规模与复杂度
Laravel:
- 大型项目:Laravel更适合大型项目。它提供了丰富的内置功能和模块化设计,能够更好地支持复杂的应用架构。
- 高扩展性:Laravel拥有完善的生态系统,包括大量的第三方包和插件,可以方便地扩展应用程序的功能。
ThinkPHP:
- 中小型项目:ThinkPHP更适合中小型项目。其配置和使用相对简单,可以快速搭建和部署应用。
- 轻量级:ThinkPHP的架构相对轻量级,适合对性能有较高要求的场景。
二、文档与社区支持
Laravel:
- 文档丰富:Laravel的官方文档非常详细,覆盖了几乎所有常用功能,并且有大量的教程和视频资源。
- 社区活跃:Laravel拥有活跃的社区,开发者可以在其中交流经验、分享资源,并快速找到解决方案。
ThinkPHP:
- 中文文档:ThinkPHP提供了详细的中文文档,适合国内开发者学习和使用。
- 社区支持:虽然ThinkPHP的社区不如Laravel活跃,但仍然有一定的用户群体和开发者支持。
三、性能表现
Laravel:
- 性能优化:Laravel在性能上可能稍逊于ThinkPHP,但通过一些优化手段(如缓存、数据库索引等)可以显著提升性能。
- 资源占用:Laravel应用程序在运行时可能会占用较多的内存和CPU资源,特别是在处理大量数据或复杂请求时。
ThinkPHP:
- 高效性能:ThinkPHP在性能上表现较好,尤其是在中小型项目中。其轻量级的架构使得资源占用相对较少。
- 响应速度:ThinkPHP的响应速度通常较快,适合对实时性要求较高的应用场景。
四、安全性与稳定性
Laravel:
- 内置安全机制:Laravel内置了多种安全机制,如CSRF保护、密码哈希、加密等,可以有效地保护应用程序的安全性。
- 稳定性:Laravel经过长时间的迭代和更新,已经变得非常稳定可靠。
ThinkPHP:
- 安全更新:ThinkPHP一直在不断更新以修复已知的安全漏洞。然而,开发者仍需注意安全问题,并及时应用安全更新。
- 稳定性:虽然ThinkPHP在某些版本中存在稳定性问题,但整体而言,它仍然是一个可靠的PHP开发框架。
五、开发者生态与工具支持
Laravel:
- 生态系统完善:Laravel拥有更丰富的第三方包和插件,生态更加完善。这使得开发者可以更方便地扩展应用程序的功能。
- 工具支持:Laravel提供了许多内置的工具和命令行界面(如Artisan),提高了开发效率。
ThinkPHP:
- 第三方扩展:虽然ThinkPHP也有许多第三方扩展,但相对于Laravel而言,数量和质量略逊一筹。
- 工具支持:ThinkPHP也提供了一些内置的工具和命令行界面,但相对于Laravel而言,功能可能不够全面。
综上所述,从项目选择的角度来看,Laravel和ThinkPHP各有优缺点。开发者在选择框架时,应根据具体项目需求、团队技能和个人喜好来评估哪个框架更适合自己的项目。对于大型项目或需要丰富生态系统支持的场景,Laravel可能是一个更好的选择;而对于中小型项目或对性能有较高要求的场景,ThinkPHP可能更加合适。
二、如何封装
封装框架就要理解框架、合理利用设计模式这里我就用Laravel进行举例如果有哪些问题各位大佬可以在评论区积极的讨论。
将框架封装三层、或四层,将业务逻辑与数据库操作分开 这样便于后期维护也便于方法复用。
控制器按业务模块分开
每个业务一个基类,在基类中通过单例模式进行初始化调用该模块所需要的服务类、公共类后在业务逻辑层可以直接调用,简化了在业务代码中不断实例化的过程也加快了代码的执行速度。并且该操作在开发与后续维护中简化了开发时间成本也便捷了开发人员可以复用代码不用过于臃肿,代码简洁化
合理利用设计模式 比如 一些特定的项目需要接入大量的三方支付就可以采用工厂模式
1、先定义一个 abstract 抽象类定义需要用到的抽象方法、公共的参数(工厂)
2、在定义一个类去继承工厂 也继承了工厂中的所有方法和参数 也可以在该类中定义自己的(车间)
3、 具体实现类 继承车间 从而书写自己的业务逻辑(产品)
在项目中可以使用产品每个产品达到的效果都是不一样的
通过单例模式也可以封装 redis、mongo等项目中需要用到的缓存
上述所讲的封装较为普遍适用于大多数中小项目,还是那句话具体问题具体分析,根据自己的业务逻辑封装项目最适用框架,可以便捷团队开发和后期维护。
三、总结
根据业务分层简化代码提高代码执行效率、合理利用设计模式封装公共服务 。封装框架不能只考虑眼前业务需要考虑到后期迭代、维护等因素。
还是那句话具体问题具体分析,希望各个大大佬一起交流。
(备注:根据上述封装后业务开发完测试可以达到2000qps/s,还是没有做集群的情况下)