《高性能 PHP7》笔记

《高性能 PHP7》笔记

编程那点事 随便写写 PHP 2586 字 / 5 分钟

类型声明

PHP 作为一个弱类型的语言,加入类型声明,真是一件大好事啊!这样确实能够减少很多 bug 的产生,今后也要试着养成写类型声明的习惯。

形参类型声明

function foo(int $num){
	echo($num);
}
// foo(123); -> 123
// foo('123'); -> 123
// foo('asd'); -> PHP Warning

这里使用类型声明,会对传入的参数进行类型检测。 但是!我这里限制了$num形参为int类型;而当我传入为string类型的'111'时,**PHP 会对其进行强制转换。**若能够成功转换,则正常运行,不报错。否则,报一个 Warning 级别的错误。 但是++!当我传入0easdfgh这种类似“科学计数法”的字符串时,PHP 会报一个 Notice 级别的错误,并继续执行。可见,它这里也是当成科学计数法强制转成了整形数字。

返回类型声明

function foo(): string{
	return 'here is string';
}

同上,这里是对函数 / 方法返回值类型的限定。并且,也有如上中的两个奇怪的特性:**若返回值不满足条件,会进行一遍强制转换。**若转换不成功,会报一个 Warning 级别的错误。int类型传入类似科学计数法的字符串,如果不是真正的科学计数法, 会报一个 Notice 级别的错误,并继续执行。

以上的类型限定,也支持自定义的类。

匿名类

$name = new class(){
	public function __construct(){
		echo('John Wu');
	}
}

这样就声明了一个匿名类。它与普通定义的类相同,可以实现继承,重写。

不推荐使用老式的构造方法

从 PHP 4 开始,构造函数可以使用与类名一致的方式来声明。这种方式被一直沿用至 PHP 5.6。但是在 PHP 7 中,这种方式已经不再被推荐使用。这个其实对我的影响不大,我从一开始就是使用__construct()来声明构造函数的。但是注意,如果一个类中即存在__construct()和与类名相同的老式构造函数,PHP 会把__construct()当做构造函数来看待。而老式的构造函数则当做普通的类方法,不会在类实例化的时候被调用。

太空飞船操作符<=>

这个名字,Spaceship Operator真的有够科幻的。 主要是用于usort uasort uksort那几个自定义排序函数的。规则如下:

  • 当符号两边相等时返回0
  • 当符号右边大于符号左边时返回-1
  • 当符号左边大于符号右边时返回1

null 合并运算符??

这个运算符我在写助手的项目时专门用到过。 ??是为了解决原来要用isset()和三元运算符才能做到的事情。

$post = $_POST['tilte'] ?? 'No title';

这里会判断第一个参数$_POST['tilte']是否存在,即判断isset($_POST['tilte'])是否为true,如果为true,则返回$_POST['title']的值,否则返回后面的值,即No title。 null 合并运算符还可以多个一起使用:

$title = $_POST['title'] ?? $_GET['title'] ?? 'No title';

写成原来的老式代码,就是:

if(isset($_POST['title'])){
	$title = $_POST['title'];
}else if(isset($_GET['title'])){
	$title = $_GET['title'];
}else{
	$title = 'No title';
}

很明显,使用 null 合并运算符?? 效率会快很多。因为在日常开发中,关于$_POST $_GET $_REQUEST的参数传入检测是很常用的,因此这个运算符真的是太需要了。

统一变量语法

这个其实也不说不清它重要不重要。因为日常开发中这么写的,出现这种情况的,其实真不多。可以说程序员会尽可能避免去写这样的代码,因此也太会遇到这种情况。 不多说,上一个例子:

class Foo{
	function bro(){
		echo('ok!');
	}
}

$object = new Foo();
$methoods = ['title' => 'bro'];
echo( $object->$methods['title']() );

上面一段代码,在 PHP 5.x 版本上运行没有问题。但是在 PHP 7 中,会默认从左到右进行解析,从而导致刚开始尝试解析的是$object->$methods,这会报一个 Fatal 级别的错误。因此,需要使用大括号{}对顺序进行调整,修改为:

echo( $object->{$methods['title']()} );

Unserialize 函数引入过滤器

PHP 反序列化漏洞大概是从前年开始得到重视的。这个确实危害挺大的,直接可以对当前运行程序的变量进行替换。 而 PHP 7 引入的 Unserialize 函数过滤器,可以限制允许反序列化的类:

$result = unserialize($object, ['allowed_classes' => ['Packt', 'Books', 'Ebooks'] ]);

但是默认情况下,如果不设置过滤器的话,是允许反序列化所有类型的对象的。

开启 GZIP 压缩

自从看了这一节后,我便把自己服务器上的网站都开启了 gzip 压缩。还真别说,压缩率高达 80%!!速度确实上来了不少。看来是以后建站必做的事情啊。 值得留意的是,浏览器的请求头中会有一个Accept-Encoding,用来说明自己可接受的压缩方式,然后服务器的返回头中的Content-Encoding,表明了当前使用的压缩方式。

在 Apache 环境下开启

编辑.htaccess文件:

<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
	# 不压缩图片
	SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png) $ no-gzip dont-vary
</IfModule>

在 Nginx 环境下开启

在 Nginx 的站点配置文件中,加入:

gzip on;
gzip_very on;
gzip_types text/html text/plain text/xml text/css text/javascript application/x-javascript;
gzip_com_level 4;

这里的gzip_com_level为压缩等级,范围为1 - 9,不宜设置太高,建议取中间值。

Redis 键值缓存存储

这本书上初步讲了很少一点的 Redis,我有要学习 Redis 的打算,不过现在连 MySQL 都没搞清,连个视图都不会写。QAQ

检测 Redis 服务器是否开始运行

redis-cli ping

Redis 默认使用本地 IP 和端口 6379,**尽管远程连接可以被开启但并不被允许。**Redis 在 database 中保存数据,database 被命名为如 0、1、2 等整型数字。

改变当前数据库

SELECT 1

清空当前数据库中的所有键、值

FLUSHDB

清空所有的数据库

FLUSHALL

列出当前数据库中所有匹配指定模式的键

KEYS *

PHP x Redis

连接 Redis 服务器

$redisObject = new Redis();
if( !$redisObject->connect('127.0.0.1', 6379))
	die("Can't connect to Redis Server!");

保存&获取数据

$redisObject->set('name', 'John Wu');
echo( $redisObject->get('name') );

其实我们也可以把json_encode后的字符串以键值对的形式进行保存的。这样其实就可以实现保存数组了。 这本书讲的真的很浅很浅啊,之后更多的关于 Redis 的还得自己找些书去看。

Xdebug

Xdebug 这里我还没有实践过,之后实践配好后会写一篇文章去详细聊聊。

PHP 压力/负载测试

Apache JMeter

JMeter 使用 Java 编写,可以提供不同种类的压力测试。 因为全是图形化的,所用起来应该挺方便的。书上是起很多歌线程,然后疯狂循环发请求,最后能够生成图表来查看。

ApacheBench(ab)

ApacheBench 随着 Apache HTTP Web 服务器一起被安装。所以在 Apache 中自带。

ab -n <Number_Requests> -c <Concurrency> <Address>:<Post><Path>
  • n:发送测试请求的总数目
  • c:并发量,一次同时发的请求的数目
  • Address:URL 或 IP
  • Port:端口号(默认 80 端口)
  • Path:路径

通过不断增加发送测试请求和并发量,就可以知道服务器的性能。关于这个,我觉得也可以直接用在 Golang 的压测上?

PHP 代码规范

PHP 通用性框架小组定义的 PHP 代码风格。

  • 类名中每个单词的首字母必须大写,大括号换行。
class WishList
{
	
}
  • 类中的方法名和函数命名都应该是驼峰式的。大括号换行。(这点我不承认)
public function phpBook($arg1, $arg2){
	
}
  • 命名空间的声明后应该空一行。
namespace Packt\Videos;

use Packt\Books;
use Pakct\Presentations;
  • if``for大括号都不换行。true``false都小写。

嘛……整本书比较重要的感觉就这些了。这书真的挺薄的,不过这份总结我也咕了很久。 接下来 PHP 方面就是接着写我的那个 API 框架,再去配一下 Xdebug。