为什么大多数PHP致命框架1完整版都没有实现类似Laravel中队列的功能

现在很多互联网应用都是php开发的,在很多人的观念里已经把php与java分到了两个开发领域,php是互联网,java是企业应用。 都说php的开发效率高,更适合互联网快速发布的特点,但我一直 没感觉到php的开发效率比java到底高在哪,请说的具体一点,细节一点。

PHP和MySQL是绝配,一开始就作为PHP开发的亮点而存在。PHP操作MySQL的方便性其他语言比不了。

PHP跟Apache等服务器亦是绝配,一等支持。代码文件往服务器上一丢,爱咋整咋整。

PHP的Array堪称一绝,数组、关联数组一网打尽,而且提取、存入等各种功能,甚至你想不到的一些方便功能,PHP都给你了。

PHP为Web而生,Web开发需要的什么协议相关、请求响应、加密处理、各种流,都内置了,琳琅满目受用一生。

社区资源丰富,资料唾手可得。

动态语言、弱类型的灵活度,加上PHP后来增强的类型提示,让你随心所欲。

以上还没提到Laravel,如果你用上Laravel、Yii啥的框架,估计会乐不思蜀

最后让PHP黑继续顽固下去吧,这么好的语言/工具是给我等享用的。其实PHP的主要矛盾不是PHP黑嘴里说的那么不堪,而是入点流的PHP开发者供不应求。

PHP适合非核心系统,玩票小系统,如果要要应用到大系统就要做很多改造,所以小玩家比较多。

JAVA适合小系统,中型系统和大系统,结构整齐,缺点是代码看起来死板,看起来复杂。

php程序员往往都有半吊子的前端技能,所以理论上来说是全栈工程师的支柱,也代表着老板可以用一个人做两个人的活。

所以你随便糊一个什么东西基本上满足需求,写再乱的代码只要能运行起来就有好。
但是反过来如果想要他变得干净就要费劲了:一大堆的convention,各种黑科技,没错虽然psr标准化了但是autoload这东西真的就是在糊啊。

很多人会喷C++程序员都习惯随手造轮子,PHP可是把随手Hack的轮子都直接当成了标准来处理了的。

这么脏确实方便,就像一些答案里说的,随手就能登上机器改代码等等。可是,这样搞对Ops和质量保证很不友好啊。比如你在生产机器上fix了一个bug,在什么情况下把它合并到主分支呢?难道还要在生产机器上配置一套vcs客户端?

再者,业务复杂和高吞吐量的情况下,PHP这些特色都没了:要么没有一个强有力的类型系统做保障结果自身写成了一坨屎,要么滥用动态特性造成代码极度不可读。所以很有可能的原因是,团队的核心成员离职以后这个项目基本就废了,不得不再挖新坑。更神奇的是PHP中这种能够诡异地实现各种需求的特性还真是非常的多,更加剧了这一问题。

第三点就是,PHP是很multi-paradigm的,而且因为一些设计的缺陷导致项目里面不得不交叉混用各种不同的paradigm。加之语言版本的混乱,配置的复杂(当然现在你可以php -S了),以及各种安全性和一些隐晦的缺陷,这些都是影响项目稳定性的致命伤害:因为这些原因可能会有一大部分人不得不在不同机器/操作系统上保留不同的配置,或者是固守某个特定的版本,或者坚持使用自己hack出来的工具。

当然其实上面那些缺陷,除了作为动态语言必有的之外,Java里也多少都存在(特别是对于初学者,或者至今还在使用一些老旧技术栈的人)。但关键是,首先Java自身设计上还是有一定的紧凑和保守(所谓的歧视程序员智商),对于团队协作来说非常的重要,毕竟不是每个人都是大牛。其次Java有非常完善的标准和工具集,自动化程度非常的高,这就避免了需要程序员“ssh到服务器”这种尴尬的操作。另外作为一个工业级的编程语言,Java(及一部分开发框架)在可靠性方面是少有能及的,这一点你PHP再洗也没用。

所以对比一下其实就出来了,PHP脏又快,所以,个人或者小团队快速实现一些原型产品的时候可能会非常的方便,但是随着业务逻辑变复杂,这个优势会逐渐消失。反观Java虽然自由度不高,设计的看起来有些蠢,但是有工业级框架和工具的支撑前期开发上不比PHP差劲,而且能够保证后续的可维护性:至少每个人都能看懂代码。

关于程序员,我觉得完全不能按照使用的编程语言来划分,更不应该随便用80%这个数字来随便代表别人。

就像,ssh到Linux这种本身作为基本的ops知识是一个合格的开发人员的必备,而且,自动化工具的存在带给开发人员的好处就是,不用再处理这些脏东西了,把更多的时间留给更好的实现逻辑和提升质量:在源头控制好了问题,就更不会存在ssh到生产环境修bug这种操作了。

从0开始构建一个属于你自己的PHP框架

如何构建一个自己的PHP框架

为什么我们要去构建一个自己的PHP框架?可能绝大多数的人都会说“市面上已经那么多的框架了,还造什么轮子?”。我的观点“造轮子不是目的,造轮子的过程中汲取到知识才是目的”。

那怎样才能构建一个自己的PHP框架呢?大致流程如下:

除此之外我们还需要单元测试、nosql支持、接口文档支持、一些辅助脚本等。最终我的框架目录如下:

定义一个统一的入口文件,对外提供统一的访问文件。对外隐藏了内部的复杂性,类似企业服务总线的思想。

使用spl_autoload_register函数注册自加载函数到__autoload队列中,配合使用命名空间,当使用一个类的时候可以自动载入(require)类文件。注册完成自加载逻辑后,我们就可以使用use和配合命名空间申明对某个类文件的依赖。

E_STRICT。所以我们需要使用register_shutdown_function配合error_get_last获取脚本终止执行的最后错误,目的是对于不同错误级别和致命错误进行自定义处理,例如返回友好的提示的错误信息。

通过函数set_exception_handler注册未捕获异常处理方法,目的捕获未捕获的异常,例如返回友好的提示和异常信息。

加载框架自定义和用户自定义的配置文件。

  • 定义请求对象:包含所有的请求信息
  • 定义响应对象:申明响应相关信息

框架中所有的异常输出和控制器输出都是json格式,因为我认为在前后端完全分离的今天,这是很友善的,目前我们不需要再去考虑别的东西。

通过用户访问的url信息,通过路由规则执行目标控制器类的的成员方法。我在这里把路由大致分成了四类:

我在这里详细说下这里所谓的微单体路由,面向SOA和微服务架构大行其道的今天,有很多的团队都在向服务化迈进,但是服务化过程中很多问题的复杂度都是指数级的增长,例如分布式的事务,服务部署,跨服务问题追踪等等。这导致对于小的团队从单体架构走向服务架构难免困难重重,所以有人提出来了微单体架构,按照我的理解就是在一个单体架构的SOA过程,我们把微服务中的的各个服务还是以模块的方式放在同一个单体中,比如:

如上,我们简单的在一个单体里构建了各个服务模块,但是这些模块怎么通信呢?如下:

通过上面的方式我们就可以松耦合的方式进行单体下各个模块的通信和依赖了。与此同时,业务的发展是难以预估的,未来当我们向SOA的架构迁移时,很简单,我们只需要把以往的模块独立成各个项目,然后把App实例get方法的实现转变为RPC或者REST的策略即可,我们可以通过配置文件去调整对应的策略或者把自己的,第三方的实现注册进去即可。

传统的MVC模式提倡为MCL模式

传统的MVC模式包含model-view-controller层,绝大多时候我们会把业务逻辑写到controller层或model层,但是慢慢的我们会发现代码难以阅读、维护、扩展,所以我在这里强制增加了一个logics层。至于,逻辑层里怎么写代码怎么,完全由你自己定义,你可以在里面实现一个工具类,你也可以在里面再新建子文件夹并在里面构建你的业务逻辑代码,你甚至可以实现一个基于责任连模式的网关(我会提供具体的示例)。这样看来,我们的最终结构是这样的:

  • M: models, 职责只涉及数据模型相关操作
  • L: logics, 职责灵活实现所有业务逻辑的地方

我们在logics层目录下增加了一个gateway目录,然后我们就可以灵活的在这个目录下编写逻辑了。gateway的结构如下:

网关入口类主要负责网关的初始化,代码如下:

实现完成这个gateway之后,我们如何在框架中去使用呢?在logic层目录中我提供了一个user-defined的实体类,我们把gateway的入口类注册到UserDefinedCase这个类中,示例如下:

这样这个gateway就可以工作了。接着说说这个UserDefinedCase类,UserDefinedCase会在框架加载到路由机制之前被执行,这样我们就可以灵活的实现一些自定义的处理了。这个gateway只是个演示,你完全可以天马行空的组织你的逻辑~

视图View去哪了?由于选择了完全的前后端分离和SPA(单页应用), 所以传统的视图层也因此去掉了,详细的介绍看下面。

完全的前后端分离,数据双向绑定,模块化等等的大势所趋。这里我把我自己开源的vue前端项目结构 easy-vue 移植到了这个项目里,作为视图层。我们把前端的源码文件都放在frontend目录里,详细如下,你也可以自己定义:

build成功之后会生成dist目录和入口文件index.html在public目录中。非发布分支.gitignore文件会忽略这些文件,发布分支去除忽略即可。

数据库对象关系映射ORM(Object Relation Map)是什么?按照我目前的理解:顾名思义是建立对象和抽象事物的关联关系,在数据库建模中model实体类其实就是具体的表,对表的操作其实就是对model实例的操作。可能绝大多数的人都要问“为什么要这样做,直接sql语句操作不好吗?搞得这么麻烦!”,我的答案:直接sql语句当然可以,一切都是灵活的,但是从一个项目的 可复用,可维护, 可扩展 出发,采用ORM思想处理数据操作是理所当然的,想想如果若干一段时间你看见代码里大段的难以阅读且无从复用的sql语句,你是什么样的心情。

Record,laravel系列框架的Eloquent(据说是最优雅的),那我们这里言简意赅就叫ORM了。接着为ORM建模,首先是ORM客户端实体DB:通过配置文件初始化不同的db策略,并封装了操作数据库的所有行为,最终我们通过DB实体就可以直接操作数据库了,这里的db策略目前我只实现了mysql(负责建立连接和db的底层操作)。接着我们把DB实体的sql解析功能独立成一个可复用的sql解析器的trait,具体作用:把对象的链式操作解析成具体的sql语句。最后,建立我们的模型基类model,model直接继承DB即可。最后的结构如下:

服务容器听起来很浮,按我的理解简单来说就是提供一个第三方的实体,我们把业务逻辑需要使用的类或实例注入到这个第三方实体类中,当需要获取类的实例时我们直接通过这个第三方实体类获取。

用设计模式来讲:其实不管设计模式还是实际编程的经验中,我们都是强调“高内聚,松耦合”,我们做到高内聚的结果就是每个实体的作用都是极度专一,所以就产生了各个作用不同的实体类。在组织一个逻辑功能时,这些细化的实体之间就会不同程度的产生依赖关系,对于这些依赖我们通常的做法如下:

这样的写法没有什么逻辑上的问题,但是不符合设计模式的“最少知道原则”,因为之间产生了直接依赖,整个代码结构不够灵活是紧耦合的。所以我们就提供了一个第三方的实体,把直接依赖转变为依赖于第三方,我们获取依赖的实例直接通过第三方去完成以达到松耦合的目的,这里这个第三方充当的角色就类似系统架构中的“中间件”,都是协调依赖关系和去耦合的角色。最后,这里的第三方就是所谓的服务容器。

在实现了一个服务容器之后,我把Request,Config等实例都以单例的方式注入到了服务容器中,当我们需要使用的时候从容器中获取即可,十分方便。使用如下:

提供对nosql的支持,提供全局单例对象,借助我们的服务容器我们在框架启动的时候,通过配置文件的配置把需要的nosql实例注入到服务容器中。目前我们支持redis/memcahed/mongodb。

接口文档生成和接口模拟模块

通常我们写完一个接口后,接口文档是一个问题,我们这里使用Api Blueprint协议完成对接口文档的书写和mock(可用),同时我们配合使用Swagger通过接口文档实现对接口的实时访问(目前未实现)。

基于phpunit的单元测试,写单元测试是个好的习惯。

tests目录下编写测试文件,具体参考tests/demo目录下的DemoTest文件,然后运行:

目的规范化我们的项目代码和commit记录。

  • 代码规范:配合使用php_codesniffer,在代码提交前对代码的编码格式进行强制验证。

以命令行的方式运行框架,具体见使用说明。

打包PHP项目脚本,打包整个项目到runtime/build目录,例如:

不足的地方还有很多,如果大家发现了什么问题,可以给我提 issue 或者PR。

或者你觉着在这个框架实现的细节你想了解的,一样可以给我提 issue ,后面我会总结成相应的文章分享给大家。

然后正常发起PR即可, 所有的commit我都会进行代码格式(psr)验证和commit-msg验证,如果发生错误,请按照提示纠正即可。

  • 懒加载优化框架加载流程
  • 变更Helper助手类的成员方法为框架函数,简化使用提高生产效率
  • 提供更友善的开发api帮助
  • 模块支持数据库nosql自定义配置
  • 支持mysql主从配置
  • ORM提供更多链式操作api
  • 框架log行为进行级别分类
  • 想办法解决上线部署是配置文件问题

高并发、高流量、高性能 听起来像是架构的问题, 所谓的架构类似下面的: 数据库集群处理, 读写分离; 负载均衡, 流量大, 加机器呗, 没钱? 没听过哪个流量大的项目没钱的... ; CDN, 把静态内容搁置到 CDN 上, 加快下载速度, 也减少数据服务器上带宽的占用; 缓…

我要回帖

更多关于 致命框架1完整版 的文章

 

随机推荐