文件中並未提及,但 heredoc 結尾的分號實際上會被解釋為真正的分號,因此有時會導致語法錯誤。
這個可以正常運作
<?php
$foo = <<<END
abcd
END;
?>
這個不行
<?php
foo(<<<END
abcd
END;
);
// 語法錯誤,出現意外的 ';'
?>
沒有分號,它就能正常運作
<?php
foo(<<<END
abcd
END
);
?>
一個字串是一系列的字元,其中一個字元相當於一個位元組。這表示 PHP 只支援 256 個字元的字元集,因此不提供原生 Unicode 支援。請參閱字串類型的詳細資訊。
注意:在 32 位元版本中,字串的大小最大可達 2GB(最多 2147483647 個位元組)。
字串字面值可以用四種不同的方式指定:
指定字串最簡單的方法是用單引號(字元 '
)將其括起來。
若要指定一個字面單引號,請使用反斜線 (\
) 跳脫。若要指定一個字面反斜線,請將其重複 (\\
)。所有其他反斜線的實例都將被視為字面反斜線:這表示您可能習慣的其他跳脫序列,例如 \r
或 \n
,將會按原樣輸出,而不是具有任何特殊含義。
注意: 與 雙引號 和 heredoc 語法不同,在單引號 字串 中出現的 變數 和特殊字元的跳脫序列將*不會*被展開。
<?php
echo '這是一個簡單的字串';
echo '您也可以用這種方式在
字串中嵌入換行符號,因為這是
允許的';
// 輸出:Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"';
// 輸出:您刪除了 C:\*.*?
echo '您刪除了 C:\\*.*?';
// 輸出:您刪除了 C:\*.*?
echo '您刪除了 C:\*.*?';
// 輸出:這不會展開:\n 換行
echo '這不會展開:\n 換行';
// 輸出:變數也不會 $expand $either
echo '變數也不會 $expand $either';
?>
如果 字串 用雙引號 ("
) 括起來,PHP 會將以下跳脫序列解譯為特殊字元
序列 | 含義 |
---|---|
\n |
換行 (LF 或 ASCII 中的 0x0A (10)) |
\r |
歸位字元 (CR 或 ASCII 中的 0x0D (13)) |
\t |
水平定位字元 (HT 或 ASCII 中的 0x09 (9)) |
\v |
垂直定位字元 (VT 或 ASCII 中的 0x0B (11)) |
\e |
跳脫字元 (ESC 或 ASCII 中的 0x1B (27)) |
\f |
換頁 (FF 或 ASCII 中的 0x0C (12)) |
\\ |
反斜線 |
\$ |
錢字號 (美元符號) |
\" |
雙引號 |
\[0-7]{1,3} |
八進位:符合正規表達式 [0-7]{1,3} 的字元序列是以八進位表示法表示的字元(例如,"\101" === "A" ),它會無聲地溢位以適應一個位元組(例如,"\400" === "\000" ) |
\x[0-9A-Fa-f]{1,2} |
十六進位:符合正規表達式 [0-9A-Fa-f]{1,2} 的字元序列是以十六進位表示法表示的字元(例如,"\x41" === "A" ) |
\u{[0-9A-Fa-f]+} |
Unicode:符合正規表達式 [0-9A-Fa-f]+ 的字元序列是一個 Unicode 字碼點,它將以該字碼點的 UTF-8 表示形式輸出到字串中。序列中需要大括號。例如 "\u{41}" === "A" |
如同單引號 字串,跳脫任何其他字元將導致反斜線也被印出。
界定 字串 的第三種方法是 heredoc 語法:<<<
。在此運算子之後,會提供一個識別符號,然後是一個換行符號。接著是 字串 本身,然後再次使用相同的識別符號來關閉引號。
結尾識別符號可以用空格或 Tab 縮排,在這種情況下,文件字串中所有行的縮排都會被移除。在 PHP 7.3.0 之前,結尾識別符號*必須*從行的第一列開始。
此外,結尾識別符號必須遵循與 PHP 中任何其他標籤相同的命名規則:它只能包含英數字元和底線,並且必須以非數字字元或底線開頭。
範例 #1 自 PHP 7.3.0 起的基本 Heredoc 範例
<?php
// 無縮排
echo <<<END
a
b
c
\n
END;
// 4 個空格的縮排
echo <<<END
a
b
c
END;
以上範例在 PHP 7.3 中的輸出
a b c a b c
如果結尾識別符號的縮排比主體的任何一行都多,則會拋出 ParseError。
範例 #2 結尾識別符號的縮排不能比主體的任何一行都多
<?php
echo <<<END
a
b
c
END;
以上範例在 PHP 7.3 中的輸出
PHP Parse error: Invalid body indentation level (expecting an indentation level of at least 3) in example.php on line 4
如果結尾識別符號有縮排,也可以使用 Tab,但是,關於結尾識別符號的縮排和主體(直到結尾識別符號)的縮排,Tab 和空格*不得*混合使用。在任何這些情況下,都會拋出 ParseError。包含這些空白限制是因為混合使用 Tab 和空格進行縮排不利於程式碼的可讀性。
範例 #3 主體(空格)和結尾識別符號使用不同的縮排
<?php
// 以下所有程式碼皆無法運作。
// 主體(空格)和結尾標記(Tab)使用不同的縮排
{
echo <<<END
a
END;
}
// 在主體中混合使用空格和 Tab
{
echo <<<END
a
END;
}
// 在結尾標記中混合使用空格和 Tab
{
echo <<<END
a
END;
}
以上範例在 PHP 7.3 中的輸出
PHP Parse error: Invalid indentation - tabs and spaces cannot be mixed in example.php line 8
主體字串的結尾識別符號之後不需要分號或換行符號。例如,自 PHP 7.3.0 起,允許以下程式碼。
範例 #4 在結束識別符號後繼續表達式
<?php
$values = [<<<END
a
b
c
END, 'd e f'];
var_dump($values);
以上範例在 PHP 7.3 中的輸出
array(2) { [0] => string(11) "a b c" [1] => string(5) "d e f" }
如果結束識別符號位於一行的開頭,那麼無論它是否是另一個單字的一部分,它都可能被視為結束識別符號,並導致 ParseError。
範例 #5 字串主體中的結束識別符號容易造成 ParseError
<?php
$values = [<<<END
a
b
END ING
END, 'd e f'];
以上範例在 PHP 7.3 中的輸出
PHP Parse error: syntax error, unexpected identifier "ING", expecting "]" in example.php on line 6
為了避免這個問題,安全的做法是遵循一個簡單的規則:*不要選擇在文字主體中出現的字串作為結束識別符號*。
在 PHP 7.3.0 之前,需要注意的是,包含結束識別符號的行除了分號 (;
) 之外,不能包含任何其他字元。這尤其意味著識別符號*不能縮排*,並且分號前後不能有任何空格或 Tab 字元。同樣重要的是,結束識別符號之前的首個字元必須是本地作業系統定義的換行符號。在 UNIX 系統(包括 macOS)上,這是 \n
。結束分隔符號之後也必須跟著一個換行符號。
如果違反此規則且結束識別符號不「乾淨」,則它不會被視為結束識別符號,PHP 將繼續尋找結束識別符號。如果在目前檔案的結尾之前沒有找到正確的結束識別符號,則最後一行將會產生解析錯誤。
範例 #6 PHP 7.3.0 之前的無效範例
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
// 識別符號不能縮排
?>
範例 #7 即使在 PHP 7.3.0 之前也是有效的範例
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
?>
包含變數的 Heredoc 無法用於初始化類別屬性。
Heredoc 文字的行為就像雙引號括起來的 字串,只是沒有雙引號。這意味著 Heredoc 中的引號不需要跳脫,但上述跳脫碼仍然可以使用。變數會被展開,但在 Heredoc 中表達複雜變數時,必須像使用 字串一樣小心。
範例 #8 Heredoc 字串引號範例
<?php
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
/* 更複雜的例子,包含變數。 */
class foo
{
var $foo;
var $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>
以上範例會輸出
My name is "MyName". I am printing some Foo. Now, I am printing some Bar2. This should print a capital 'A': A
也可以使用 Heredoc 語法將資料傳遞給函式參數
範例 #9 Heredoc 參數範例
<?php
var_dump(array(<<<EOD
foobar!
EOD
));
?>
可以使用 Heredoc 語法初始化靜態變數和類別屬性/常數
範例 #10 使用 Heredoc 初始化靜態值
<?php
// 靜態變數
function foo()
{
static $bar = <<<LABEL
Nothing in here...
LABEL;
}
// 類別屬性/常數
class foo
{
const BAR = <<<FOOBAR
Constant example
FOOBAR;
public $baz = <<<FOOBAR
Property example
FOOBAR;
}
?>
起始的 Heredoc 識別符號可以選擇性地用雙引號括起來
範例 #11 在 Heredoc 中使用雙引號
<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>
Nowdoc 之於單引號字串,如同 heredoc 之於雙引號字串。Nowdoc 的指定方式與 heredoc 類似,但 *nowdoc 內部* **不會** *進行字串插值*。這種結構非常適合嵌入 PHP 程式碼或其他大段文字,而無需使用跳脫字元。它與 SGML 的 <![CDATA[ ]]>
結構有一些共同之處,因為它宣告了一塊不需解析的文字區塊。
Nowdoc 使用與 heredoc 相同的 <<<
序列來識別,但後面的識別符號會用單引號括起來,例如 <<<'EOT'
。所有關於 heredoc 識別符號的規則也適用於 nowdoc 識別符號,尤其是關於結尾識別符號出現方式的規則。
範例 #12 Nowdoc 字串引號範例
<?php
echo <<<'EOD'
使用 nowdoc 語法
跨越多行的字串範例。反斜線永遠按字面處理,
例如 \\ 和 \'.
EOD;
以上範例會輸出
Example of string spanning multiple lines using nowdoc syntax. Backslashes are always treated literally, e.g. \\ and \'.
範例 #13 包含變數的 Nowdoc 字串引號範例
<?php
class foo
{
public $foo;
public $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<'EOT'
我的名字是 "$name"。我正在印出一些 $foo->foo。
現在,我正在印出一些 {$foo->bar[1]}。
這不應該印出大寫字母 'A': \x41
EOT;
?>
以上範例會輸出
My name is "$name". I am printing some $foo->foo. Now, I am printing some {$foo->bar[1]}. This should not print a capital 'A': \x41
範例 #14 靜態資料範例
<?php
class foo {
public $bar = <<<'EOT'
bar
EOT;
}
?>
當字串以雙引號或 heredoc 指定時,可以在其中替換變數。
有兩種語法:基本語法和進階語法。基本語法是最常見且方便的。它提供了一種以最少的 Aufwand 將變數、陣列值或物件屬性嵌入字串的方法。
如果遇到錢字號 ($
),則後面的可用於變數名稱的字元將被解釋為變數名稱並進行替換。
<?php
$juice = "apple";
echo "He drank some $juice juice." . PHP_EOL;
?>
以上範例會輸出
He drank some apple juice.
正式來說,基本變數替換語法的結構如下:
string-variable:: variable-name (offset-or-property)? | ${ expression } offset-or-property:: offset-in-string | property-in-string offset-in-string:: [ name ] | [ variable-name ] | [ integer-literal ] property-in-string:: -> name variable-name:: $ name name:: [a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*
自 PHP 8.2.0 起,`${ expression }` 語法已被棄用,因為它可能被解釋為可變變數
<?php
const foo = 'bar';
$foo = 'foo';
$bar = 'bar';
var_dump("${foo}");
var_dump("${(foo)}");
?>
以上範例在 PHP 8.2 中的輸出
Deprecated: Using ${var} in strings is deprecated, use {$var} instead in file on line 6 Deprecated: Using ${expr} (variable variables) in strings is deprecated, use {${expr}} instead in file on line 9 string(3) "foo" string(3) "bar"
以上範例會輸出
string(3) "foo" string(3) "bar"
注意:如果無法組成有效的變數名稱,則錢字號 ($) 將會原樣保留在字串中:
<?php
echo "No interpolation $ has happened\n";
echo "No interpolation $\n has happened\n";
echo "No interpolation $2 has happened\n";
?>以上範例會輸出
No interpolation $ has happened No interpolation $ has happened No interpolation $2 has happened
範例 #15 插入陣列或屬性第一維度的值
<?php
$juices = array("apple", "orange", "string_key" => "purple");
echo "他喝了一些 $juices[0] 果汁。";
echo PHP_EOL;
echo "他喝了一些 $juices[1] 果汁。";
echo PHP_EOL;
echo "他喝了一些 $juices[string_key] 果汁。";
echo PHP_EOL;
class A {
public $s = "string";
}
$o = new A();
echo "物件值: $o->s。";
?>
以上範例會輸出
He drank some apple juice. He drank some orange juice. He drank some purple juice. Object value: string.
注意: 陣列鍵值不應加引號,因此無法使用基本語法將常數作為鍵值。請改用進階語法。
從 PHP 7.1.0 開始,也支援*負*數值索引。
範例 #16 負數值索引
<?php
$string = 'string';
echo "索引 -2 的字元是 $string[-2]。", PHP_EOL;
$string[-3] = 'o';
echo "將索引 -3 的字元改為 o 得到 $string。", PHP_EOL;
?>
以上範例會輸出
The character at index -2 is n. Changing the character at index -3 to o gives strong.
對於更複雜的情況,必須使用進階語法。
進階語法允許插入具有任意存取器的*變數*。
任何具有字串表示形式的純量變數、陣列元素或物件屬性(無論是否為靜態)都可以透過此語法包含。表達式的寫法與其在字串之外的寫法相同,然後用 {
和 }
包起來。由於 {
無法被跳脫,因此只有在 $
緊跟在 {
之後時,才會辨識此語法。使用 {\$
來取得字面上的 {$
。以下是一些清楚的例子
<?php
const DATA_KEY = 'const-key';
$great = 'fantastic';
$arr = [
'1',
'2',
'3',
[41, 42, 43],
'key' => 'Indexed value',
'const-key' => 'Key with minus sign',
'foo' => ['foo1', 'foo2', 'foo3']
];
// Won't work, outputs: This is { fantastic}
echo "This is { $great}";
// Works, outputs: This is fantastic
echo "This is {$great}";
class Square {
public $width;
public function __construct(int $width) { $this->width = $width; }
}
$square = new Square(5);
// Works
echo "This square is {$square->width}00 centimeters wide.";
// Works, quoted keys only work using the curly brace syntax
echo "This works: {$arr['key']}";
// Works
echo "This works: {$arr[3][2]}";
echo "This works: {$arr[DATA_KEY]}";
// When using multidimensional arrays, always use braces around arrays
// when inside of strings
echo "This works: {$arr['foo'][2]}";
echo "This works: {$obj->values[3]->name}";
echo "This works: {$obj->$staticProp}";
// Won't work, outputs: C:\folder\{fantastic}.txt
echo "C:\folder\{$great}.txt";
// Works, outputs: C:\folder\fantastic.txt
echo "C:\\folder\\{$great}.txt";
?>
注意:由於此語法允許任意表達式,因此可以在進階語法中使用可變變數。
可以透過在字串後使用方括號指定所需字元的以零為基底的偏移量來存取和修改字串中的字元,例如 $str[42]。為此,您可以將字串視為字元的陣列。當您想要擷取或替換多個字元時,可以使用 substr() 和 substr_replace() 函式。
注意:從 PHP 7.1.0 開始,也支援負的字串偏移量。這些偏移量指定從字串結尾算起的偏移量。以前,負的偏移量在讀取時會發出
E_NOTICE
(產生空字串),在寫入時會發出E_WARNING
(使字串保持不變)。
注意:在 PHP 8.0.0 之前,也可以使用大括號存取字串,例如 $str{42},目的相同。此大括號語法自 PHP 7.4.0 起已被棄用,並且從 PHP 8.0.0 開始不再支援。
寫入超出範圍的偏移量會以空格填充字串。非整數類型會轉換為整數。非法的偏移量類型會發出 E_WARNING
。只會使用指定字串的第一個字元。從 PHP 7.1.0 開始,指定空字串會引發致命錯誤。以前,它會指定一個 NULL 位元組。
在內部,PHP 字串是位元組陣列。因此,使用陣列括號存取或修改字串並非多位元組安全,並且應該只對使用單一位元組編碼(例如 ISO-8859-1)的字串執行。
注意:從 PHP 7.1.0 開始,對空字串應用空索引運算子會引發致命錯誤。以前,空字串會靜默轉換為陣列。
範例 #17 一些字串範例
<?php
// 取得字串的第一個字元
$str = 'This is a test.';
$first = $str[0];
// 取得字串的第三個字元
$third = $str[2];
// 取得字串的最後一個字元
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
// 修改字串的最後一個字元
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
?>
字串的偏移量必須是整數或類似整數的字串,否則會產生警告。
範例 #18 非法字串偏移量的範例
<?php
$str = 'abc';
var_dump($str['1']);
var_dump(isset($str['1']));
var_dump($str['1.0']);
var_dump(isset($str['1.0']));
var_dump($str['x']);
var_dump(isset($str['x']));
var_dump($str['1x']);
var_dump(isset($str['1x']));
?>
以上範例會輸出
string(1) "b" bool(true) Warning: Illegal string offset '1.0' in /tmp/t.php on line 7 string(1) "b" bool(false) Warning: Illegal string offset 'x' in /tmp/t.php on line 9 string(1) "a" bool(false) string(1) "b" bool(false)
注意事項:
使用 `[]` 或 `{}` 存取其他類型(不包括陣列或實作適當介面的物件)的變數時,會靜默地返回
null
。
注意事項:
字串字面值中的字元可以使用
[]
或{}
來存取。
注意事項:
在 PHP 7.4 中,使用
{}
語法存取字串字面值中的字元已被棄用。此功能在 PHP 8.0 中已被移除。
字串 可以使用 '.' (點) 運算子連接。請注意,'+' (加法) 運算子不能用於此目的。詳情請參閱字串運算子。
有許多實用的函式可用於操作 字串。
有關一般函式,請參閱字串函式區段;有關進階的尋找和取代功能,請參閱Perl 相容正規表示式函式。
還有URL 字串函式,以及用於加密/解密字串的函式(Sodium 和 雜湊)。
最後,也請參閱字元類型函式。
可以使用 (string)
轉型或 strval() 函式將值轉換為 字串。在需要 字串 的表達式範圍內,會自動執行字串轉換。這種情況發生在使用 echo 或 print 函式時,或將變數與 字串 比較時。類型和類型轉換章節將更清楚地說明這一點。另請參閱 settype() 函式。
布林值 true
會轉換為 字串 "1"
。布林值 false
會轉換為 ""
(空字串)。這允許在 布林值 和 字串 值之間來回轉換。
整數 或 浮點數 會轉換為表示該數字的 字串(包括 浮點數 的指數部分)。浮點數可以使用科學記數法 (4.1E+6
) 進行轉換。
注意事項:
從 PHP 8.0.0 開始,小數點字元一律為句點 ("
.
")。在 PHP 8.0.0 之前,小數點字元是在腳本的地區設定 (類別 LC_NUMERIC) 中定義的。請參閱 setlocale() 函式。
陣列 (Array) 永遠會被轉換成字串 (string) "Array"
;因此,echo 和 print 本身無法顯示陣列 (array) 的內容。要查看單個元素,請使用諸如 echo $arr['foo']
的結構。有關查看整個內容的技巧,請參見下文。
為了將物件 (object) 轉換為字串 (string),必須使用魔術方法 __toString。
資源 (Resource) 永遠會被轉換成結構為 "Resource id #1"
的字串 (string),其中 1
是 PHP 在執行時分配給資源 (resource) 的資源編號。雖然不應依賴此字串的確切結構,且該結構可能會發生變化,但在執行腳本(例如網頁請求或 CLI 處理程序)的生命週期內,它對於給定的資源始終是唯一的,並且不會被重複使用。要取得資源 (resource) 的類型,請使用 get_resource_type() 函式。
null
永遠會被轉換為空字串。
如上所述,將陣列 (array)、物件 (object) 或資源 (resource) 直接轉換為字串 (string) 並不會提供任何關於值類型以外的有效資訊。有關檢查這些類型內容的更有效方法,請參見 print_r() 和 var_dump() 函式。
大多數 PHP 值也可以轉換為字串 (string) 以進行永久儲存。這種方法稱為序列化,由 serialize() 函式執行。
PHP 中的字串 (string) 是以位元組陣列和一個指示緩衝區長度的整數來實現的。它沒有關於這些位元組如何轉換為字元的信息,這項任務留給程式設計師處理。字串的組成值沒有限制;特別是,值為 0
的位元組(「NUL 位元組」)允許出現在字串中的任何位置(然而,本手冊中提到的一些函式並非「二進位制安全」,可能會將字串傳遞給忽略 NUL 位元組後數據的函式庫。)
字串類型的這種特性解釋了為什麼 PHP 中沒有單獨的「位元組」類型——字串扮演了這個角色。不返回文字數據的函式——例如,從網路通訊端讀取的任意數據——仍然會返回字串。
由於 PHP 並未強制規定字串的特定編碼,因此您可能會想知道字串字面量的編碼方式。例如,字串 "á"
是否等同於 "\xE1"
(ISO-8859-1)、"\xC3\xA1"
(UTF-8,C 形式)、"\x61\xCC\x81"
(UTF-8,D 形式) 或任何其他可能的表示方式?答案是,字串將以腳本檔案中的編碼方式進行編碼。因此,如果腳本是以 ISO-8859-1 編寫的,則字串將以 ISO-8859-1 編碼,依此類推。但是,如果啟用了 Zend Multibyte,則此規則不適用;在這種情況下,腳本可以用任意編碼(明確聲明或偵測到的編碼)編寫,然後轉換為特定的內部編碼,而該內部編碼將用於字串字面量。請注意,腳本的編碼(或啟用 Zend Multibyte 時的內部編碼)有一些限制 - 這幾乎總是意味著此編碼應該是 ASCII 的相容超集,例如 UTF-8 或 ISO-8859-1。但是,請注意,在初始和非初始 shift 狀態下可以使用相同位元組值的狀態相關編碼可能會產生問題。
當然,為了發揮作用,操作文字的函式可能必須對字串的編碼方式做出一些假設。遺憾的是,PHP 的函式在這方面存在很大的差異。
u
修飾符時)。
最終,這意味著使用 Unicode 編寫正確的程式取決於小心避免使用無效的函式,這些函式很可能會損壞資料,而改用行為正確的函式,這些函式通常來自 intl 和 mbstring 擴充套件。然而,使用可以處理 Unicode 編碼的函式只是一個開始。無論語言提供哪些函式,了解 Unicode 規範都是至關重要的。例如,一個假設只有大寫和小寫的程式就做了一個錯誤的假設。
文件中並未提及,但 heredoc 結尾的分號實際上會被解釋為真正的分號,因此有時會導致語法錯誤。
這個可以正常運作
<?php
$foo = <<<END
abcd
END;
?>
這個不行
<?php
foo(<<<END
abcd
END;
);
// 語法錯誤,出現意外的 ';'
?>
沒有分號,它就能正常運作
<?php
foo(<<<END
abcd
END
);
?>
在 PHP 8.2 中,在字串裡使用 ${var} 已被棄用,請改用 {$var}
<?php
$juice = "apple";
// 有效。透過將變數名稱用大括號括起來,明確指定變數名稱的結尾:
echo "He drank some juice made of {$juice}s.";
?>
您可以使用複雜語法將物件屬性和物件方法的值放在字串中。例如...
<?php
class Test {
public $one = 1;
public function two() {
return 2;
}
}
$test = new Test();
echo "foo {$test->one} bar {$test->two()}";
?>
會輸出 "foo 1 bar 2"。
但是,您無法對命名空間中的所有值都這樣做。類別常數和靜態屬性/方法將無法使用,因為複雜語法會尋找 '$'。
<?php
class Test {
const ONE = 1;
}
echo "foo {Test::ONE} bar";
?>
這將輸出 "foo {Test::ONE} bar"。常數和靜態屬性需要您將字串拆開。
md5('240610708') == md5('QNKCDZO')
這個比較結果為 true,因為兩個 md5() 雜湊值都以 '0e' 開頭,所以 PHP 類型轉換會將這些字串理解為科學記號。根據定義,零的任何次方都是零。
在 heredoc 格式中使用常數的簡單透明解決方案
DEFINE('TEST','TEST STRING');
$const = get_defined_constants();
echo <<<END
{$const['TEST']}
END;
結果
測試字串
一個簡單的函式,用於建立人類可讀的跳脫雙引號字串,以供在原始碼中使用或在除錯包含換行/定位字元/等的字串時使用。
<?php
function doubleQuote($str) {
$ret = '"';
for ($i = 0, $l = strlen($str); $i < $l; ++$i) {
$o = ord($str[$i]);
if ($o < 31 || $o > 126) {
switch ($o) {
case 9: $ret .= '\t'; break;
case 10: $ret .= '\n'; break;
case 11: $ret .= '\v'; break;
case 12: $ret .= '\f'; break;
case 13: $ret .= '\r'; break;
default: $ret .= '\x' . str_pad(dechex($o), 2, '0', STR_PAD_LEFT);
}
} else {
switch ($o) {
case 36: $ret .= '\$'; break;
case 34: $ret .= '\"'; break;
case 92: $ret .= '\\\\'; break;
default: $ret .= $str[$i];
}
}
}
return $ret . '"';
}
?>
字串轉數字。
很遺憾,文件內容不正確。
「數值由字串的初始部分給定。如果字串以有效的數值數據開頭,則將使用此值。否則,該值將為 0(零)。 」
整個文檔中都沒有說明,也沒有在範例中顯示,在將字串轉換為數字時,開頭的空格字元會被忽略,就像 strtod 函數一樣。
<?php
echo " \v\f \r 1234" + 1; // 1235
var_export ("\v\f \r 1234" == "1234"); // true
?>
然而,PHP 的行為甚至與 strtod 的行為不同。文檔說明,如果字串包含「e」或「E」字元,它將被解析為浮點數,並建議查看 strtod 的手冊以獲取更多資訊。手冊說明
「十六進位數字由「0x」或「0X」後跟一個非空的十六進位數字序列組成,可能包含一個基數字元,後面可以選擇跟一個二進位指數。二進位指數由一個「P」或「p」組成,後跟一個可選的加號或減號,再後跟一個非空的十進位數字序列,表示乘以 2 的冪次方。」
但似乎 PHP 並不識別指數或基數字元。
<?php
echo "0xEp4" + 1; // 15
?>
strtod 也使用目前的語系環境來選擇基數字元,但 PHP 忽略語系環境,基數字元始終為 2E。然而,PHP 在將數字轉換為字串時會使用語系環境。
使用 strtod 時,目前的語系環境也用於選擇空格字元,我不了解 PHP 的情況。
這裡有一個與字串超出結尾的字元訪問相關的奇特行為的潛在陷阱
$string = 'a';
var_dump($string[2]); // string(0) ""
var_dump($string[7]); // string(0) ""
$string[7] === ''; // TRUE
看起來字串結尾之後的任何東西都會給出一個空字串。然而,當 E_NOTICE 開啟時,上述範例將會拋出訊息
Notice: Uninitialized string offset: N in FILE on line LINE (注意:未初始化的字串偏移量:第 LINE 行的檔案中的 N)
此訊息無法使用 @$string[7] 特定遮罩,就像 $string 本身未設定時一樣。
isset($string[7]); // FALSE
$string[7] === NULL; // FALSE
即使它看起來像是一個非 NULL 值的字串類型,它仍然被視為未設定。
字串中的前導零(毫不意外地)不會被視為八進位。
考慮
$x = "0123" + 0;
$y = 0123 + 0;
echo "x is $x, y is $y"; //印出 "x is 123, y is 83"
換句話說
* 原始碼中數值字面值的前導零會被解釋為「八進位」,參考 strtol()。
* 字串(例如使用者提交的數據)中的前導零,在(隱式或顯式)轉換為整數時會被忽略,並視為十進位,參考 strtod()。
<?php
\\範例 # 10 簡單語法 - 最後一行 "echo" 的解決方案。
class people {
public $john = "John Smith";
public $jane = "Jane Smith";
public $robert = "Robert Paulsen";
public $smith = "Smith";
}
$people = new people();
echo "$people->john then said hello to $people->jane.".PHP_EOL;
echo "$people->john's wife greeted $people->robert.".PHP_EOL;
echo "$people->robert greeted the two $people->smiths";
\\無法正常運作
\\輸出:Robert Paulsen greeted the two
/**解決方案:**\
echo "$people->robert greeted the two $people->smith\x08s";
\\可以正常運作
\\輸出:Robert Paulsen greeted the two Smiths
?>
這是一個簡單的技巧,允許雙引號字串和 heredocs 使用大括號語法包含任意表達式,包括常數和其他函數呼叫。
<?php
// Hack 宣告
函式 _expr($v) { return $v; }
$_expr = '_expr';
// 我們的測試區
define('qwe', 'asd');
define('zxc', 5);
$a=3;
$b=4;
函式 c($a, $b) { return $a+$b; }
// 使用範例
echo "pre {$_expr(1+2)} post\n"; // 輸出 'pre 3 post'
echo "pre {$_expr(qwe)} post\n"; // 輸出 'pre asd post'
echo "pre {$_expr(c($a, $b)+zxc*2)} post\n"; // 輸出 'pre 17 post'
// 一般語法為 {$_expr(...)}
?>
為了節省您的時間,請不要閱讀先前關於日期的註解 ;)
當兩個字串都可以轉換為數字時(在 ("$a" > "$b") 測試中),則使用結果數字,否則逐字比較完整字串。
<?php
var_dump('1.22' > '01.23'); // bool(false)
var_dump('1.22.00' > '01.23.00'); // bool(true)
var_dump('1-22-00' > '01-23-00'); // bool(true)
var_dump((float)'1.22.00' > (float)'01.23.00'); // bool(false)
?>