PHP 開發工程師基礎篇 – PHP 字元串
字元串 (String)
字元串是一系列字元的集合。如 「abc」. 在 PHP 中,一個字元代表一個位元組,一個位元組 (Byte) 有 8 比特 (bit). PHP 僅支援 256 字符集,因此 PHP 本身不支援 Unicode 字符集.
This means that PHP only supports a 256-character set, and hence does not offer native Unicode support.
那麼 PHP 是如何做到支援 Unicode 字符集的,答案是在於 PHP 底層字元串實現中,PHP 的字元串是一個由位元組組成的數組再加上一個整數指明緩衝區長度。並沒有如何將位元組轉換字元的資訊。那麼字元串如何編碼和解碼,這些全部由使用者來決定編碼方式.
字元串會被按照該腳本文件相同的編碼方式來編碼。因此如果一個腳本的編碼是 ISO-8859-1,則其中的字元串也會被編碼為 ISO-8859-1,以此類推。不過這並不適用於激活了 Zend Multibyte 時;此時腳本可以是以任何方式編碼的(明確指定或被自動檢測)然後被轉換為某種內部編碼,然後字元串將被用此方式編碼存入由位元組組成的數組.
The answer is that string will be encoded in whatever fashion it is encoded in the script file. Thus, if the script is written in ISO-8859-1, the string will be encoded in ISO-8859-1 and so on. However, this does not apply if Zend Multibyte is enabled; in that case, the script may be written in an arbitrary encoding (which is explicitly declared or is detected) and then converted to a certain internal encoding, which is then the encoding that will be used for the string literals.
通過例子說明一下,比較易懂.
// unicode 字符集下 utf-8 編碼方式 $s = '嚴'; var_dump(strlen($s)); // 3 $len = strlen($s); // 3 /** * int(228) 對應二進位為 11100100 * int(184) 對應二進位為 10111000 * int(165) 對應二進位為 10100101 */ for ($i = 0; $i < $len; $i++) { var_dump(ord($s[$i])); }
「嚴」 這個字怎麼會是 3 個,而不是一個呢,由於 strlen 返回的是位元組數,而非字元數. PHP 底層字元串實現方式。是由位元組組成的數組的。因此可以得出 PHP 對於 「嚴」 在 utf-8 編碼方式的底層實現是由 3 個位元組組成數組,而這些位元組不超過 256 的值,這就是 PHP 編碼方式。而解碼則是通過文件編碼方式取對應位元組數目來找對應字面字元.
而這些數值代表什麼意思,則是 utf-8 的編碼方式了。嚴的Unicode 是 4E25(100111000100101),根據上表,可以發現 4E25 處在第三行的範圍內(0000 0800 – 0000 FFFF),因此嚴的 UTF-8 編碼需要三個位元組,即格式是 1110xxxx 10xxxxxx 10xxxxxx。然後,從嚴的最後一個二進位位開始,依次從後向前填入格式中的 x,多出的位補 0。這樣就得到了,嚴的 UTF-8 編碼是 11100100 10111000 10100101,轉換成十六進位就是 E4B8A5。
非二進位安全
字元串由什麼值來組成並無限制;特別的,其值為 0(「NUL bytes」)的位元組可以處於字元串任何位置 (不過有幾個函數,在本手冊中被稱為非 「二進位安全」 的,也許會把 NUL 位元組之後的數據全都忽略). 在 C 語言里字元串都以 \0 作為結束符,而 PHP 底層是由 C 語言編寫的,因此某些函數遇到 \0 的 會忽略之後位元組的,從而影響程式邏輯和結果.
$string1 = "Hello"; $string2 = "Hello\0World"; // 非二進位安全, \0 在 ascii 表是 NUL '\0' var_dump(strcoll($string1, $string2)); // 0 // 二進位安全 var_dump(strcmp($string1, $string2)); // -6
語法
- 單引號
- 雙引號
- heredoc 語法結構
- nowdoc 語法結構 (自 PHP 5.3.0 起)
單引號
定義一個字元串的最簡單的方法是用單引號把它包圍起來 (字元 ‘), 單引號無法解析變數和轉義字元,要表達單引號本身則在單引號前面加個反斜杠 (), 要表達反斜杠 () 則在反斜杠前加個反斜杠 ()
// this is string echo 'this is string'; // I'm your father echo 'I\'m your father'; // C:\*.*? echo 'C:\\*.*?';
雙引號
用雙引號 (“) 把字元包圍起來,PHP 雙引號會把特殊字元解釋以下轉義序列.
雙引號還有一個特點,就是會解析變數。變數解析有兩個解析語法,一個是簡單和一個複雜的.
- 簡單解析語法:
簡單的解析方式當 PHP 解析器遇到一個美元符號($)時,它會和其它很多解析器一樣,去組合盡量多的標識以形成一個合法的變數名。可用花括弧限制解析範圍.
$juice = 'apple'; $juices = 'apple\s'; // He drank some apple juice echo "He drank some $juice juice." . PHP_EOL; // He drank some apple\s juice echo "He drank some $juices juice" . PHP_EOL; // He drank some apples juice echo "He drank some {$juice}s juice" . PHP_EOL;
類似的,一個 array 索引或一個 object 屬性也可被解析。數組索引要用方括弧(])來表示索引結束的邊際,對象屬性則是和上述的變數規則相同。
- 複雜解析語法
這並不因為語法複雜而被稱為複雜,而是因為它允許使用複雜的表達式.
任何具有 string 表達的標量變數,數組單元或對象屬性都可使用此語法。只需簡單地像在 string 以外的地方那樣寫出表達式,然後用花括弧 {和} 把它括起來即可。由於 { 無法被轉義,只有 $ 緊挨著 { 時才會被識別。可以用 {$ 來表達 {$。
echo "This works too: {$obj->values[3]->name}"; echo "This works too: {$obj->values[3]->name}"; echo "This is the value of the var named by the return value of getName(): {${getName()}}";
Heredoc
第三種表達字元串的方法是用 heredoc 句法結構:<<<。在該運算符之後要提供一個標識符,然後換行。接下來是字元串 string 本身,最後要用前面定義的標識符作為結束標誌。
結束時所引用的標識符必須在該行的第一列,而且,標識符的命名也要像其它標籤一樣遵守 PHP 的規則:只能包含字母、數字和下劃線,並且必須以字母和下劃線作為開頭。
Heredoc 結構就象是沒有使用雙引號的雙引號字元串,這就是說在 heredoc 結構中單引號不用被轉義,但是上文中列出的轉義序列還可以使用
$str = <<<EOD Example of string spanning multiple lines using heredoc syntax. EOD; $juice = 'apple'; $str1 = <<<EOD He drank some $juice juice. EOD; // 運用在函數中 function foo() { static $bar = <<<LABEL Nothing in here... LABEL; } // 運用在類中 class foo { const BAR = <<<FOOBAR Constant example FOOBAR; public $baz = <<<FOOBAR Property example FOOBAR; }
Nowdoc
Nowdoc 結構很象 heredoc 結構,但是 nowdoc 中不進行解析操作。這種結構很適合用於嵌入 PHP 程式碼或其它大段文本而無需對其中的特殊字元進行轉義
一個 nowdoc 結構也用和 heredocs 結構一樣的標記 <<<, 但是跟在後面的標識符要用單引號括起來,即 <<<『EOT』。Heredoc 結構的所有規則也同樣適用於 nowdoc 結構,尤其是結束標識符的規則。
$str = <<<'EOD' Example of string spanning multiple lines using nowdoc syntax. EOD;
單引號比雙引號快?
在 PHP 7 之前,假如字元串沒有存在變數替換,單引號和雙引號幾乎一樣的。如果存在變數替換的時候是單引號比雙引號要快. PHP 7 之後,卻是不同,雙引號與單引號幾乎一樣性能.
$singleCode = 'this is single string'; $doubleCode = "this is single string"; echo $singleCode; echo $doubleCode;
第 0 到第 3 條 op line, 可以看出在沒有使用變數替換的情況下,雙引號的和單引號所產生的 Opcodes 是一樣的.
$var = 'String'; $single_quotes_var = 'This is a '.$var; $double_quotes_var = "This is a $var"; echo $single_quotes_var; echo $double_quotes_var;
第 1 到 2 條與第 4 到 5 條,Opcodes 條數是一樣的. PHP 7 把之前 INIT_STRING, ADD_STRING, ADD_VAR 的步驟優化成一條。優化成 FAST_CONCAT
存取和修改字元串中的字元
string 中的字元可以通過一個從 0 開始的下標,用類似 array 結構中的方括弧包含對應的數字來訪問和修改,比如 $str [42]。可以把 string 當成字元組成的 array. 也可以使用花括弧來訪問和修改 注意的是字元串操作最好針對單位元組編碼操作,因為字元串在 PHP 底層是位元組組成的數組,用花括弧 / 方括弧操作多位元組字元串很不安全.
在 PHP7.1.0, 還支援負字元串偏移量
用超出字元串長度的下標寫入將會拉長該字元串並以空格填充。非整數類型下標會被轉換成整數。
$str = 'This is a test.'; $first = $str[0]; $third = $str{2}; $last = $str[-1]; echo $first . PHP_EOL; // T echo $third . PHP_EOL; // i echo $last . PHP_EOL; // . $len = strlen($str); $str[$len+1] = 'a'; echo $str . PHP_EOL; // This is a test. a $str1 = "我"; echo ord($str1[0]); // 230
還有更多進階學習資料領取進階PHP月薪30k>>>架構師成長路線【影片、面試文檔免費獲取】