guanguans.github.io icon indicating copy to clipboard operation
guanguans.github.io copied to clipboard

PHP 字符串中直接解析函数的写法

Open guanguans opened this issue 3 years ago • 4 comments

PHP 字符串中直接解析函数的写法

example

PHP 中的字符串理论上是不能够解析函数的,仅能够解析变量。最近发现一种特殊的写法,是可以让字符串直接解析函数的。

写法

// 单行
${!${''} = 代码}

// 多行
${!${''} =
    代码
}

分析

首先要知道 PHP 中 $varName${'varName'} 指的是同一个名称的变量。如果要声明一个名称为的变量只能通过这样 ${''} 的方式。

// 输出: string(7) "testing"
var_dump(${!${''} = 'testing'});

从内到外分析这段代码:

  1. ${''} = 'testing'} - 声明一个名称为空字符串的变量。
  2. !${''} = 'testing'} - 对一个赋值变量表达式取反值为:false
  3. ${!${''} = 'testing'} - 通过上面分析,最外层相当于调用变量 ${false}
  4. 由于变量名称是一个字符串,${false} 等同于 ${''}
  5. 整体分析,内部声明一个名称为空字符串的变量 ${''},而外部又调用了这个变量。

示例

以下代码仅供学习交流,实际工作中不建议用这种写法。

一、

$fruits = implode('、', ['apple', 'banana']);
var_dump("fruits: $fruits."); // 正常写法解析变量
// string(23) "fruits: apple、banana."

var_dump("fruits: implode('、', ['apple', 'banana'])."); // 错误写法不能够解析函数
// string(44) "fruits: implode('、', ['apple', 'banana'])."

var_dump("fruits: ${!${''} = implode('、', ['apple', 'banana'])}."); // 特殊写法解析函数成功
// string(23) "fruits: apple、banana."

var_dump("fruits: ${!${''} = implode('、',
    [
        'apple',
        'banana'
    ])}."
); // 多行书写依然解析函数成功
// string(23) "fruits: apple、banana."

二、

var_dump("fruits: ${!${''} = $fruit ?? 'apple'}.");
// string(14) "fruits: apple."

var_dump("fruits: ${!${''} = isset($fruit) ? $fruit : 'apple'}.");
// string(14) "fruits: apple."

三、

$fruit = function (){
    return 'banana';
};
var_dump("fruits: ${!${''} = $fruit() }.");
// string(15) "fruits: banana."

var_dump("fruits: ${!${''} = call_user_func(function (){
    $fruits = [
        'apple',
        'banana'
    ];
    
    return implode('、', $fruits);
}) }.");
// string(23) "fruits: apple、banana."

四、

class Fruit
{
    public function __toString()
    {
        return 'banana';
    }

}
var_dump("fruits: ${!${''} = new Fruit() }.");
// string(15) "fruits: banana."

原文链接

guanguans avatar Sep 12 '21 12:09 guanguans

感觉这种方式不容易读,维护成本高了

forecho avatar Jun 20 '22 06:06 forecho

感觉这种方式不容易读,维护成本高了

我感觉要禁用这种写法,ide 都直接报致命错误了。

guanguans avatar Jun 20 '22 11:06 guanguans

我觉得php 应该想办法去支持 "{md5('abc')}" 这种,因为 "{$this->md5('abc')}" 这种都是支持的。

vipzhicheng avatar Oct 20 '22 02:10 vipzhicheng

我觉得php 应该想办法去支持 "{md5('abc')}" 这种,因为 "{$this->md5('abc')}" 这种都是支持的。

如果支持了的话,确实又方便了不了。

guanguans avatar Oct 20 '22 02:10 guanguans