文档没有提到,但在 heredoc 结尾处的分号实际上会被解释为真实的分号,因此有时会导致语法错误。
这有效
<?php
$foo = <<<END
abcd
END;
?>
这无效
<?php
foo(<<<END
abcd
END;
);
// 语法错误,意外的 ';'
?>
不带分号,它可以正常工作
<?php
foo(<<<END
abcd
END
);
?>
一个 字符串 是一系列字符,其中一个字符与一个字节相同。这意味着 PHP 只支持 256 个字符集,因此不提供原生 Unicode 支持。请参阅 字符串类型的详细信息。
注意: 在 32 位版本中,字符串 的大小最多可达 2GB(最大 2147483647 字节)
可以使用四种不同的方法指定 字符串 字面量
指定 字符串 的最简单方法是用单引号(字符 '
)括起来。
要指定字面单引号,请使用反斜杠 (\
) 对其进行转义。要指定字面反斜杠,请将其加倍 (\\
)。反斜杠的其他所有实例都将被视为字面反斜杠:这意味着您可能习惯使用的其他转义序列,例如 \r
或 \n
,将按原样输出,而不会有任何特殊含义。
<?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 |
换行符 (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 语法:<<<
。在此运算符之后,提供一个标识符,然后是一个换行符。字符串 本身紧随其后,然后是相同的标识符来关闭引号。
结束标识符可以缩进空格或制表符,在这种情况下,缩进将从 doc 字符串中的所有行中删除。在 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
如果结束标识符缩进,也可以使用制表符,但是,关于结束标识符的缩进和正文(直到结束标识符)的缩进,不能混合使用制表符和空格。在任何这些情况下,都会抛出 ParseError。包含这些空格约束是因为混合使用制表符和空格进行缩进不利于可读性。
示例 3 正文(空格)结束标识符的不同缩进
<?php
// 以下所有代码均无效。
// 正文(空格)结束标记(制表符)的不同缩进
{
echo <<<END
a
END;
}
// 在正文中混合使用空格和制表符
{
echo <<<END
a
END;
}
// 在结束标记中混合使用空格和制表符
{
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 之前,非常重要的一点是,包含结束标识符的行不能包含其他字符,除了分号 (;
)。这意味着尤其不能缩进标识符,并且分号前后不能有任何空格或制表符。还必须意识到,结束标识符之前的第一个字符必须是本地操作系统定义的换行符。在 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;
}
?>
包含变量的 Heredocs 不能用于初始化类属性。
Heredoc 文本的行为与双引号字符串完全相同,只是没有双引号。这意味着Heredoc中的引号不需要转义,但上面列出的转义码仍然可以使用。变量会被扩展,但在Heredoc中表达复杂变量时,需要像使用字符串一样谨慎。
示例 #8 Heredoc 字符串引用示例
<?php
$str = <<<EOD
字符串示例
跨越多行
使用heredoc语法。
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
我的名字是 "$name". 我正在打印一些 $foo->foo.
现在,我正在打印一些 {$foo->bar[1]}.
这应该打印大写字母 '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
这里什么也没有...
LABEL;
}
// 类属性/常量
class foo
{
const BAR = <<<FOOBAR
常量示例
FOOBAR;
public $baz = <<<FOOBAR
属性示例
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时,可以替换其中的变量。
有两种类型的语法:基本语法和高级语法。基本语法是最常见和最方便的。它提供了一种方法,可以以最小的努力将变量、数组值或对象属性嵌入到字符串中。
如果遇到美元符号 ($
),则其后可以用于变量名的字符将被解释为变量名并被替换。
<?php
$juice = "apple";
echo "他喝了一些 $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 "没有发生插值 $ \n";
echo "没有发生插值 $\n 已经发生\n";
echo "没有发生插值 $2 已经发生\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']
];
// 不起作用,输出: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 "这个正方形是 {$square->width}00 厘米宽。;
// 起作用,只有使用花括号语法时,带引号的键才有效
echo "This works: {$arr['key']}";
// 起作用
echo "This works: {$arr[3][2]}";
echo "This works: {$arr[DATA_KEY]}";
// 使用多维数组时,始终在字符串内使用大括号括起数组
// when inside of strings
echo "This works: {$arr['foo'][2]}";
echo "This works: {$obj->values[3]->name}";
echo "This works: {$obj->$staticProp}";
// 不起作用,输出:C:\folder\{fantastic}.txt
echo "C:\folder\{$great}.txt";
// 起作用,输出: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 和 Hash)。
最后,另请参见字符类型函数。
可以使用 (string)
类型转换或 strval() 函数将值转换为字符串。字符串转换在表达式范围内自动完成,在该表达式中需要字符串。当使用 echo 或 print 函数时,或者当变量与字符串进行比较时,就会发生这种情况。类型和类型转换部分将使以下内容更加清晰。另请参见 settype() 函数。
布尔值 true
将转换为字符串 "1"
。布尔值 false
将转换为 ""
(空字符串)。这允许在布尔值和字符串值之间来回转换。
整数 或 浮点数 将转换为表示数字文本的字符串(包括浮点数的指数部分)。可以使用指数表示法(4.1E+6
)转换浮点数。
注意:
从 PHP 8.0.0 开始,小数点字符始终为句点("
.
")。在 PHP 8.0.0 之前,小数点字符在脚本的区域设置(类别 LC_NUMERIC)中定义。请参见 setlocale() 函数。
数组 始终转换为字符串 "Array"
;因此,echo 和 print 本身无法显示数组的内容。要查看单个元素,请使用 echo $arr['foo']
之类的构造。有关查看全部内容的提示,请参见下文。
为了将对象转换为字符串,必须使用魔术方法__toString。
资源 始终转换为结构为 "Resource id #1"
的字符串,其中 1
是 PHP 在运行时分配给资源的资源编号。虽然不应依赖此字符串的确切结构,并且它可能会发生更改,但它对于在执行脚本(即 Web 请求或 CLI 进程)的生命周期内给定的资源而言始终是唯一的,并且不会被重复使用。要获取资源的类型,请使用 get_resource_type() 函数。
null
始终转换为空字符串。
如上所述,直接将数组、对象或资源转换为字符串不会提供超出其类型之外的任何关于值的有用信息。有关更有效地检查这些类型内容的方法,请参见函数 print_r() 和 var_dump()。
大多数 PHP 值也可以转换为字符串以进行永久存储。此方法称为序列化,由 serialize() 函数执行。
PHP 中的字符串实现为字节数组和一个表示缓冲区长度的整数。它不包含关于这些字节如何转换为字符的信息,将此任务留给程序员。字符串可以由任何值组成,没有限制;特别是,值为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。但是,请注意,在初始和非初始移位状态下可以使用相同字节值的依赖于状态的编码可能会出现问题。
当然,为了实用,对文本进行操作的函数可能必须对字符串的编码方式做出一些假设。不幸的是,在 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')
此比较结果为真,因为两个 md5() 哈希都以 '0e' 开头,因此 PHP 类型转换将这些字符串理解为科学计数法。根据定义,零的任何次幂都是零。
在 heredoc 格式中使用常量的简单透明解决方案
DEFINE('TEST','TEST STRING');
$const = get_defined_constants();
echo <<<END
{$const['TEST']}
END;
结果
TEST STRING
一个简单的函数,用于创建易于阅读的转义双引号字符串,用于源代码或调试包含换行符/制表符等的字符串。
<?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
此消息不能像 `$string` 本身未设置时那样,使用 `@$string[7]` 特定地屏蔽。
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";
\Won't work
\\输出:Robert Paulsen greeted the two
/**解决方案:**\
echo "$people->robert greeted the two $people->smith\x08s";
\\将会工作
\\输出:Robert Paulsen greeted the two Smiths
?>
这是一个简单的技巧,允许双引号字符串和 heredoc 在花括号语法中包含任意表达式,包括常量和其他函数调用
<?php
// 技巧声明
function _expr($v) { return $v; }
$_expr = '_expr';
// 我们的测试环境
define('qwe', 'asd');
define('zxc', 5);
$a=3;
$b=4;
function 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)
?>