我的PHP入门实践

开头先讲故事

从开始正式接触 PHP 到现在已经走过了接近两年的时间了。

记得最开始接触 PHP 的时候是大一暑假为期两周的北邮人论坛技术组的培训上。学长学姐们花了五个晚上的时间给我们讲了 HTML、CSS、JavaScript、PHP、MySQL 和 Linux 以及 VIM 等等的基础知识。记得当时 H 仅仅两个晚上就用 PHP 手撸出来了一套 Blog。当时觉得这简直是不可能的事情。五天很快过去,我却连 VIM 怎么进入输入模式都没看懂,更别说去写各种前后端代码了。我还记得当时的绝望。

之后的暑假就是在各种 PHP 和前端视频教程中度过。记得当时是看的我的好友志鹏同学给我推荐的李炎恢的 PHP 教学视频。我看视频的方式就是两倍速度快进,视频看完以后困了就睡觉(只是看视频而不去手写代码),睡醒了就继续起来看,所以当时看学习视频的时候连白天黑夜都已经分不清楚了。看完视频也总是有一些进步,已经可以用自己的(或者是模糊印象中李炎恢的)套路写出一些简单的网站了。但是网站的前端还是很丑陋(因为不怎么会 JS,也不会套模版),而且很多东西也是不成体系。

第一次实践就是在写 VLiner(微联,已经关闭,并不是现在的 VLine)网站的时候。网站很简单,就是像问卷星那样可以提供社团招新报名注册、名单汇总或者订阅报纸等等简单的功能。当时不怎么懂数据库,也不懂得怎么优化并发,所以访问的人一多网站就会崩溃(当时使用 CNZZ 统计应该是高峰期一个小时也就只有 3、4K 的访问量),更要命的是不懂得怎么复用和自动化,所以针对于每个组织的页面都是我手工一个一个填上去的。大概团队撑了半年左右,做不下去就散伙了。

接下来是北邮人论坛以及一个自己拍脑门想的云印项目,这时候我第一次接触到了 MVC 架构和 Yaf 框架,不过也都半途而废。

再次的 PHP 实践机会就是一年之后的弹幕派了。在一次 Hackahton 中,我用二十行 PHP 代码和Cyprestar同学就完成了弹幕派的最初原型。之后在不断重构的过成功逐渐形成了自己的一些套路。这个套路也用在了VLine和北邮人论坛每日十大查询上,主要就是通过 MVC 架构和工厂模式实现了一个很简陋的 API 框架(到底算不算框架呢?)。

接下来在乐享其约项目中见识了 ThinkPHP3.2(当时也并不觉得有多好用,就是一堆方法的封装),在弹幕派重构的时候又见识了 Yii2 框架。

PHP 实践方式

我认为从最开始的原生野蛮的 PHP 写法到现在所认知的几种框架,构成了 PHP 的几种实践方式。

原生野蛮,没有架构

如果就像我最开始写 Vliner 的时候,从 W3school 里面看完 PHP 教程就去撸代码的话,代码大概就会变成这样。

PHP 代码和 HTML 页面全都混写在一起,而且都是采用面向过程的方式完成。用一个页面完成一个逻辑,然后跳转到下一个页面继续。没有 MVC,没有设计模式。

这样的后果就是逻辑非常混乱,而且代码很难复用,一定有许多复制粘贴的操作,就更不提代码的运行效率、维护成本和安全问题了。

当然,事情并不一定总是这样。比如 WikiPedia 的开源版本 MediaWiki,代码也同样没有使用 MVC 模式,没有使用框架,都是自己的逻辑。但是 MediaWiki 也经受住了历史的考验,已经安然运行了十六年多。里面也有许多非常精彩的实践方式。

自己苦思冥想,根据自己的理解规范代码

既然框架就是为了规范代码,所以自己的一套代码规范也可以称作是“比较蠢”的框架了。

大概在弹幕派、每日十大查询和 vline 中,我都使用了自己的一套代码规范,这是在一次一次重构弹幕派代码的时候自己想出来的。为什么不去参考别人的?一是因为懒,看别人的代码进入别人的思路的确需要耗费很多注意力,二来就是心虚,觉得自己水平不够,看别人的代码怎么会看得懂。

所以就根据自己理解的 MVC 构建了自己的一套代码体系(其实和原始的 MVC 非常相似)。以下是这个简单框架的目录结构:

应用访问的方式大概是从最外层的 Index 通过不同的参数调用使用不同的 Controller 并载入配置文件,Controller 过滤输入,完成异常处理,并且根据不同参数选择不同的方法去执行 Model 的内容,而 Model 是文件或数据库的增删查改操作的封装,通过继承最基本的数据库或文件的 Model 实现,最后 Controller 还可以根据需要返回 Json 或者渲染 View。

在数据库的 Model 中使用了一个好友自己封装的数据库基类,在 View 渲染中试用了 Smarty 引擎。这样,需求比较简单的 WebApp 使用这套代码就可以很轻松地实现。

这里,也应该抛弃 FTP,学会使用 Git 或者 SVN 进行版本控制,以便于多人协作。 虽然这个框架简单到都没有一个像样的路由,但每次写代码都屡试不爽,以至于我沉溺其中无法自拔,耽误了很多学习更好 PHP 思维的时间。更关键的是因为数据库基类使用的都是被 PHP7 抛弃的类似于 mysql_connect()这种函数,所以在过去很长一段时间里我都拒绝使用 PHP7。

随着工程量的扩大,简单的工厂模式因为写起来重复代码很多,而且不支持 autoloader,所以这个小框架也逐渐让我感到力不从心。特别是自己封装的数据库基类并不如使用 ORM 模型的库用起来方便,而且也成为了应用效率的瓶颈,现在也是时候说再见了。

使用传统大而全的 PHP 框架,进入该框架的社区

比如 ThinkPHP3.2 或者 Yii2 都是传统大而全的 PHP 框架。我对这类框架是用的不多,都是在基本应用的范围内。

这类框架的缺点就在于一旦进入,就会被限制在这个框架的生态里面,不论是使用完成一些奇奇怪怪功能的插件,还是自己写的代码,都很难做到在其他框架的项目中复用,项目的命运也很可能就会和框架的命运绑定在一起。

但这类框架本身生态也非常成熟,一般都有非常庞大的社区(特别是 ThinkPHP3 之于中国),而且大而全,遇到问题很轻松搜索到解决方案,所以也可以作为主力开发的框架。

一个比较神奇的框架就是 Yaf,它是一个由 C 语言写成的 PHP Mod,运行时直接嵌入 PHP 引擎,所以性能上来说,是绝对的强悍。遇到追求性能的地方,Yaf 是不二之选。但是正因为它作为一个 PHP 的模块存在,也丧失了一些灵活性。

活在 PHP 大社区,模块化构建 PHP 应用

正如我在上一篇文章《Modern PHP》——关于 PHP 的最佳实践和最新进展中所说,如今的 PHP 已经不是网上许多文章所写或者是许多教程里所讲的那样,PHP 已经蜕变成了一门(不是那么)优雅而现代的语言。

Composer 的出现,让工程化的思想带入了 PHP,世界上最好的语言终于不在乱糟糟,她开始变得标准而统一。(这句话其实来自 justjavac 大大的原话,原文链接:http://zhihu.com/question/27453375/answer/36939511

Composer 构建了一个大的 PHP 社区,就像 NodeJs 的 nmp 或者 Python 的 pip 一样,Composer 以非常优雅的方式完成了 PHP 应用的构建。

以往的实践方式就是不断从网上下载代码,拷贝到目录里(这完全没办法对第三方代码进行版本控制),说不定还会对第三方代码进行修改,那么如果更新的话,就更是灾难。而且 Composer 也减少了许多造轮子行为的发生(如果我之前知道这个社区的话,那么为什么还会有自己封装的那么简陋的 MySql 类库呢?)

而 Laravel 正是这个精神的践行者。如果说 Modern PHP 还不是那么优雅的话,那么 Laravel 就补齐了 PHP 的最后一块短板。Laravel 符合 PHP 的 PSR 标准,而且采用了 Composer 模块化的方式构建,而且基本没有自己重复造轮子(甚至许多库都直接来自 Symfony 框架)。这样,只要符合标准的 PHP 库将都会是 Laravel 生态的一员。可以想象,如果构建一个长期运行的项目,Laravel 自然是不二之选。

使用 PHP 做更多的事情

其实 PHP 还可以做更多别的事情,比如去做 CLI 开发。

借助 Composer 和 AutoLoader,PHP 具有了不亚于 Python 作为胶水语言的能力,可以作为替代 Bash 的更方便的脚本解释器。

PS:如果还非要说 php 还不优雅的话,那就只剩下开头的<?php 符号(有开头没有结尾,不知逼死了多少强迫症)和 Bash 脚本的#!/usr/bin/php 冲突的问题了。

PHP 甚至还可以来作为一个高性能的 Web 服务器,性能不输给 Nginx,而且可以高效完成许多 Socket 相关操作。WorkerMan是一个非常优秀的实现。

其实,PHP 也可以写桌面程序,比如 PHP-GTK 库就是做这个的。但我觉得这样的确是多此一举,2015 年以后也真就没啥动静了。

最后讲两句

到这里,我觉得现在可以算是入门 PHP 了吧。然而以后的路还有很长,PHP 各种特性/设计模式以及优化方式我还知之甚少。

我认为 PHP 最大的优势在于易于上手,简单几行代码就可以写出一个网站。正是因为这种令人发指的简单,让 PHP 的实践方式变得异常自由,但也让 PHP 社区变得混乱,每一个人的水平差距会非常大。

所以我认为 PHP 依旧是最容易入门的一门脚本语言,学习曲线比类似 Java 的 Spring 或者 C#的 Asp.net 平缓很多,但如果想做出一个优秀的 Web 应用,那么难度也绝对不比那两者低。

不论这一路还有多少坑要踩,多少锅要背,我也还是会选择走下去。

踏歌长行,梦想永在!