PHP最佳实践
PHP关于应用架构、规划、数据库、安全、测试、调试和部署方面的行业标杆。
概述
3年前,我刚转做WEB开发,用PHP做了几个小网站、公众号和WEB APP以后,对PHP的印象可以用4个字形容——累觉不爱。
从手动引入自己写的代码文件,到引用产品的某个函数,到记录日志,到缓存数据,到发邮件不卡住,每换一个产品,这些基础的问题都要重新解决一遍,重复开发基础的功能(比如日志),重复写机械的代码让我实在很崩溃。
在我的观念里,软件开发不应该这样的,应用层面的软件开发发展到今天,开发者应该可以做到将注意力集中在在业务问题上,而不是再陷入语言特性和基础设施上。有一段时间我很矛盾,是否该考虑转向JAVA、Python、Node试试了。
现代PHP的出现,结束了这个矛盾的过程,那些前面令人饱受煎熬的问题,都得到了解决。
包管理、自动加载,PSR标准,以及日志、缓存、队列、命令行作为基础设施的组件,使得这个古老的语言脱胎换骨。在有了这些现代化特征后,我才第一次感觉到自己是在关注业务,而不用像之前为了让发送邮件不卡住而专门写一个简易队列。
因此,现代PHP之所以重要,就在于它将你从重复劳动中解放出来,将注意力更多地集中在具体的业务上。
开发:关注业务
在前面“现代PHP为什么重要”其实对这个问题已经有了一定的探讨。现代PHP的包管理、自动加载、PSR标准,以及日志、缓存、队列等各种组件,都是为了让开发者可以将注意力集中在解决业务问题上。
没有这些现代化特征,实际开发最容易碰到的问题就是重复开发基础功能。比如写日志时,发现没接口,于是自己实现一套简易的;发邮件不想阻塞请求,于是自己写了一个简易队列。花在写基础设施的时间比花在解决具体业务的时间都多。而且还不稳定。
工程管理:测试、部署、分析都有标准化的工具
“在过去,常见的做法是编写一个PHP文件,使用FTP上传到生产服务器,然后祈祷它能正常运行。这种开发策略非常可怕,但又必须这么做,因为当时没有可用的本地开发环境。”WEB开发是个工程管理问题比技术问题多的领域,沿用上述的这种工程管理策略,能把自己玩吐血。
现代的PHP项目的标配采用的是最佳实践的工程管理方式。
用Git做代码版本控制管理(不再使用不可靠的FTP):帮助我们维护一个可审查的代码历史,让我们可以创建代码分支、复刻(fork)代码和合并代码。
用虚拟化工具(例如Vagrant)以及配置工具(例如Ansible、Chef和Puppet),搭建和生产服务器一样的本地开发环境
通过依赖管理工具Composer使用专门的PHP组件。
在代码推送完成后通过CI/CD自动完成测试和布署。如果布署有问题,则要立刻回滚。
在性能分析上,则通过xhprof或者new relic这样的工具去分析并改进。
PHP代码遵循PSR,这是由PHP Framework Interop Group管理的社区标准。
使用PHPUnit等工具彻底测试编写的代码。
使用PHP的FastCGI进程管理器部署应用,并且放在nginx这样的Web服务器之后。
使用操作码缓存来提升应用的性能。
使用接口
依赖接口,而非具体实现,可以解耦,参考 Laravel 的契约
性状(trait)
这个特性很有意思,名字名副其实。
假如现在有一个人,还有一辆车,车和人都要实现给自己定位的功能,显然车和人不适合从一个父类继承,那这个时候 trait 就排上用场了。这是一个横向复用机制,让若干不想关的类带上同样一个性状。
http://php.net/manual/zh/language.oop5.tra...生成器(yield)
这个特性也很有用,yield 和 return 类似,区别在于 yield 只产出值,不返回值。
也可以这样理解,return 是一次性全部交付给你,yield 是承诺全部交付给你,但这次先把你现在用到的东西给你,剩下的下次你再来取。
显然,在迭代一个超大数据的时候(遍历超大数组),yield 可以先给你一个元素,不用生成整个数组,可以省内存。
上代码:
<?php
function makeRange($length){
$arr=[];
for($i=0;$i<$length;$i++) $arr[]=$i;
return $arr;
}
$results=makeRange(100000);
foreach($results as $i) echo $i.PHP_EOL;
<?php
function makeRange($length){
$arr=[];
for($i=0;$i<$length;$i++) yield $i;
}
foreach(makeRange(100000) as $i) echo $i.PHP_EOL;
第一个是先生成一整个数组再遍历,第二个是一边生成一边遍历。
闭包,命名空间,opcache
PSR,组件,composer
这三个东西对现代 PHP 意义特别重大,选择可复用组件就是选择了未来,细分领域让最专业的人去做。
过滤,验证,转义(防注入和防XSS)
输入和输出要过滤 html,使用 htmlentities($str, ENT_QUOTES, "UTF-8"); 第二个参数开启转义单双引号,第三个参数指明字符集,都是必须开启的。
使用 PHP 自带过滤和验证函数
filter_input()
http://php.net/manual/zh/function.filter-i...
filter_var()
数据库
使用 PDO 和预处理
密码
使用内置的密码函数,使用bcrypt 加密
password_hash()
http://php.net/manual/zh/function.password...
password_verify() http://php.net/manual/zh/function.password...
多字节字符串
使用 mb 系列函数