文档中没有提到,但在 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 '这是一个简单的字符串';
echo '你也可以这样在字符串中嵌入换行符
因为这样做是
可以的';
// 输出: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 之前,务必注意,包含结束标识符的行除了分号(;
)之外,不能包含其他字符。这意味着特别是标识符 * 不能缩进 *,并且分号前后不能有任何空格或制表符。同样重要的是要认识到,结束标识符之前的第一个字符必须是本地操作系统定义的换行符。这在包括 macOS 在内的 UNIX 系统上是 \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 文本的行为就像一个双引号的 string,没有双引号。这意味着 Heredoc 中的引号不需要转义,但上面列出的转义代码仍然可以使用。变量会被扩展,但在 Heredoc 中表达复杂变量时,与 string 一样,必须小心。
示例 #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,就像 Heredoc 是对双引号字符串一样。Nowdoc 的指定方式与 Heredoc 类似,但 * Nowdoc 中没有进行解析 *。该结构非常适合嵌入 PHP 代码或其他大型文本块,而无需转义。它与 SGML <![CDATA[ ]]>
结构有一些共同的功能,因为它声明了一个不进行解析的文本块。
Nowdoc 使用与 Heredoc 相同的 <<<
序列标识,但后面的标识符用单引号括起来,例如 <<<'EOT'
。Heredoc 标识符的所有规则也适用于 Nowdoc 标识符,尤其是那些关于结束标识符外观的规则。
示例 #12 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 \'.
示例 #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'
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
示例 #14 静态数据示例
<?php
class foo {
public $bar = <<<'EOT'
bar
EOT;
}
?>
当 string 用双引号或 Heredoc 指定时,variables 会在其中解析。
有两种语法:简单 的和 复杂 的。简单语法是最常见和最方便的语法。它提供了一种将变量、array 值或 object 属性嵌入到 string 中的方法,只需最少的努力。
复杂语法可以通过包围表达式的花括号来识别。
如果遇到美元符号($
),解析器将贪婪地获取尽可能多的标记以形成有效的变量名。将变量名括在花括号中以明确指定名称的结束位置。
<?php
$juice = "apple";
echo "He drank some $juice juice." . PHP_EOL;
// 不小心。 "s" 是变量名中的有效字符,因此它指的是 $juices,而不是 $juice。
echo "He drank some juice made of $juices." . PHP_EOL;
// 通过将引用括在花括号中,明确指定变量名的结束位置。
echo "He drank some juice made of {$juice}s.";
?>
上面的示例将输出
He drank some apple juice. He drank some juice made of . He drank some juice made of apples.
类似地,可以解析 array 索引或 object 属性。对于数组索引,结束方括号(]
)标记索引的结束位置。与简单变量一样,对象属性也适用相同的规则。
示例 #15 简单语法示例
<?php
$juices = array("apple", "orange", "koolaid1" => "purple");
echo "他喝了一些 $juices[0] 汁。".PHP_EOL;
echo "他喝了一些 $juices[1] 汁。".PHP_EOL;
echo "他喝了一些 $juices[koolaid1] 汁。".PHP_EOL;
class people {
public $john = "John Smith";
public $jane = "Jane Smith";
public $robert = "Robert Paulsen";
public $smith = "Smith";
}
$people = new people();
echo "$people->john 喝了一些 $juices[0] 汁。".PHP_EOL;
echo "$people->john 然后对 $people->jane 说你好。".PHP_EOL;
echo "$people->john 的妻子向 $people->robert 打招呼。".PHP_EOL;
echo "$people->robert 向两个 $people->smiths 打招呼。"; // 无法工作
?>
上面的示例将输出
He drank some apple juice. He drank some orange juice. He drank some purple juice. John Smith drank some apple juice. John Smith then said hello to Jane Smith. John Smith's wife greeted Robert Paulsen. Robert Paulsen greeted the two .
从 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
// 显示所有错误
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 的常量,如果未找到,则抛出错误。
// 如果找到常量,则将使用其值(而不是 'foo' 本身)
// 作为数组索引。
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()}";
// 无法工作,输出:C:\folder\{fantastic}.txt
echo "C:\folder\{$great}.txt"
// 工作,输出:C:\folder\fantastic.txt
echo "C:\\folder\\{$great}.txt"
?>
也可以使用此语法在字符串中使用变量访问类属性。
<?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";
?>
上面的示例将输出
I am bar. I am bar.
注意:
在
{$}
内,从函数、方法调用、静态类变量和类常量访问的值将被解释为定义字符串的作用域中的变量名称。使用单花括号 ({}
) 无法访问函数或方法的返回值,也不能访问类常量或静态类变量的值。
<?php
// 显示所有错误。
error_reporting(E_ALL);
class beers {
const softdrink = 'rootbeer';
public static $ale = 'ipa';
}
$rootbeer = 'A & W';
$ipa = 'Alexander Keith\'s';
// 这有效;输出:I'd like an A & W
echo "I'd like an {${beers::softdrink}}\n";
// 这也有效;输出:I'd like an Alexander Keith's
echo "I'd like an {${beers::$ale}}\n";
?>
可以在 字符串 中通过在 字符串 后面使用方括号 (数组 方括号),指定所需字符的从零开始的偏移量来访问和修改字符,例如 $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 开始,分配空字符串会抛出致命错误。以前,它会分配一个空字节。
在内部,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
(“空字节”)的字节在字符串中的任何位置都是允许的(但是,本手册中称为“非二进制安全”的少数几个函数可能会将字符串传递给忽略空字节之后数据的库)。
字符串类型的这种特性解释了为什么 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 "他喝了一些由 {$juice} 制成的果汁。" ;
?>
可以使用复杂语法将对象属性和对象方法的值都放入字符串中。例如...
<?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
\Example # 10 Simple Syntax - Solution for the last "echo" line.
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
\\Outputs: Robert Paulsen greeted the two
/**Solution:**\
echo "$people->robert greeted the two $people->smith\x08s";
\\Will work
\\Outputs: 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)
?>