最近看了不少編碼方面的文章,所以分二篇博文說下“PHP、字符串、編碼、UTF-8”相關知識,本篇博文是上半部分,分為四大塊內容,分別是「字串的定義與使用」、「字串轉換」、「PHP 字串的本質」、「多位元組字串」。上半部比較基礎、。
PHP 中能夠透過四種方法設定字串:
單引號字串
。字串沒有變數解析功能和特殊字元轉義功能。例如$str='hellonworld',其中的n並沒有換行功能。
雙引號字串
雙引號字串具備單引號字串沒有的變數解析功能和特殊字元轉義功能。
個人對於十六進制和八進制的字串特殊轉義很感興趣,特別補充:
\[0-7]{1,3} #八进制表达方式 \x[0-9A-Fa-f]{1,2} #十六进制表达方式
heredoc
這種表達式類似於Python 中包含多行的字串,就能夠定義字串。其語法定義很嚴格,使用起來需要注意。
$str=<<<EOD hello\n world EOD;
Nowdoc
Nowdoc類似於單引號字串,不會解析變數。比較適合定義一大段文字且無需對其中的特殊字元進行轉義。
變數解析
PHP字串最強大的部分就是變數解析,可以在運行時根據上下文解析變數(這才是解釋型語言),可以產生很多妙用。
簡單的變數解析就是在字串中可以包含“變數”,“數組”,“物件屬性”,複雜的語法規則就是使用{}符號來進行操作(組成一個表達式)。
透過一個例子看看變數解析的強大之處
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";
PHP 語言比 Python 簡單的另一個原因就是類型的隱式轉換,會簡化很多操作,這裡透過字串轉換來說明。
字串類型強制轉換
$var = 10 ; $dvar = (string)$var ; echo $dvar . "_" . gettype($dvar);
strval()函數是取得變數的字串值:
$var = 10.2 ; $dvar = strval($var) ; echo gettype($var) . "_" . $dvar . "_" . gettype($dvar);
settype()函數是設定變數的的值轉換成字串的時候會遵循一定的規則,例如一個布林值boolean 的TRUE 被轉換成string 的「1」。相關規則最好還是理解下。
自動型別轉換上面的二個轉換屬於顯示轉換,而更要關注的是自動型別轉換,在一個需要字串的表達式中,會自動轉換為型,具體見例子:
$str = "10hello"; settype($str, "integer"); echo $str ;
PHP 字串的本質
PHP並不特別指明字串的編碼,那字串到底是怎麼編碼的呢,這取決於程式設計師。字串會依照 PHP 檔案的編碼來對字串進行編碼。例如你的檔案編碼是 GBK,那你程式碼內容都是 GBK的。
補充二進位安全這個概念,其值為 0 (NULL)的位元組可以處於字串任何位置,而 PHP 的部分非二進位函數底層是呼叫的 C 函數,會把 NULL 後面的字元忽略。
只要 PHP 的檔案編碼是能相容 ASCII 的,那麼字串操作就可以很好的被處理。但是字串操作本質上還是Native 的(不管檔案編碼是什麼),所以在使用的時候需要注意:
mbstring 擴充預設不是開啟的,安裝的時候需要 --enable-mbstring。
我們先看看 PHP.INI 中對於 mbstring 指令的配置,花了好久才逐步明白。
mbstring.language 這個參數我就理解為UTF-8 了
mbstring.internal_encoding 這個編碼和PHP 檔案編碼沒有關係,只是在大部分mbstring 函數裡面需要指定待處理字串的編碼,如不顯示指定,預設就取得該參數的值,該參數的值在高版本PHP 中以default_charset 參數取代了。
mbstring.http_input 此參數指定 HTTP input 的預設編碼(不包含 GET 參數)。一般和 HTML 頁面的編碼保持一致,該參數的值以 default_charset 參數取代。
mbstring.http_output 該參數誤導我了,HTTP output 是什麼,PHP 輸出不就是頁面,怎麼會有這概念?
mbstring.encoding_translation,這個參數重點說下,預設是關閉的,假如打開,PHP 會對POST 變數和上傳檔案的名稱自動轉換編碼為mbstring.internal_encoding 指定的值,不過大家我沒有試驗過,大家可以上傳一個中文名的檔案。建議關閉,讓程式設計師來處理相關問題。
後面看看 mbstring 擴充的一些函數:
mb_http_input():偵測 HTTP input 字元編碼,覺得對於上傳的檔案名稱有必要處理。
mb_convert_encoding():比較常用的函數,注意第三個參數。
mb_detect_order():設定/取得字元編碼的偵測順序。
mb_list_encodings():傳回系統支援的編碼清單。
重點說明下:PHP 檔案支援的編碼有一定要,要相容於 ASCII。
但不要使用 BIG-5 作為 PHP 檔案編碼,尤其字串以 identifiers 或 literals 形式出現,假如實在 PHP 檔案編碼要是 BIG-5,那麼對於輸入輸出的內容盡量轉換為 UTF-8。
最後說下 Zend Multibyte 這個概念,理解的不是特別深刻,首先不要和 mbstring 擴展混在一塊。 Zend Multibyte 模式預設是關閉的,可以透過 zend.multibyte 指令開啟。然後透過 declare() 函數來指定 PHP 解析器的編碼。
那這個指令出現的意義是什麼?上面說過PHP 檔案的編碼需要是相容ASCII 的,那麼類似於BIG-5 這樣的非相容ASCII 編碼怎麼辦,可以透過這個指令來操作,當PHP 解析器讀取mbstring.script_encoding 編碼並用該編碼來解析PHP 檔案。