## String 字符串(標量 )
一個字符串 string 就是由一系列的字符組成,其中每個字符等同于一個字節。這意味著 PHP 只能支持 256 的字符集,因此不支持 Unicode 。
> **Note**: string最大可以達到 2GB。
### 語法
一個字符串可以用 4 種方式表達:
* 單引號
* 雙引號
* heredoc 語法結構
* nowdoc 語法結構
#### 單引號
定義一個字符串的最簡單的方法是用單引號把它包圍起來(字符 *'*)。
要表達一個單引號自身,需在它的前面加個反斜線(*\\*)來轉義。要表達一個反斜線自身,則用兩個反斜線(*\\\\*)。其它任何方式的反斜線都會被當成反斜線本身:也就是說如果想使用其它轉義序列例如 *\\r* 或者 *\\n*,并不代表任何特殊含義,就單純是這兩個字符本身。
> **Note**: 不像雙引號和 heredoc 語法結構,在單引號字符串中的變量和特殊字符的轉義序列將*不會*被替換。
```
<?php
echo?'this?is?a?simple?string';
//?可以錄入多行
echo?'You?can?also?have?embedded?newlines?in?
strings?this?way?as?it?is
okay?to?do';
//?輸出:?Arnold?once?said:?"I'll?be?back"
echo?'Arnold?once?said:?"I\'ll?be?back"';
//?輸出:?You?deleted?C:\*.*?
echo?'You?deleted?C:\\*.*?';
//?輸出:?You?deleted?C:\*.*?
echo?'You?deleted?C:\*.*?';
//?輸出:?This?will?not?expand:?\n?a?newline
echo?'This?will?not?expand:?\n?a?newline';
//?輸出:?Variables?do?not?$expand?$either
echo?'Variables?do?not?$expand?$either';
?>
```
#### 雙引號
如果字符串是包圍在雙引號(")中, PHP 將對一些特殊的字符進行解析:
**轉義字符**
| 序列 | 含義 |
| --- | --- |
| | |
| \\n | 換行(ASCII 字符集中的 LF 或 0x0A (10)) |
| \\r | 回車(ASCII 字符集中的 CR 或 0x0D (13)) |
| \\t | 水平制表符(ASCII 字符集中的 HT 或 0x09 (9)) |
| \\v | 垂直制表符(ASCII 字符集中的 VT 或 0x0B (11))(自 PHP 5.2.5 起) |
| \\e | Escape(ASCII 字符集中的 ESC 或 0x1B (27))(自 PHP 5.4.0 起) |
| \\f | 換頁(ASCII 字符集中的 FF 或 0x0C (12))(自 PHP 5.2.5 起) |
| \\ | 反斜線 |
| $ | 美元標記 |
| " | 雙引號 |
| \[0-7\]{1,3} | 符合該正則表達式序列的是一個以八進制方式來表達的字符 |
| \\x\[0-9A-Fa-f\]{1,2} | 符合該正則表達式序列的是一個以十六進制方式來表達的字符 |
和單引號字符串一樣,轉義任何其它字符都會導致反斜線被顯示出來。PHP 5.1.1 以前,*\\{$var}* 中的反斜線還不會被顯示出來。
用雙引號定義的字符串最重要的特征是變量會被解析
#### Heredoc 結構
第三種表達字符串的方法是用 heredoc 句法結構:*<<<*。在該運算符之后要提供一個標識符,然后換行。接下來是字符串 string本身,最后要用前面定義的標識符作為結束標志。
結束時所引用的標識符*必須*在該行的第一列,而且,標識符的命名也要像其它標簽一樣遵守 PHP 的規則:只能包含字母、數字和下劃線,并且必須以字母和下劃線作為開頭。
```
<?php
$str?=?<<<EOD
Example?of?string
spanning?multiple?lines
using?heredoc?syntax.
EOD;
echo $str;
```
**heredoc 結構類似于雙引號字符串,它跟雙引號的特征一樣,變量會被解析**
**Warning**
要注意的是結束標識符這行除了*可能*有一個分號(*;*)外,絕對不能包含其它字符。這意味著標識符*不能縮進*,分號的前后也不能有任何空白或制表符。更重要的是結束標識符的前面必須是個被本地操作系統認可的換行,比如在 UNIX 和 Mac OS X 系統中是 *\\n*,而結束定界符(可能其后有個分號)之后也必須緊跟一個換行。
如果不遵守該規則導致結束標識不“干凈”,PHP 將認為它不是結束標識符而繼續尋找。如果在文件結束前也沒有找到一個正確的結束標識符,PHP 將會在最后一行產生一個解析錯誤。
Heredocs 結構不能用來初始化類的屬性。自 PHP 5.3 起,此限制僅對 heredoc 包含變量時有效。
#### Nowdoc 結構
Nowdoc 結構是類似于單引號字符串的,這種結構很適合用于嵌入 PHP 代碼或其它大段文本而無需對其中的特殊字符進行轉義。
一個 nowdoc 結構也用和 heredocs 結構一樣的標記 *<<<*, 但是跟在后面的標識符要用單引號括起來,即 *<<<'EOT'*。Heredoc 結構的所有規則也同樣適用于 nowdoc 結構,尤其是結束標識符的規則。
```
<?php
$str?=?<<<'EOD'
Example?of?string
spanning?multiple?lines
using?nowdoc?syntax.
EOD;
```
> **Note**:
> 不象 heredoc 結構,nowdoc 結構可以用在任意的靜態數據環境中,最典型的示例是用來初始化類的屬性或常量:
#### 變量解析
**Example # 靜態數據的示例**
```
<?php
class?foo?{
????public?$bar?=?<<<'EOT'
bar
EOT;
}
?>
```
當字符串用雙引號或 heredoc 結構定義時,其中的變量將會被解析。
這里共有兩種語法規則:一種簡單規則,一種復雜規則。簡單的語法規則是最常用和最方便的,它可以用最少的代碼在一個 string中嵌入一個變量,一個 array的值,或一個 object的屬性。
復雜規則語法的顯著標記是用花括號包圍的表達式。
##### 簡單語法
當 PHP 解析器遇到一個美元符號(*$*)時,它會和其它很多解析器一樣,去組合盡量多的標識以形成一個合法的變量名。可以用花括號來明確變量名的界線。
**Example #8 簡單語法示例**
```
<?php
$juice?=?"apple";
echo?"He?drank?some?$juice?juice.".PHP_EOL;
```
類似的,一個 array 索引或一個object 屬性也可被解析。數組索引要用方括號(*\]*)來表示索引結束的邊際,對象屬性則是和上述的變量規則相同。
```
<?php
$juices?=?array("apple",?"orange",?"koolaid1"?=>?"purple");
echo?"He?drank?some?$juices[0]?juice.".PHP_EOL;
```
##### 復雜(花括號)語法
復雜語法不是因為其語法復雜而得名,而是因為它可以使用復雜的表達式。
任何具有 string表達的標量變量,數組單元或對象屬性都可使用此語法。只需簡單地像在 string以外的地方那樣寫出表達式,然后用花括號 *{* 和 *}* 把它括起來即可。由于 *{* 無法被轉義,只有 *$* 緊挨著 *{* 時才會被識別。可以用 *{\\$* 來表達 *{$*。
```
<?php
//?顯示所有錯誤
error_reporting(E_ALL);
$great?=?'fantastic';
//?無效,輸出:?This?is?{?fantastic}
echo?"This?is?{?$great}";
//?有效,輸出:?This?is?fantastic
echo?"This?is?{$great}";
//?有效
echo?"This?square?is?{$square->width}00?centimeters?broad.";?
//?有效,只有通過花括號語法才能正確解析帶引號的鍵名
echo?"This?works:?{$arr['key']}";
//?有效
echo?"This?works:?{$arr[4][3]}";
//?這是錯誤的表達式,因為就象?$foo[bar]?的格式在字符串以外也是錯的一樣。
//?換句話說,只有在?PHP?能找到常量?foo?的前提下才會正常工作;這里會產生一個
//?E_NOTICE?(undefined?constant)?級別的錯誤。
echo?"This?is?wrong:?{$arr[foo][3]}";?
//?有效,當在字符串中使用多重數組時,一定要用括號將它括起來
echo?"This?works:?{$arr['foo'][3]}";
//?有效
echo?"This?works:?"?.?$arr['foo'][3];
echo?"This?works?too:?{$obj->values[3]->name}";
echo?"This?is?the?value?of?the?var?named?$name:?{${$name}}";
echo?"This?is?the?value?of?the?var?named?by?the?return?value?of?getName():?{${getName()}}";
echo?"This?is?the?value?of?the?var?named?by?the?return?value?of?\$object->getName():?{${$object->getName()}}";
//?無效,輸出:?This?is?the?return?value?of?getName():?{getName()}
echo?"This?is?the?return?value?of?getName():?{getName()}";
?>
```
也可以在字符串中用此語法通過變量來調用類的屬性。
```
<?php
class?foo?{
????var?$bar?=?'I?am?bar.';
}
$foo?=?new?foo();
$bar?=?'bar';
$baz?=?array('foo',?'bar',?'baz',?'quux');
echo?"{$foo->$bar}\n";
echo?"{$foo->{$baz[1]}}\n";
?>
```
> **Note**:
> 函數、方法、靜態類變量和類常量只有在 PHP 5 以后才可在 *{$}* 中使用。然而,只有在該字符串被定義的命名空間中才可以將其值作為變量名來訪問。只單一使用花括號 (*{}*) 無法處理從函數或方法的返回值或者類常量以及類靜態變量的值。
#### 存取和修改字符串中的字符
string中的 字符串可以通過一個從0開始的下標,用類似array結構中的 方括號包含對應的數字來訪問和修改,比如$str\[42\]。可以把string當成字符組成的array。
> string也可用花括號訪問,比如$str{42}。
**Warning**用超出字符串長度的下標寫入將會拉長該字符串并以空格填充。非整數類型下標會被轉換成整數。非法下標類型會產生一個 \*\*`E_NOTICE**` 級別錯誤。用負數下標寫入字符串時會產生一個 \*\*`E_NOTICE**` 級別錯誤,用負數下標讀取字符串時返回空字符串。寫入時只用到了賦值字符串的第一個字符。用空字符串賦值則賦給的值是 NULL 字符。
> **Note**:
> 用 *\[\]* 或 *{}* 訪問任何其它類型(不包括數組或具有相應接口的對象實現)的變量只會無聲地返回 \*\*`NULL**`。
> **Note**:
> PHP 5.5 增加了直接在字符串原型中用 *\[\]* 或 *{}* 訪問字符的支持。
### 有用的函數和運算符
字符串可以用 '.'(點)運算符連接起來,注意 '+'(加號)運算符*沒有*這個功能。
### 轉換成字符串
一個值可以通過在其前面加上 *(string)* 或用 [strval()](http://php.net/manual/zh/function.strval.php) 函數來轉變成字符串。在一個需要字符串的表達式中,會自動轉換為 [string](http://php.net/manual/zh/language.types.string.php)。比如在使用函數 [echo](http://php.net/manual/zh/function.echo.php) 或 [print](http://php.net/manual/zh/function.print.php) 時,或在一個變量和一個 [string](http://php.net/manual/zh/language.types.string.php) 進行比較時,就會發生這種轉換。[類型](http://php.net/manual/zh/language.types.php)和[類型轉換](http://php.net/manual/zh/language.types.type-juggling.php)可以更好的解釋下面的事情,也可參考函數 [settype()](http://php.net/manual/zh/function.settype.php)。
一個布爾值 [boolean](http://php.net/manual/zh/language.types.boolean.php) 的 \*\*`TRUE**` 被轉換成 [string](http://php.net/manual/zh/language.types.string.php) 的 *"1"*。[Boolean](http://php.net/manual/zh/language.types.boolean.php) 的 \*\*`FALSE**` 被轉換成 *""*(空字符串)。這種轉換可以在 [boolean](http://php.net/manual/zh/language.types.boolean.php) 和 [string](http://php.net/manual/zh/language.types.string.php) 之間相互進行。
一個整數 [integer](http://php.net/manual/zh/language.types.integer.php) 或浮點數 [float](http://php.net/manual/zh/language.types.float.php) 被轉換為數字的字面樣式的 [string](http://php.net/manual/zh/language.types.string.php)(包括 [float](http://php.net/manual/zh/language.types.float.php) 中的指數部分)。使用指數計數法的浮點數(*4.1E+6*)也可轉換。
數組 [array](http://php.net/manual/zh/language.types.array.php) 總是轉換成字符串 *"Array"*,因此,[echo](http://php.net/manual/zh/function.echo.php) 和 [print](http://php.net/manual/zh/function.print.php) 無法顯示出該數組的內容。要顯示某個單元,可以用 *echo $arr\['foo'\]* 這種結構。要顯示整個數組內容見下文。
在 PHP 4 中對象 [object](http://php.net/manual/zh/language.types.object.php) 總是被轉換成字符串 *"Object"*,如果為了調試原因需要打印出對象的值,請繼續閱讀下文。為了得到對象的類的名稱,可以用 [get\_class()](http://php.net/manual/zh/function.get-class.php) 函數。自 PHP 5 起,適當時可以用 [\_\_toString](http://php.net/manual/zh/language.oop5.magic.php) 方法。
資源 [resource](http://php.net/manual/zh/language.types.resource.php) 總會被轉變成 *"Resource id #1"* 這種結構的字符串,其中的 *1* 是 PHP 在運行時分配給該 [resource](http://php.net/manual/zh/language.types.resource.php) 的唯一值。不要依賴此結構,可能會有變更。要得到一個 [resource](http://php.net/manual/zh/language.types.resource.php) 的類型,可以用函數 [get\_resource\_type()](http://php.net/manual/zh/function.get-resource-type.php)。
\*\*`NULL**` 總是被轉變成空字符串。
如上面所說的,直接把 [array](http://php.net/manual/zh/language.types.array.php),[object](http://php.net/manual/zh/language.types.object.php) 或 [resource](http://php.net/manual/zh/language.types.resource.php) 轉換成 [string](http://php.net/manual/zh/language.types.string.php) 不會得到除了其類型之外的任何有用信息。可以使用函數 [print\_r()](http://php.net/manual/zh/function.print-r.php) 和 [var\_dump()](http://php.net/manual/zh/function.var-dump.php) 列出這些類型的內容。
大部分的 PHP 值可以轉變成 [string](http://php.net/manual/zh/language.types.string.php) 來永久保存,這被稱作串行化,可以用函數 [serialize()](http://php.net/manual/zh/function.serialize.php) 來實現。如果 PHP 引擎設定支持 [WDDX](http://php.net/manual/zh/ref.wddx.php),PHP 值也可被串行化為格式良好的 XML 文本。
### 字符串轉換為數值
當一個字符串被當作一個數值來取值,其結果和類型如下:
如果該字符串沒有包含 '.','e' 或 'E' 并且其數字值在整型的范圍之內(由 \*\*`PHP_INT_MAX**` 所定義),該字符串將被當成 [integer](http://php.net/manual/zh/language.types.integer.php) 來取值。其它所有情況下都被作為 [float](http://php.net/manual/zh/language.types.float.php) 來取值。
該字符串的開始部分決定了它的值。如果該字符串以合法的數值開始,則使用該數值。否則其值為 0(零)。合法數值由可選的正負號,后面跟著一個或多個數字(可能有小數點),再跟著可選的指數部分。指數部分由 'e' 或 'E' 后面跟著一個或多個數字構成。
```
<?php
$foo?=?1?+?"10.5";????????????????//?$foo?is?float?(11.5)
$foo?=?1?+?"-1.3e3";??????????????//?$foo?is?float?(-1299)
$foo?=?1?+?"bob-1.3e3";???????????//?$foo?is?integer?(1)
$foo?=?1?+?"bob3";????????????????//?$foo?is?integer?(1)
$foo?=?1?+?"10?Small?Pigs";???????//?$foo?is?integer?(11)
$foo?=?4?+?"10.2?Little?Piggies";?//?$foo?is?float?(14.2)
$foo?=?"10.0?pigs?"?+?1;??????????//?$foo?is?float?(11)
$foo?=?"10.0?pigs?"?+?1.0;????????//?$foo?is?float?(11)?????
?>
```
### 字符串類型詳解
PHP中的string的實現方式是一個由字節組成的數組再加上一個整數指明緩沖區長度。并無如何將字節轉換成字符的 信息,由程序員來決定。字符串由什么值來組合并無限制;特別的,其值為0("NUL bytes")的字節可以處于字符串任何位置(不過有幾個函數,在本手冊中被稱為非“二進制安全”的,也許會把NUL字節之后的數據全部都忽略)。
字符串類型的此特性解釋了為什么 PHP 中沒有單獨的“byte”類型 - 已經用字符串來代替了。返回非文本值的函數 - 例如從網絡套接字讀取的任意數據 - 仍會返回字符串。
由于 PHP 并不特別指明字符串的編碼,那字符串到底是怎樣編碼的呢?例如字符串 *"á"* 到底是等于 *"\\xE1"*(ISO-8859-1),*"\\xC3\\xA1"*(UTF-8,C form),*"\\x61\\xCC\\x81"*(UTF-8,D form)還是任何其它可能的表達呢?答案是字符串會被按照該腳本文件相同的編碼方式來編碼。因此如果一個腳本的編碼是 ISO-8859-1,則其中的字符串也會被編碼為 ISO-8859-1,以此類推。不過這并不適用于激活了 Zend Multibyte 時;此時腳本可以是以任何方式編碼的(明確指定或被自動檢測)然后被轉換為某種內部編碼,然后字符串將被用此方式編碼。注意腳本的編碼有一些約束(如果激活了 Zend Multibyte 則是其內部編碼)- 這意味著此編碼應該是 ASCII 的兼容超集,例如 UTF-8 或 ISO-8859-1。不過要注意,依賴狀態的編碼其中相同的字節值可以用于首字母和非首字母而轉換狀態,這可能會造成問題。
當然了,要做到有用,操作文本的函數必須假定字符串是如何編碼的。不幸的是,PHP 關于此的函數有很多變種:
* 某些函數假定字符串是以單字節編碼的,但并不需要將字節解釋為特定的字符。例如 [substr()](http://php.net/manual/zh/function.substr.php),[strpos()](http://php.net/manual/zh/function.strpos.php),[strlen()](http://php.net/manual/zh/function.strlen.php) 和 [strcmp()](http://php.net/manual/zh/function.strcmp.php)。理解這些函數的另一種方法是它們作用于內存緩沖區,即按照字節和字節下標操作。
* 某些函數被傳遞入了字符串的編碼方式,也可能會假定默認無此信息。例如 [htmlentities()](http://php.net/manual/zh/function.htmlentities.php) 和 [mbstring](http://php.net/manual/zh/book.mbstring.php) 擴展中的大部分函數。
* 其它函數使用了當前區域(見 [setlocale()](http://php.net/manual/zh/function.setlocale.php)),但是逐字節操作。例如 [strcasecmp()](http://php.net/manual/zh/function.strcasecmp.php),[strtoupper()](http://php.net/manual/zh/function.strtoupper.php) 和 [ucfirst()](http://php.net/manual/zh/function.ucfirst.php)。這意味著這些函數只能用于單字節編碼,而且編碼要與區域匹配。例如 *strtoupper("á")* 在區域設定正確并且 *á* 是單字節編碼時會返回 *"á"*。如果是用 UTF-8 編碼則不會返回正確結果,其結果根據當前區域有可能返回損壞的值。
* 最后一些函數會假定字符串是使用某特定編碼的,通常是 UTF-8。[intl](http://php.net/manual/zh/book.intl.php) 擴展和 [PCRE](http://php.net/manual/zh/book.pcre.php)(上例中僅在使用了 *u* 修飾符時)擴展中的大部分函數都是這樣。盡管這是由于其特殊用途,[utf8\_decode()](http://php.net/manual/zh/function.utf8-decode.php) 會假定 UTF-8 編碼而 [utf8\_encode()](http://php.net/manual/zh/function.utf8-encode.php) 會假定 ISO-8859-1 編碼。
最后,要書寫能夠正確使用 Unicode 的程序依賴于很小心地避免那些可能會損壞數據的函數。要使用來自于 [intl](http://php.net/manual/zh/book.intl.php) 和 [mbstring](http://php.net/manual/zh/book.mbstring.php) 擴展的函數。不過使用能處理 Unicode 編碼的函數只是個開始。不管用何種語言提供的函數,最基本的還是了解 Unicode 規格。例如一個程序如果假定只有大寫和小寫,那可是大錯特錯。
- 序言
- 簡介
- PHP是什么?
- PHP能做什么?
- 基本語法
- 類型
- boolean(布爾型)
- integer(整型)
- float(浮點型)
- string(字符串)
- array(數組)
- object(對象)
- callable(可調用)
- resource(資源)
- NULL(無類型)
- 偽類型
- 類型轉換的判別
- 變量
- 基礎
- 預定義變量
- 變量范圍
- 可變變量
- 來自PHP之外的變量
- 常量
- 語法
- 魔術常量
- 表達式
- 運算符
- 運算符優先級
- 算術運算符
- 賦值運算符
- 位運算符
- 比較運算符
- 錯誤控制運算符
- 執行運算符
- 遞增/遞減運算符
- 邏輯運算符
- 字符串運算符
- 數組運算符
- 類型運算符
- 流程控制
- if
- else
- elseif/else if
- 流程控制的替代語法
- while
- do-whille
- for
- foreach
- break
- continue
- switch
- declare
- return
- require
- include
- require_once
- include_once
- goto
- 函數
- 用戶自定義函數
- 函數的參數
- 返回值
- 可變函數
- 內部 (內置)函數
- 匿名函數
- 類與對象
- 簡介
- 基本概念
- 屬性
- 類的自動加載
- 構造函數
- 訪問控制(可見性)