在字符串中包含常量而不需要连接。

199

在PHP中,是否有一种方法可以将常量包含在字符串中,而无需进行连接操作?

define('MY_CONSTANT', 42);

echo "This is my constant: MY_CONSTANT";

19
我的直觉告诉我,“这是我的常量:{MY_CONSTANT}”应该可以工作。但实际上并不行。我在这里只是提醒其他人不要和我有相同的想法。 - Mikael Lindqvist
15个回答

164

使用字符串时,PHP无法区分字符串数据和常量标识符。这适用于PHP中的任何字符串格式,包括heredoc。

constant()是获取常量的替代方法,但是函数调用也不能直接放入字符串中,需要使用连接符。

PHP常量手册


74
"函数调用不能放入字符串中" 可以的:define('ANIMAL','turtles'); $constant='constant'; echo "我喜欢{$constant('ANIMAL')}"; - raveren
3
@Raveren,你应该以正确的方式提交你的答案,而不是作为评论。我相信这个回答以最有效和优雅的方式回答了OOP问题(也回答了我的问题)。谢谢。 - hndcrftd
2
@Raveren,虽然其他人提供了间接的变体,不必要地创建函数,但你的解决方案最短、重点明确,依赖于变量函数,这是 PHP 中被低估和极少使用的特性。在整个帖子中,我选择了你的特定解决方案。我希望我能对它进行多次+1评价。 - hndcrftd
1
我按要求提供了答案,并添加了更多关于为什么它有效的信息,以使答案对新手更有意义。https://dev59.com/83E95IYBdhLWcg3wrP6w#22407812 - raveren
4
我只是指出这是可能的,没有评论哪种方式更好。 - raveren
显示剩余2条评论

129

没错(某种程度上是的 ;)):

define('FOO', 'bar');

$test_string = sprintf('This is a %s test string', FOO);

这可能不是你的目标,但我认为,从技术上讲,这并不是连接操作,而是替换操作。基于此假设,它在字符串中包含了一个常量而无需进行连接操作。


这是将常量注入字符串的最干净的方法。没有拼接或插值语法,也没有临时变量将常量传递给字符串。printf()sprintf()绝对是我会使用和推荐的专业解决方案。此外,使用printf()函数族可以以最干净的方式分割长行,因为函数调用的每个参数都可以写在单独的一行上。最后,如果您需要在字符串中多次使用常量,printf()函数提供了编号的占位符。使用。这。技巧。 - undefined

84
要在字符串中使用常量,您可以使用以下方法[1]:
define( 'ANIMAL', 'turtles' ); 
$constant = constant(...);
echo "I like {$constant('ANIMAL')}!";

[1] “可以”并不意味着你“应该”,实际上我建议你真的这样做: sprintf('我喜欢%s!', ANIMAL);

如何使用{$constant('ANIMAL')}

字符串中的{}括号允许我们调用任何可调用函数,只要以$开头!

例如,"我喜欢{constant('ANIMAL')}";如果没有$,将不会触发变量替换,所以我们必须将可调用函数放在一个变量中。

顺便说一下:使用constant(...)语法被称为一级可调用语法

您还可以使用字符串函数名 - 以及任意参数

可以将任何函数名放在一个变量中,并在双引号字符串中使用参数调用它。也适用于多个参数。

$fn = 'substr';

echo "I like {$fn('turtles!', 0, -1)}";

产生

我喜欢乌龟

还有匿名函数、数组等等

$escape = fn( $string ) => htmlspecialchars( (string) $string, ENT_QUOTES, 'utf-8' );
$userText = "<script>alert('xss')</script>";

echo "You entered {$escape( $userText )}";

你输入了
class Arr
{
    public static function get( $array, $key, $default = null )
    {
        return is_array( $array ) && array_key_exists( $key, $array ) 
            ? $array[$key] 
            : $default;
    }
}

$fn = array( 'Arr', 'get' );

echo "I like {$fn(['turtles'], 0)}!"; 

产生:

我喜欢乌龟!

在3v4l.org上自己试试 并注意 - 大多数可调用类型(除了string)在php5.3之前不起作用(在撰写本帖时)- 现在已更新到php7+++时代

请记住

这种做法是不明智的,但有可能存在。


2
这是一个很棒的技巧!和其他答案一样,与串联相比在努力和可读性方面并没有太大的优势,但知道这个技巧还是很不错的。当你做类似于 $_ = create_function('$a','return $a;'); $s = "I like {$_(ANIMAL)}" 这样的事情时,它甚至更加性感。Thetaiko的版本消除了引号的需要,下划线也很可爱。 - Beejor
4
我可以看出这对于构建模板引擎很有用,但实际使用起来似乎太狡猾了。 - Mnebuerquo
在使用可调用数组进行字符串插值之前,将其转换为字符串对我来说很常见。只要方法是公共的,$fn = implode('::', array( 'Arr', 'get' )); 就可以工作。我看到其他人使用匿名函数包装器调用 call_user_func,但我认为这样做很草率。 - NeoVance
更加隐蔽的方法是定义 $_c = 'constant';,这样会稍微缩短一些但更加显眼:echo( "hello {$_c(NAME)}, how are you?";。但与 echo( "hello ".NAME." how are you?" ); 相比优势还有待商榷。在 Web 开发中,可以考虑使用 Hello <?=NAME?> hru? - theking2

29
define( 'FOO', 'bar');  
$FOO = FOO;  
$string = "I am too lazy to concatenate $FOO in my string";

9
这是我使用最频繁的语句,当我需要编写一堆疯狂的SQL语句时。也许有点暗示被动吧?;-) - Beejor
2
这个程序最简单,但会显得有些多余。 - BrDaHa

13
define('FOO', 'bar');
$constants = create_function('$a', 'return $a;');
echo "Hello, my name is {$constants(FOO)}";

这个未解释的答案在PHP8及以上版本中会产生致命错误,原因是create_function()函数。该函数在PHP7.2到PHP7.4版本中会抛出一个废弃通知。 - undefined

13

如果您真的想要在没有连接操作符的情况下回显常量,这里有解决方法:

define('MY_CONST', 300);
echo 'here: ', MY_CONST, ' is a number';

注意: 在这个例子中,echo使用了多个参数(看逗号),所以它并不是真正的字符串连接。

echo行为类似于函数,它可以接受更多的参数,相比于字符串连接,它更加高效,因为它不需要首先进行字符串连接然后再输出,而是直接输出所有参数,无需创建新的字符串拼接对象 :))

编辑

如果你考虑拼接字符串、传递字符串作为参数或者一次性写下整个字符串,那么,(逗号方式)是最快的,其次是.(带有'单引号的字符串连接),而最慢的字符串构建方法是使用"双引号,因为这种方式写出的表达式必须与已声明的变量和函数进行求值比较。


12

你可以这样做:

define( 'FOO', 'bar' );

$constants = get_defined_constants(true); // the true argument categorizes the constants
$constants = $constants[ 'user' ]; // this gets only user-defined constants

echo "Hello, my name is {$constants['FOO']}";

8
最简单的方法是:
define('MY_CONSTANT', 42);

$my_constant = MY_CONSTANT;
echo "This is my constant: $my_constant";

使用(s)printf的另一种方法

define('MY_CONSTANT', 42);

// Note that %d is for numeric values. Use %s when constant is a string    
printf('This is my constant: %d', MY_CONSTANT);

// Or if you want to use the string.

$my_string = sprintf('This is my constant: %d', MY_CONSTANT);
echo $my_string;

我认为这是一个很好的解决方案。在某些情况下,如果在内部使用直接常量,连接字符串可能无法正常工作。 - kta

5

正如其他人所指出的那样,您不能这样做。PHP有一个函数constant(),不能直接在字符串中调用,但我们可以轻松地解决这个问题。

$constant = function($cons){
   return constant($cons);
};

并提供基本示例以说明其用法:

define('FOO', 'Hello World!');
echo "The string says {$constant('FOO')}"; 

你可以直接使用 $constant = 'constant'; 而不是定义另一个函数,因为该函数已经存在,这样做的效果是一样的。 - redreinard

2
以下是一些替代其他答案的方法,这些答案似乎主要集中在 "{$}" 技巧上。虽然它们的速度不能保证;但这都是纯语法糖。对于这些示例,我们将假设下面的常量集已经定义好了。
define( 'BREAD', 'bread' ); define( 'EGGS', 'eggs' ); define( 'MILK', 'milk' );

使用extract()
这个函数非常好用,因为它的结果与变量相同。首先您需要创建一个可重复使用的函数:

function constants(){ return array_change_key_case( get_defined_constants( true )[ 'user' ] ); }

然后可以从任何作用域调用它:

extract( constants() );
$s = "I need to buy $bread, $eggs, and $milk from the store.";

在这里,它将常量转换为小写,以便您更容易输入,但是您可以删除array_change_key_case()以保持它们不变。如果您已经有冲突的本地变量名称,则常量不会覆盖它们。

使用字符串替换
这个与sprintf()类似,但只使用一个替换标记并接受无限数量的参数。我相信有更好的方法来做到这一点,但请原谅我的笨拙,并尝试专注于其背后的思想。

与之前一样,您可以创建可重复使用的函数:

function fill(){
    $arr = func_get_args(); $s = $arr[ 0 ]; array_shift( $arr );
    while( strpos( $s, '/' ) !== false ){
        $s = implode( current( $arr ), explode( '/', $s, 2 ) ); next( $arr );
    } return $s;
}

然后从任何作用域调用它:

$s = fill( 'I need to buy /, /, and / from the store.', BREAD, EGGS, MILK );

你可以使用任何你想要的替换标记,比如 % 或 #。我在这里使用了斜杠,因为它打起来更容易。


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