在PHP中字符串中的大括号

226

在PHP中,字符串文字中的{ }(花括号)表示将变量嵌入到字符串中。


3
@Quasimodo'sclone 这是完全不同的问题,不应被视为重复。 - Douwe de Haan
4个回答

338
这是用于字符串插值的复杂(花括号)语法,来自手册:

Complex (curly) syntax

This isn't called complex because the syntax is complex, but because it allows for the use of complex expressions.

Any scalar variable, array element or object property with a string representation can be included via this syntax. Simply write the expression the same way as it would appear outside the string, and then wrap it in { and }. Since { can not be escaped, this syntax will only be recognised when the $ immediately follows the {. Use {\$ to get a literal {$. Some examples to make it clear:

<?php
// Show all errors
error_reporting(E_ALL);

$great = 'fantastic';

// Won't work, outputs: This is { fantastic}
echo "This is { $great}";

// Works, outputs: This is fantastic
echo "This is {$great}";
echo "This is ${great}";

// Works
echo "This square is {$square->width}00 centimeters broad."; 


// Works, quoted keys only work using the curly brace syntax
echo "This works: {$arr['key']}";


// Works
echo "This works: {$arr[4][3]}";

// This is wrong for the same reason as $foo[bar] is wrong  outside a string.
// In other words, it will still work, but only because PHP first looks for a
// constant named foo; an error of level E_NOTICE (undefined constant) will be
// thrown.
echo "This is wrong: {$arr[foo][3]}"; 

// Works. When using multi-dimensional arrays, always use braces around arrays
// when inside of strings
echo "This works: {$arr['foo'][3]}";

// Works.
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()}}";

// Won't work, outputs: This is the return value of getName(): {getName()}
echo "This is the return value of getName(): {getName()}";
?>
经常情况下,这种语法是不必要的。例如,这样写:
$a = 'abcd';
$out = "$a $a"; // "abcd abcd";

与此完全相同:

$out = "{$a} {$a}"; // same

所以花括号是不必要的,但是这个是必要的:

$out = "$aefgh";

根据您的错误级别,将无法工作或因没有名为$aefgh的变量而产生错误,因此您需要执行以下操作:

$out = "${a}efgh"; // or
$out = "{$a}efgh";

49
过于苛求复制/粘贴细节的批判并不必要。如果这样做可以使它更易理解、更方便查找,那么这是一个好决定。对我来说,这个决定得到了赞同,正是我所寻找的,而我在PHP手册中没有找到。可能是因为他们用了正确的名称之类的原因,但我在这里找到了它。 - Gabriel Magana
10
对于花括号字符,请将它们重复两次,例如 $vars='x:3,y:9'; $json="{{$vars}}";。感谢 QiGuang的文章 - Bob Stein
3
如果大括号内的内容也包含变量,则对每个变量加上花括号:$min=1;$max=5; echo ".{{$min},{$max}}" 输出结果为 .{1,5}。(我在@BobStein的评论中提到“双重使用大括号”时有些困惑。) - Xenos
第十一个例子加上这两行会更加清晰:$name = 'hello'; $hello = 'world'; - CaptureWiz
再举一个例子:使用方法的返回值:echo "我的名字是{$this-getName()}" - Abdull
显示剩余5条评论

51

对我而言,花括号可作为字符串拼接的替代符号,更易于快速输入,代码看起来也更加简洁。请记得使用双引号(" "),因为 PHP 会将其内容解析,而单引号(' ')则会直接输出变量名字本身:

<?php

 $a = '12345';

// This works:
 echo "qwe{$a}rty"; // qwe12345rty, using braces
 echo "qwe" . $a . "rty"; // qwe12345rty, concatenation used

// Does not work:
 echo 'qwe{$a}rty'; // qwe{$a}rty, single quotes are not parsed
 echo "qwe$arty"; // qwe, because $a became $arty, which is undefined

?>

1
他们的内容是经过 PHP 解析的。这是具有误导性的。你不能仅仅将任意的 PHP 表达式放在花括号语法中,那是我从你的引文中读到的意思。 - Mark Amery
1
总的来说,使用括号打字并不比不用更快。你需要按SHIFT键来输入双引号和花括号。如果你严格使用双引号,那会更快一些。 - deflime
4
谢谢您强调双引号和单引号的区别,加一分。 - cameronjonesweb
我会使用 evaluate 而不是 parse - Cholthi Paul Ttiopic
1
任何被赋值给变量的单引号内容都会被视为字符串。 - shashikant kuswaha
补充@shashikantkuswaha的评论:如果字符串周围有单引号,你不会“仅获得变量的字面名称”[这意味着'{$a}'将产生包含一个字符a的字符串],而是“获取包含您键入的确切字符序列的字符串”:在此示例中,一个包含4个字符{ $ a }的字符串。 - ToolmakerSteve

25

例子:

$number = 4;
print "You have the {$number}th edition book";
//output: "You have the 4th edition book";

如果没有花括号,PHP会尝试查找名为$numberth的变量,但该变量不存在!


4
我也发现访问对象属性非常有用,尤其是在属性名称因某些迭代器而变化的情况下。例如,我已经使用下面的模式来处理一组时间段:小时、天、月份。
$periods=array('hour', 'day', 'month');
foreach ($periods as $period)
{
    $this->{'value_'.$period}=1;
}

这种模式也可以用来访问类方法。同样地,只需按照相同的方式构建方法名,使用字符串和字符串变量即可。

你可能很容易就会认为通过使用数组来存储值是更好的选择。如果这个应用程序仅限于 PHP,我会同意这一点。当类属性映射到数据库表中的字段时,我使用这种模式。虽然可以使用序列化将数组存储在数据库中,但这样做是低效的,而且如果必须对各个字段进行索引,则没有意义。我经常添加一个由迭代器键入的字段名称数组,以兼顾两全其美。

class timevalues
{
                             // Database table values:
    public $value_hour;      // maps to values.value_hour
    public $value_day;       // maps to values.value_day
    public $value_month;     // maps to values.value_month
    public $values=array();

    public function __construct()
    {
        $this->value_hour=0;
        $this->value_day=0;
        $this->value_month=0;
        $this->values=array(
            'hour'=>$this->value_hour,
            'day'=>$this->value_day,
            'month'=>$this->value_month,
        );
    }
}

1
这是一个有用的技巧。然而,我很少使用它:在我看来,“高效”的方法是避免仅为访问值而需要字符串连接。将对象属性命名为您想要访问它们的方式:public $hour;。给定 $key='hour';,可以执行 $it->$key。不要存储每个对象的值数组[会增加额外的存储成本],而是存储一个类变量公共常量,其中包含属性名称和数据库名称之间的映射:public const value_names = ['hour'=>'value_hour', ...];。有了这些,编写任何所需访问的函数就很容易了。 - ToolmakerSteve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接