奇技指南
语法糖往往给程序员提供了更实用的编码方式,可以使代码更简洁流畅,语义更自然。本文介绍笔者自己写的 PHP 语法糖扩展,扩展了一种全新的 PHP 超全局变量获取方式。
本文作者范家鹏,360 技术委员会 –WEB 服务端分 TC 委员。
1、说说语法糖
首先说说“语法糖”这个词绝非贬义词,它可以给我们的开发工作带来便利,是一种轻量级便捷的写法,既不会对语言本身的使用造成不利影响,也不会在性能上带来损失。
通常情况下,使用语法糖能够增加程序的可读性,减少程序复杂性,减少编码中出错的机会,也对开发工程师具有友好性,能够提升我们的开发效率。
优秀的语法糖,应该是一种灵魂思想的注入,简单写法的应用。我这里用一幅图来表示:
2、什么是 SG?
SG 全称 Superglobals,引用全局作用域中可用的全部变量。SG扩展了一种全新的 PHP 超全局变量获取方式。
这些超全局变量是:_SERVER,_GET,_POST,_FILES,_COOKIE,_SESSION,_REQUEST,_ENV。
当然了,也可以应用到自定义变量场景。
非常重要的一点是:它很简单!
2.1 项目背景
这个 idea 出发点很简单,从扩展名称我们应该能猜到它是做什么的。
在性能最优的前提下:
- 能通俗易懂地简化 HTTP 参数获取方法
- 需要对 HTTP 参数值进行统一过滤、转换、解密操作
- 获取 HTTP 参数前,需要进行一些 Predefined Operation
- 针对 HTTP 参数的一切行为,需要同步更新对应的 PHP Superglobal
- 声明时才使用,而非请求一开始就对 PHP Superglobals 扫荡式处理
- 在 global 语法上,扩展一项能获取 HTTP 参数的能力
So,SG出现就是为了解决上面这些问题而来,它提供了一种更加甜蜜的语法,当前已经发布了 v3.0.0。
2.2 项目地址
https://github.com/yulonghu/sg
欢迎大家来提交 Issues~
当前支持的 PHP 版本,如下图所示:
3、SG 的特性
- 简单,快速,轻量
- 零拷贝访问 PHP 超全局变量,使用 SG 会同步更新 PHP 超全局变量
- 支持取值前调用自定义函数,默认情况下,字符串变量会自动调用 PHP trim
- 解决使用 PHP 超全局变量时出现未定义系列的问题 (Undefined variable, Undefinedoffset)
- 采用静态方法时,以小数点代替 PHP 数组维度
- 采用 global 声明方式时,以下划线代替 PHP 数组维度
- 支持可配置的 global $variable 查找深度,默认一级查找
4、配置项(php.ini)
配置项 | 权限 | 类型 | 默认值 | 说明 |
---|---|---|---|---|
sg.enable | PHP_INI_SYSTEM | bool | 0 | 0 关闭 1 开启 |
sg.global_level | PHP_INI_SYSTEM | bool | 1 | 1 只支持一级查找 0 无限制查找 |
sg.func_name | PHP_INI_ALL | char | trim | 默认调用 PHP trim 函数,也支持自定义函数 |
5、Hash Map
PHP 超全局变量 | SG key (关键字缩写) | global 声明 | 函数 |
---|---|---|---|
$GLOBALS | 无 | 无 | sg::all() |
$_SERVER | s | global $s | sg::get/set/has/del(‘s’) |
$_GET | g | global $g | sg::get/set/has/del(‘g’) |
$_POST | p | global $p | sg::get/set/has/del(‘p’) |
$_FILES | f | global $f | sg::get/set/has/del(‘f’) |
$_COOKIE | c | global $c | sg::get/set/has/del(‘c’) |
$_SESSION | n | global $n | sg::get/set/has/del(‘n’) |
$_REQUEST | r | global $r | sg::get/set/has/del(‘r’) |
$_ENV | e | global $e | sg::get/set/has/del(‘e’) |
6、流程图
6.1 global 声明方式(PHP7)
6.2 函数方式
7、API
7.1 global 声明方式
global $g_key, $p_key, $c_key, $s_key, $f_key, $n_key, $e_key, $r_key
7.2 静态方法
bool sg::set(string $key, mixed $value)
mixed sg::get(string $key [, mixed $default_value = null])
bool sg::has(string $key)
bool sg::del(string $key [, mixed $...])
array sg::all(void)
8、例子
8.1 global 声明例子
8.1.1 sg.global_level = 1
<?php
$_GET['key'] = 'GET_test_key';
function testGlobal()
{
global $g_key;
var_dump($g_key);
$g_key = 'NEW_GET_test_key';
}
testGlobal();
var_dump(sg::get('g.key'));
var_dump($GLOBALS['g_key']);
var_dump($g_key);
var_dump($_GET['key']);
以上例子输出的结果:
string(12) "GET_test_key"
string(16) "NEW_GET_test_key"
string(16) "NEW_GET_test_key"
string(16) "NEW_GET_test_key"
string(16) "NEW_GET_test_key"
8.1.2 sg.global_level = 0
<?php
$_GET['key']['key1']['key2'] = 'GET_test_key';
function testGlobal()
{global $g_key_key1_key2;}
testGlobal();
var_dump(sg::get('g.key.key1.key2'));
var_dump($GLOBALS['g_key_key1_key2']);
var_dump($g_key_key1_key2);
var_dump($_GET['key']['key1']['key2']);
以上例子输出的结果:
string(12) "GET_test_key"
string(12) "GET_test_key"
string(12) "GET_test_key"
string(12) "GET_test_key"
8.1.3 sg.func_name
<?php
ini_set('sg.func_name', 'decryptTest');
$_POST['key'] = 'IEEgQmFuYW5hIA==';
function decryptTest($data)
{return trim(base64_decode($data));
}
var_dump($p_key);
以上例子输出的结果:
string(8) "A Banana"
8.2 静态方法例子
8.2.1 get/set/has/del()
<?php
$key = 'test';
$val = 'A Banana';
echo "------------------start\n";
var_dump(sg::get($key));
var_dump(sg::get($key, 'def'));
var_dump(sg::has($key));
echo "------------------set\n";
var_dump(sg::set($key, $val));
echo "------------------get\n";
var_dump(sg::get($key));
var_dump(sg::get($key, 'def'));
var_dump(sg::has($key));
echo "------------------del\n";
var_dump(sg::del($key));
echo "------------------get\n";
var_dump(sg::get($key));
var_dump(sg::has($key));
以上例子输出的结果:
------------------start
NULL
string(3) "def"
bool(false)
------------------set
bool(true)
------------------get
string(8) "A banana"
string(8) "A banana"
bool(true)
------------------del
bool(true)
------------------get
NULL
bool(false)
8.2.2 sg.func_name
<?php
ini_set('sg.func_name', 'encryptTest');
function decryptTest($data)
{return trim(base64_decode($data));
}
function encryptTest($data)
{return base64_encode(trim($data));
}
sg::set('user', encryptTest('A Banana'));
var_dump(sg::get('user'));
以上例子输出的结果:
string(8) "A Banana"
9、性能测试
噼里啪啦说了大半天,性能到底怎么样呢?我在本地环境做了一个简单的 ab 测试(ab -c100 -n10000),PHP 测试代码如下:
9.1 default – 源码
<?php
/* default.php */
for($i = 0; $i < 1000; $i++) {if(isset($_GET['key'])) {var_dump(trim($_GET['key']));
}
}
9.2 global 声明方式 – 源码
<?php
/* sg.php */
for($i = 0; $i < 1000; $i++) {
global $g_key;
var_dump($g_key);
}
ab 测试的结果如下:
9.3 default – 结果
$ ab -c100 -n10000 localhost/default.php?key=hello_world
Concurrency Level: 100
Time taken for tests: 1.615 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 251370000 bytes
HTML transferred: 250000000 bytes
Requests per second: 6190.21 [#/sec] (mean)
Time per request: 16.155 [ms] (mean)
Time per request: 0.162 [ms] (mean, across all concurrent requests)
Transfer rate: 151956.36 [Kbytes/sec] received
9.4 global 声明方式 – 结果
$ ab -c100 -n10000 localhost/sg.php?key=hello_world
Concurrency Level: 100
Time taken for tests: 1.441 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 251931544 bytes
HTML transferred: 250557708 bytes
Requests per second: 6938.67 [#/sec] (mean)
Time per request: 14.412 [ms] (mean)
Time per request: 0.144 [ms] (mean, across all concurrent requests)
Transfer rate: 170709.87 [Kbytes/sec] received
10、总 结
SG具有以下优势:
- 兼容了当前的主流 PHP 版本
- 提供了一种更加甜蜜的语法,丰富了 Superglobals 的应用
- 我们始终相信:简单才是王道
注意:global 声明方式,当前只支持不可变变量名。
(360 技术原创内容,转载请务必保留文末二维码,谢谢~)
关于 360 技术
360 技术是 360 技术团队打造的技术分享公众号,每天推送技术干货内容
更多技术信息欢迎关注“360 技术”微信公众号