Modern PHP
首先推荐这本书,不厚,沉下心来半天能看完。前半部分才是介绍的新特性,后半部分讲的都是测试、部署的工具和流程。没有编码技巧,只是介绍了 PHP 最新的现代化的工程开发、测试、部署应该是什么样。其实这也是最重要的,PHP 需要一种优雅、有效的方式来规范化工程的开发。
这本书基于 5.6 的,毕竟那个时候 PHP7 没有发布,但是读者应该以现在的眼光和视角来阅读这本书,毕竟技术一直在向前发展,从作者整理到出书甚至得加上翻译再出版,这个时间已经很长了。
从另外一个角度来看,互联网才是获取知识的最快途径,并且,英文很重要。
本人在做笔记整理的时候,会加入 PHP7 (截止目前 7.1) 的一些特性和一些书上没介绍的,但本人接触比较多的特性,会在后面注明:补。
语言新特性
命名空间 (5.3)
这是现代 PHP 组件生态系统的基础。
命名空间好比操作系统中的目录,两个同名的文件可以共存在不同的目录下。同理两个同名的 PHP 类可以在不同的 PHP 命名空间下共存,就这么简单。
你的代码很可能和其他开发者的代码使用相同的类名、接口名、函数名或常量名,如果不使用命名空间,名称会起冲突,导致 PHP 执行出错。而使用命名空间,把代码放在唯一的厂商命名空间中的话,你的代码和其他开发者的代码可以使用相同的名称命名类、接口、函数和常量。
有些代码可能没有命名空间,这些代码就存在于全局命名空间中,在命名空间中引用全局命名空间代码的时候,要在前面加上 \
,比如你在自己的命名空间中调用 PHP 原生的 Exception
类。
后期静态绑定 (补 5.3)
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
//输出:A
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // 后期静态绑定从这里开始
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
//输出:B
“后期绑定” 的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为 “静态绑定”,因为它可以用于(但不限于)静态方法的调用。
使用接口
接口并不是特性,而是面向对象中一个很重要的思想。
接口是两个 PHP 对象间的契约,其目的不是为了让一个对象依赖另一个对象的身份,而是依赖于另一个对象的能力。
使用性状 (5.4)
性状表明了这个 trait
可以做什么,又提供了一种模块话的实现,既像类又像接口。然而其实两者都不是,性状是部分类的实现 (包含常量、属性、方法),可以混入到一个或多个 PHP 类中。
你想下,手机和汽车都用定位功能,他们两者没有什么关联,继承同一个父类显然不合适,但是他们如何复用定位有关的功能呢?现在我们项目中是通过封装一个 service 来实现复用的。
在 Laravel 里面可以看到很多 trait
使用场景,典型的就是 Auth 认证服务。
class LoginController extends Controller
{
use AuthenticatesUsers;
....
}
trait AuthenticatesUsers
{
....
}
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
生成器 (5.5)
生成器是只能向前进行的迭代器,这意味着不能使用生成器在数据集中执行后退、快进、查找操作,只能让生成器计算并生产下一个值。
<?php
function makeRange($length)
{
for($i = 0;$i < $length;$i++){
yield $i;
}
}
foreach(makeRange(10000000) as $i){
echo $i.PHP_EOL;
}
每当产生一个数组元素,就通过 yield
关键字返回成一个,并且函数执行暂停,当返回的迭代器的 next
方法被调用的时候,会恢复刚才函数的执行,从上一次被 yield
暂停的位置开始继续执行,到下一次遇到 yield
的时候,再次返回。foreach
会自动调用 next
方法。
还有一个更高级的用法,见鸟哥博客。
在 PHP7 中,当生成器迭代完成后,可以获取该生成器函数的返回值 (如果有 return
操作的话)。通过 Generator::getReturn()
得到。
闭包 | 匿名函数 (5.3)
PHP 中的闭包很有意思,它可以引用外部变量,并且可能保存其状态,直到使用的时候。
最常用的闭包在 array_map
这个函数中。
<?php
$result = array_map(function($value){
return $value + 1;
},[1,2,3]);
print_r($result);
//[2,3,4];
或者直接创建一个闭包。关于实现,涉及到_invoke()
方法,可以看官方文档。
<?php
$closure = function($blogName){
return 'Welcome to '.$blogName;
}
echo $closure('chengxiaobai');
//Welcome to chengxiaobai
附加一个外部状态到闭包内。
<?php
function hello($blogName){
return function($userName) use ($blogName){
return sprintf('Hello %s,welcome to %s',$userName,$blogName);
}
}
//附加 chengxiaobai 到闭包内
$helloString = hello('chengxiaobai');
//正常调用闭包
echo $helloString('Tom');
//Hello Tom,welcome to chengxiaobai;
//下面也是相同的效果
$blogName = 'chengxiaobai';
$helloString = function($userName) use ($blogName){
return sprintf('Hello %s,welcome to %s',$userName,$blogName);
};
echo $helloString('Tom');
//Hello Tom,welcome to chengxiaobai;
还有一个很有意思的 bindTo
方法,laravel 的路由闭包就用了这个方法,具体可以去看看 laravel。
可变长函数参数 (补 5.6)
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
//输出 10
社区 (PHP-FIG) 规范 (PSR)
中文翻译文档在这里,已经落后了,仅供参考吧
PHP-FIG 的目的是实现组件的互操作性。这个互操作性是指通过接口、自动加载机制和标准的风格,让组件互相合作。
PSR 是 PHP Standards Recommendation 的简称,中文就是 PHP 推荐标准。每一个规范都是用于解决大多数 PHP 框架经常用会遇到的某个具体问题。
正是大家都遵循于此规范,才让大家现在如此轻松的使用第三方组件,减少很多重复造轮子的工作,也让整个社区的编码质量得到了提升,最典型的就是 Symfony。
序号 | 描述 | 备注 |
---|---|---|
1 | Basic Coding Standard | 编码基础规范 |
2 | Coding Style Guide | 编码风格规范 |
3 | Logger Interface | 日志接口规范 |
4 | Autoloading Standard | 自动加载规范 |
6 | Caching Interface | 缓存接口规范 |
7 | HTTP Message Interface | HTTP 消息接口规范 |
13 | Hypermedia Links | 超媒体链接规范 |
16 | Simple Cache | 轻量缓存接口规范 |
本来有个 PSR-0,也是自动加载规范,但是已经被 PSR-4 替代了,但是现在部分框架依然使用了该规范,比如鸟哥的 Yaf 框架。
组件
在组件概念没有流行前,要解决问题,大都选择某个全栈框架去开发应用解决问题。大家会花大量时间去学习某个框架的封闭生态系统,使用这个框架提供的工具,很难集成第三方库或者自定义库,因为这些库没有使用相同的接口。但是现在,这样的日子一去不复返了,现在不必拘泥于框架筑起的围墙中了。
组件是什么?组件就是打包好的代码,用于解决某一个具体的问题。比如 Guzzle,Monolog。
一般选择一个合适的组件可以从几个方面来选择:
- 作用单一,能很好的解决一个问题,术业有专攻,并不需要一个万金油。
- 精炼
- 适配性,能很好的结合现有代码,并且与其他组件间能很好的适配。尽量不选有侵入性的组件,万一改了你的默认时区呢?
- 最好有测试用例,能很好的介绍如何使用该组件,也能提高测试覆盖度。
- 文档完善。应该有良好的文档说明,方便大家理解和使用。
- 社区活跃度。
在 Packagist 你能找到很多组件,这是一个专门收集组件的地方。当然你得使用神器 Composer,PEAR 现在也还能用,但向 Composer 靠拢吧。
组件和框架的选择。用正确的工具做正确的事情即可。组件和框架的区别好像专科医生和医院的区别。大多数现代框架也是构建在小型的 PHP 组件之上的一系列约定。
当然,团队协作最好还是使用框架,并不是说框架提供了多丰富的功能,而是为了一种规范和约定。