单引号
定义一个字符串的最简单的方法是用单引号把它包围起来(字符 ')。
要表达一个单引号自身,需在它的前面加个反斜线(\)来转义。要表达一个反斜线自身,则用两个反斜线(\\)。其它任何方式的反斜线都会被当成反斜线本身:也就是说如果想使用其它转义序列例如
\r 或者 \n,并不代表任何特殊含义,就单纯是这两个字符本身。
注意:
不像双引号和
heredoc
语法结构,在单引号字符串中的变量和特殊字符的转义序列将不会被替换。
示例 #1 Syntax Variants
<?php
echo 'this is a simple string', PHP_EOL;
// 可以录入多行
echo 'You can also have embedded newlines in
strings this way as it is
okay to do', PHP_EOL;
// 输出:Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"', PHP_EOL;
// 输出:You deleted C:\*.*?
echo 'You deleted C:\\*.*?', PHP_EOL;
// 输出:You deleted C:\*.*?
echo 'You deleted C:\*.*?', PHP_EOL;
// 输出:This will not expand: \n a newline
echo 'This will not expand: \n a newline', PHP_EOL;
// 输出:Variables do not $expand $either
echo 'Variables do not $expand $either', PHP_EOL;
?>
双引号
如果字符串是包围在双引号("))中, PHP 将对以下特殊的字符进行解析:
转义字符
| 序列 |
含义 |
\n |
换行(ASCII 字符集中的 LF 或 0x0A (10)) |
\r |
回车(ASCII 字符集中的 CR 或 0x0D (13)) |
\t |
水平制表符(ASCII 字符集中的 HT 或 0x09 (9)) |
\v |
垂直制表符(ASCII 字符集中的 VT 或 0x0B (11)) |
\e |
Escape(ASCII 字符集中的 ESC 或 0x1B (27)) |
\f |
换页(ASCII 字符集中的 FF 或 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 结构
第三种表达字符串的方法是用 heredoc
句法结构:<<<。在该运算符之后要提供一个标识符,然后换行。接下来是字符串
string 本身,最后要用前面定义的标识符作为结束标志。
结束标识符可以使用空格或制表符(tab)缩进,此时文档字符串会删除所有缩进。
在 PHP 7.3.0 之前的版本中,结束时所引用的标识符必须在该行的第一列。
而且,标识符的命名也要像其它标签一样遵守
PHP 的规则:只能包含字母、数字和下划线,并且必须以字母和下划线作为开头。
示例 #2 PHP 7.3.0 之后的基础 Heredoc 示例
<?php
// 无缩进
echo <<<END
a
b
c
\n
END;
// 4 空格缩进
echo <<<END
a
b
c
END;
如果结束标识符的缩进超过内容的任何一行的缩进,则将抛出 ParseError 异常:
示例 #3 结束标识符的缩进不能超过正文的任何一行
<?php
echo <<<END
a
b
c
END;
Parse error: Invalid body indentation level (expecting an indentation level of at least 3) in example.php on line 4
制表符也可以缩进结束标识符,但是,关于缩进结束标识符和内容,
制表符和空格不能混合使用。在以上任何情况下,
将会抛出 ParseError 异常。
之所以包含这些空白限制,是因为混合制表符和空格来缩进不利于易读性。
示例 #4 内容(空白)和结束标识符的不同缩进
<?php
// 以下所有代码都不起作用。
// 正文(空格)和结束标记(制表符),不同的缩进
{
echo <<<END
a
END;
}
// 在正文中混合空格和制表符
{
echo <<<END
a
END;
}
// 在结束标记中混合空格和制表符
{
echo <<<END
a
END;
}
Parse error: Invalid indentation - tabs and spaces cannot be mixed in example.php line 8
内容字符串的结束标识符后面不需要跟分号或者换行符。
例如,从 PHP 7.3.0 开始允许以下代码:
示例 #5 在结束标识符后继续表达式
<?php
$values = [<<<END
a
b
c
END, 'd e f'];
var_dump($values);
array(2) {
[0] =>
string(11) "a
b
c"
[1] =>
string(5) "d e f"
}
警告
如果在某一行的开头找到了结束标识符,那么不管它是否是另外一个单词的一部分,
它都可能看作结束标识符并引起 ParseError。
示例 #6 字符串内容中的结束标识符往往会导致 ParseError
<?php
$values = [<<<END
a
b
END ING
END, 'd e f'];
Parse error: syntax error, unexpected identifier "ING", expecting "]" in example.php on line 5
为了避免这个问题,遵循以下简单的规则较为安全:
不要选择一个出现在文本主体中的单词作为结束标识符。
警告
在 PHP 7.3.0 之前,请务必注意,带有结束标识符的行不能包含除
(;)外的任何其他字符。
这意味着标识符不能缩进,分号的前后也不能有任何空白或制表符。更重要的是结束标识符的前面必须是个被本地操作系统认可的换行,比如在
UNIX 和 macOS 系统中是 \n,而结束定界符之后也必须紧跟一个换行。
如果不遵守该规则导致结束标识不“干净”,PHP
将认为它不是结束标识符而继续寻找。如果在文件结束前也没有找到一个正确的结束标识符,PHP
将会在最后一行产生一个解析错误。
示例 #7 PHP 7.3.0 之前的错误示例
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
// 不能缩进标识符
?>
示例 #8 在 PHP 7.3.0 之前有效示例
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
?>
Heredocs 结构不能用来初始化类的属性。
Heredoc 结构就象是没有双引号的 string,这就是说在 heredoc
结构中单引号不用被转义,但是上文中列出的转义序列还可以使用。变量将被替换,但在 heredoc
结构中含有复杂的变量时要像 string 一样格外小心。
示例 #9 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 结构用在函数参数中来传递数据:
示例 #10 Heredoc 结构在参数中的示例
<?php
var_dump(array(<<<EOD
foobar!
EOD
));
?>
可以用 Heredoc 结构来初始化静态变量和类的属性和常量:
示例 #11 使用 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 结构中用双引号来声明标识符:
示例 #12 在 heredoc 结构中使用双引号
<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>
Nowdoc 结构
就象 heredoc 结构类似于双引号字符串,Nowdoc 结构是类似于单引号字符串的。Nowdoc
结构很象 heredoc 结构,但是 nowdoc
中不进行字符串插值。这种结构很适合用于嵌入 PHP
代码或其它大段文本而无需对其中的特殊字符进行转义。与 SGML 的
<![CDATA[ ]]> 结构是用来声明大段的不用解析的文本类似,nowdoc 结构也有相同的特征。
一个 nowdoc 结构也用和 heredocs 结构一样的标记
<<<, 但是跟在后面的标识符要用单引号括起来,即
<<<'EOT'。Heredoc 结构的所有规则也同样适用于 nowdoc
结构,尤其是结束标识符的规则。
示例 #13 Nowdoc 结构字符串示例
<?php
echo <<<'EOD'
Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.
EOD;
Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.
示例 #14 含变量引用的 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'
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
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
示例 #15 静态数据的示例
<?php
class foo {
public $bar = <<<'EOT'
bar
EOT;
}
?>
注意:
Nowdoc 结构是在 PHP 5.3.0 中加入的。
字符串插值
当字符串用双引号或 heredoc 结构定义时,其中的变量可以进行替换。
这里共有两种语法规则:一种基本规则,一种高级规则。基本的语法规则是最常用和最方便的,它可以用最少的代码在一个
string 中嵌入一个变量,一个 array 的值,或一个 object 的属性。
基本语法
如果遇到一个美元符号($),后面的字符会被解释为变量名,然后替换为变量的值。
示例 #16 String Interpolation
<?php
$juice = "apple";
echo "He drank some $juice juice." . PHP_EOL;
?>
He drank some apple juice.
从形式上讲,基本变量替换语法的结构如下:
警告
${ expression } 语法从 PHP 8.2.0 开始被弃用,因为它可能被解释为
可变变量:
高级 字符串插值语法应该被使用。
注意:
如果无法形成有效的变量名,美元符号会保持原样。
示例 #17 插值数组或属性的第一个维度值
<?php
$juices = array("apple", "orange", "string_key" => "purple");
echo "He drank some $juices[0] juice.";
echo PHP_EOL;
echo "He drank some $juices[1] juice.";
echo PHP_EOL;
echo "He drank some $juices[string_key] juice.";
echo PHP_EOL;
class A {
public $s = "string";
}
$o = new A();
echo "Object value: $o->s.";
?>
He drank some apple juice.
He drank some orange juice.
He drank some purple juice.
Object value: string.
注意:
数组键必须是无引号的,因此不能用基本语法将常量作为键来引用。使用
高级
语法代替。
从 PHP 7.1.0 起,还支持负数字索引。
示例 #18 负数索引
<?php
$string = 'string';
echo "The character at index -2 is $string[-2].", PHP_EOL;
$string[-3] = 'o';
echo "Changing the character at index -3 to o gives $string.", PHP_EOL;
?>
The character at index -2 is n.
Changing the character at index -3 to o gives strong.
对于更复杂的情况,可以使用 高级
语法。
高级(大括号)语法
高级语法允许使用任意访问器对变量进行插值。
任何标量变量、数组元素或对象属性(static 或非
static)都可以通过这种语法进行插值。表达式的写法和
在string之外的写法一样,然后用大括号{和
}包围。由于{不能被转义,所以这种语法只有在
紧跟在{后面的$才会被识别。要得到一个字面的
{$,需要用{\$。以下是一些例子:
示例 #19 Curly Syntax
<?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']
];
// 无效,输出 This is { fantastic}
echo "This is { $great}";
// 有效,输出 This is fantastic
echo "This is {$great}";
class Square {
public $width;
public function __construct(int $width) { $this->width = $width; }
}
$square = new Square(5);
// 有效
echo "This square is {$square->width}00 centimeters wide.";
// 有效,引用 key 仅使用花括号语法时有效
echo "This works: {$arr['key']}";
// 有效
echo "This works: {$arr[3][2]}";
echo "This works: {$arr[DATA_KEY]}";
// 使用多维数组时,在字符串内部时,始终使用括号括住数组
echo "This works: {$arr['foo'][2]}";
echo "This works: {$obj->values[3]->name}";
echo "This works: {$obj->$staticProp}";
// 无效,输出 C:\directory\{fantastic}.txt
echo "C:\directory\{$great}.txt";
// 有效,输出 C:\directory\fantastic.txt
echo "C:\\directory\\{$great}.txt";
?>
注意:
由于该语法允许任意表达式,因此可以在高级语法中使用
可变变量。
存取和修改字符串中的字符
string 中的字符可以通过一个从 0 开始的下标,用类似
array 结构中的方括号包含对应的数字来访问和修改,比如
$str[42]。可以把 string
当成字符组成的 array。函数 substr() 和
substr_replace() 可用于操作多于一个字符的情况。
注意:
从 PHP 7.1.0 开始,还支持 string 负偏移量。从 string 尾部到指定位置的偏移量。
以前,负偏移量读取时(返回空 string)会发出 E_NOTICE,
写入时(string 保持不变)会发出 E_WARNING。
注意:
PHP 8.0.0 之前, 出于同样的目的,可以使用大括号访问 string,例如 $str{42}。
从 PHP 7.4.0 起,此大括号语法被弃用,自 PHP 8.0.0 开始不再受支持。
警告
用超出字符串长度的下标写入将会拉长该字符串并以空格填充。非整数类型下标会被转换成整数。非法下标类型会产生一个
E_WARNING 级别错误。
写入时只用到了赋值字符串的第一个字符。
PHP 7.1.0 开始,用空字符串赋值会导致 fatal 错误;在之前赋给的值是
NULL 字符。
警告
PHP 的字符串在内部是字节组成的数组。因此用花括号访问或修改字符串对多字节字符集很不安全。仅应对单字节编码例如
ISO-8859-1 的字符串进行此类操作。
注意:
从 PHP 7.1.0 开始,对空字符串应用空索引运算符会引发致命错误。
以前是空字符串会被静默转为数组。
示例 #20 一些字符串示例
<?php
// 取得字符串的第一个字符
$str = 'This is a test.';
$first = $str[0];
var_dump($first);
// 取得字符串的第三个字符
$third = $str[2];
var_dump($third);
// 取得字符串的最后一个字符
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
var_dump($last);
// 修改字符串的最后一个字符
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
var_dump($str);
?>
字符串下标必须为整数或可转换为整数的字符串,否则会发出警告。之前类似
"foo" 的下标会无声地转换成 0。
示例 #21 字符串无效下标的例子
<?php
$str = 'abc';
$keys = [ '1', '1.0', 'x', '1x' ];
foreach ($keys as $keyToTry) {
var_dump(isset($str[$keyToTry]));
try {
var_dump($str[$keyToTry]);
} catch (TypeError $e) {
echo $e->getMessage(), PHP_EOL;
}
echo PHP_EOL;
}
?>
bool(true)
string(1) "b"
bool(false)
Cannot access offset of type string on string
bool(false)
Cannot access offset of type string on string
bool(false)
Warning: Illegal string offset "1x" in Standard input code on line 10
string(1) "b"
注意:
用 [] 或 {}
访问任何其它类型(不包括数组或具有相应接口的对象实现)的变量只会无声地返回 null。
注意:
可以直接在字符串原型中用
[] 或 {} 访问字符。
注意:
PHP 7.4 中弃用在字符串字面量中使用 {} 来访问字符。
PHP 8.0 已移除。