《高性能 PHP7》笔记
类型声明
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。
喜欢这篇文章?为什么不打赏一下呢?