奇技指南
語法糖往往給程式設計師提供了更實用的編碼方式,可以使程式碼更簡潔流暢,語義更自然。本文介紹筆者自己寫的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技術”微信公眾號