PHP中的字符串饵骨、編碼丐怯、UTF-8

最近看了不少編碼方面的文章煞抬,所以分二篇博文說(shuō)下“PHP疟羹、字符串县好、編碼围橡、UTF-8”相關(guān)知識(shí),本篇博文是上半部分缕贡,分為四大塊內(nèi)容翁授,分別是“字符串的定義和使用”、“字符串轉(zhuǎn)換”晾咪、“PHP 字符串的本質(zhì)”收擦、“多字節(jié)字符串”。上半部分比較基礎(chǔ)禀酱,下一篇文章《PHP 與 UTF-8的最佳實(shí)踐》可能干貨更多一點(diǎn)炬守。

字符串的定義和使用

PHP 中能夠通過(guò)四種方法設(shè)置字符串:

單引號(hào)字符串
單引號(hào)字符串類似于 Python 中的原始字符串,也就是說(shuō)單引號(hào)字符串沒(méi)有變量解析功能和特殊字符轉(zhuǎn)義功能。比如$str='hello\nworld'剂跟,其中的\n并沒(méi)有換行功能减途。

雙引號(hào)字符串
雙引號(hào)字符串具備單引號(hào)字符串沒(méi)有的變量解析功能和特殊字符轉(zhuǎn)義功能。

個(gè)人對(duì)于十六進(jìn)制和八進(jìn)制的字符串特殊轉(zhuǎn)義很感興趣曹洽,特別補(bǔ)充:

\[0-7]{1,3} #八進(jìn)制表達(dá)方式
\x[0-9A-Fa-f]{1,2} #十六進(jìn)制表達(dá)方式

heredoc
這種表達(dá)式類似于 Python 中的長(zhǎng)字符串鳍置,能夠定義包含多行的字符串。其語(yǔ)法定義很嚴(yán)格送淆,使用起來(lái)需要注意税产。

$str=<<<EOD
hello\n
world
EOD;

Nowdoc
Nowdoc類似于單引號(hào)字符串,不會(huì)解析變量偷崩。比較適合定義一大段文本且無(wú)需對(duì)其中的特殊字符進(jìn)行轉(zhuǎn)義辟拷。

變量解析
PHP字符串最強(qiáng)大的部分就是變量解析,可以在運(yùn)行時(shí)根據(jù)上下文解析變量(這才是解釋型語(yǔ)言)阐斜,可以產(chǎn)生很多妙用衫冻。

簡(jiǎn)單的變量解析就是在字符串中可以包含“變量”,“數(shù)組”谒出,“對(duì)象屬性”隅俘,復(fù)雜的語(yǔ)法規(guī)則就是使用{}符號(hào)來(lái)進(jìn)行操作(組成一個(gè)表達(dá)式)。

通過(guò)一個(gè)例子看看變量解析的強(qiáng)大之處

class beers {
    const softdrink = 'softdrink';
    public static $ale = 'ale';
    public $data = array(1,3,"k"=>4);
}

$softdrink = "softdrink";
$ale = "ale";
$arr = array("arr1","arr2","arr3"=>"arr4","arr4"=>array(1,2));
$arr4 = "arr4";
$obj = new beers;
echo "line1:{$arr[1]}\n";
echo "line2:{$arr['arr4'][0]}\n"; 
echo "line3:{$obj->data[1]}\n";
echo "line4:{${$arr['arr3']}}\n";
echo "line5:{${$arr['arr3']}[1]}\n";
echo "line6:{${beers::softdrink}}\n";
echo "line7:{${beers::$ale}}\n";

字符串轉(zhuǎn)換

PHP 語(yǔ)言比 Python 簡(jiǎn)單的另外一個(gè)原因就是類型的隱式轉(zhuǎn)換笤喳,會(huì)簡(jiǎn)化很多操作为居,這里通過(guò)字符串轉(zhuǎn)換來(lái)說(shuō)明。

字符串類型強(qiáng)制轉(zhuǎn)換

$var = 10 ;
$dvar = (string)$var ;
echo $dvar . "_" . gettype($dvar);

strval()函數(shù)是獲取變量的字符串值:

$var = 10.2 ;
$dvar = strval($var) ;
echo gettype($var) . "_" . $dvar . "_" . gettype($dvar);

settype()函數(shù)是設(shè)置變量的類型:

$str = "10hello";
settype($str, "integer");
echo $str ;

在強(qiáng)制類型轉(zhuǎn)換過(guò)程中杀狡,將其他類型的值轉(zhuǎn)換為字符串的時(shí)候會(huì)遵循一定的規(guī)則蒙畴,比如一個(gè)布爾值 boolean 的 TRUE 被轉(zhuǎn)換成 string 的 “1”。相關(guān)規(guī)則最好還是理解下呜象。

自動(dòng)類型轉(zhuǎn)換

上面的二個(gè)轉(zhuǎn)換屬于顯示轉(zhuǎn)換忍抽,而更要關(guān)注的是自動(dòng)類型轉(zhuǎn)換八孝,
在一個(gè)需要字符串的表達(dá)式中,會(huì)自動(dòng)轉(zhuǎn)換為類型鸠项,具體見(jiàn)例子:

$bool = true;
$str = 10 + "hello"
echo $bool . "_" . $str ;

PHP 字符串的本質(zhì)

引用 PHP 文檔的解釋:

PHP 中的 string 的實(shí)現(xiàn)方式是一個(gè)由字節(jié)組成的數(shù)組再加上一個(gè)整數(shù)指明緩沖區(qū)長(zhǎng)度干跛。并無(wú)如何將字節(jié)轉(zhuǎn)換成字符的信息,由程序員來(lái)決定祟绊。字符串由什么值構(gòu)成沒(méi)有限制楼入,包括值為 0 的字節(jié)可以出現(xiàn)在字符串的任何位置。

PHP并不特別指明字符串的編碼牧抽,那字符串到底是怎樣編碼的呢嘉熊,這取決于程序員。字符串會(huì)按照 PHP 文件的編碼來(lái)對(duì)字符串進(jìn)行編碼扬舒。比如你的文件編碼是 GBK阐肤,那么你代碼內(nèi)容都是 GBK 的。

補(bǔ)充二進(jìn)制安全這個(gè)概念讲坎,其值為 0 (NULL)的字節(jié)可以處于字符串任何位置孕惜,而 PHP 的部分非二進(jìn)制函數(shù)底層是調(diào)用的 C 函數(shù),會(huì)把 NULL 后面的字符忽略晨炕。

只要 PHP 的文件編碼是能兼容 ASCII 的衫画,那么字符串操作就可以很好的被處理。但是字符串操作本質(zhì)上還是 Native 的(不管文件編碼是什么)瓮栗,所以在使用的時(shí)候需要注意:

  • 某些函數(shù)假定字符串是以單字節(jié)編碼的削罩,但并不需要將字節(jié)解釋為特定的字符。比如 sbustr() 函數(shù)费奸。
  • 很多函數(shù)是需要顯示的傳遞編碼參數(shù)弥激,不然會(huì)從 PHP.INI 文件中獲取默認(rèn)值,比如 htmlentities() 函數(shù)愿阐。
  • 還有一些函數(shù)和本地區(qū)域有關(guān)微服,這些函數(shù)也只能是單字節(jié)操作的。

一般情況下换况,雖然 PHP 內(nèi)部不支持 Unicode 字符,但是支持 UTF-8 編碼盗蟆,絕大部分情況下不會(huì)有什么問(wèn)題戈二,但是下列的情況可能就處理不了了:

  • 非 UTF-8 編碼字符串如何進(jìn)行轉(zhuǎn)換
  • 一個(gè) UTF-8 編碼的網(wǎng)頁(yè),但是用戶在提交表單的時(shí)候喳资,可能使用 GBK 的編碼(不遵守 meta tag)
  • 一個(gè) UTF-8 編碼的 PHP 文件觉吭,使用 strlen("中國(guó)") 返回的是 6,而不是實(shí)際的字符數(shù)(2)

那么如何解決該問(wèn)題呢仆邓? PHP 提供了 mbstring 擴(kuò)展 鲜滩!

多字節(jié)字符串

mbstring 擴(kuò)展默認(rèn)不是打開(kāi)的伴鳖,安裝的時(shí)候需要 --enable-mbstring。

我們首先看看 PHP.INI 中對(duì)于 mbstring 指令的配置徙硅,花了好久才逐步明白榜聂。

  • mbstring.language 這個(gè)參數(shù)我就理解為 UTF-8 了
  • mbstring.internal_encoding 這個(gè)編碼和 PHP 文件編碼沒(méi)有關(guān)系,只是在大部分 mbstring 函數(shù)里面需要指定待處理字符串的編碼嗓蘑,假如不顯示指定须肆,默認(rèn)就獲取該參數(shù)的值,該參數(shù)的值在高版本 PHP 中用 default_charset 參數(shù)代替了桩皿。
  • mbstring.http_input 該參數(shù)指定 HTTP input 的默認(rèn)編碼(不包含 GET 參數(shù))豌汇。一般和 HTML 頁(yè)面的編碼保持一致,該參數(shù)的值用 default_charset 參數(shù)代替泄隔。
  • mbstring.http_output 該參數(shù)誤導(dǎo)我了拒贱,HTTP output 是什么,PHP 輸出不就是頁(yè)面佛嬉,怎么會(huì)有這概念逻澳?
  • mbstring.encoding_translation,這個(gè)參數(shù)重點(diǎn)說(shuō)下巷燥,默認(rèn)是關(guān)閉的赡盘,假如打開(kāi),PHP 會(huì)對(duì) POST 變量和上傳文件的名稱自動(dòng)轉(zhuǎn)換編碼為 mbstring.internal_encoding 指定的值缰揪,不過(guò)我沒(méi)有試驗(yàn)過(guò)陨享,大家可以上傳一個(gè)中文名的文件試驗(yàn)下。建議關(guān)閉钝腺,讓程序員來(lái)處理相關(guān)問(wèn)題抛姑。

后面看看 mbstring 擴(kuò)展的一些函數(shù):

  • mb_http_input():檢測(cè) HTTP input 字符編碼,覺(jué)得對(duì)于文件上傳的文件名有必要處理艳狐。
  • mb_convert_encoding():比較常用的函數(shù)定硝,注意第三個(gè)參數(shù)。
  • mb_detect_order():設(shè)置/獲取字符編碼的檢測(cè)順序毫目。
  • mb_list_encodings():返回系統(tǒng)支持的編碼列表蔬啡。

重點(diǎn)說(shuō)明下:PHP 文件支持的編碼有一定要,要兼容 ASCII镀虐。

但是不要使用 BIG-5 作為 PHP 文件編碼箱蟆,尤其字符串以 identifiers 或 literals 形式出現(xiàn),假如 PHP 文件編碼一定要是 BIG-5刮便,那么對(duì)于輸入輸出的內(nèi)容盡量轉(zhuǎn)換為 UTF-8空猜。

Zend Multibyte

最后說(shuō)下 Zend Multibyte 這個(gè)概念,理解的不是特別深刻,首先不要和 mbstring 擴(kuò)展混在一塊辈毯。 Zend Multibyte 模式默認(rèn)是關(guān)閉的坝疼,可以通過(guò) zend.multibyte 指令打開(kāi)。然后通過(guò) declare() 函數(shù)來(lái)指定 PHP 解析器的編碼谆沃。

那這個(gè)指令出現(xiàn)的意義是什么钝凶?上面說(shuō)過(guò) PHP 文件的編碼需要是兼容 ASCII 的,那么類似于 BIG-5 這樣的非兼容 ASCII 編碼怎么辦管毙,可以通過(guò)這個(gè)指令來(lái)操作腿椎,當(dāng) PHP 解析器讀取 mbstring.script_encoding 編碼并用該編碼來(lái)解析 PHP 文件。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夭咬,一起剝皮案震驚了整個(gè)濱河市啃炸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卓舵,老刑警劉巖南用,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異掏湾,居然都是意外死亡裹虫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門融击,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)筑公,“玉大人,你說(shuō)我怎么就攤上這事尊浪∠宦牛” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拇涤,是天一觀的道長(zhǎng)捣作。 經(jīng)常有香客問(wèn)我,道長(zhǎng)鹅士,這世上最難降的妖魔是什么券躁? 我笑而不...
    開(kāi)封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮掉盅,結(jié)果婚禮上也拜,老公的妹妹穿的比我還像新娘。我一直安慰自己趾痘,他們只是感情好慢哈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著扼脐,像睡著了一般岸军。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瓦侮,一...
    開(kāi)封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天艰赞,我揣著相機(jī)與錄音,去河邊找鬼肚吏。 笑死方妖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罚攀。 我是一名探鬼主播党觅,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼斋泄!你這毒婦竟也來(lái)了杯瞻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤炫掐,失蹤者是張志新(化名)和其女友劉穎魁莉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體募胃,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旗唁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痹束。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片检疫。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖祷嘶,靈堂內(nèi)的尸體忽然破棺而出屎媳,到底是詐尸還是另有隱情,我是刑警寧澤抹蚀,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布剿牺,位于F島的核電站,受9級(jí)特大地震影響环壤,放射性物質(zhì)發(fā)生泄漏晒来。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一郑现、第九天 我趴在偏房一處隱蔽的房頂上張望湃崩。 院中可真熱鬧,春花似錦接箫、人聲如沸攒读。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)薄扁。三九已至剪返,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邓梅,已是汗流浹背脱盲。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留日缨,地道東北人钱反。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像匣距,于是被迫代替她去往敵國(guó)和親面哥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容