php中的模式修饰符 二

php中的模式修饰符一 中我们介绍了 imsx 几个修饰符,本篇我们继续介绍。

e (PREG_REPLACE_EVAL)

该修饰符已经被PHP7版本弃用了。如果设置了修饰符, preg_replace() 在进行了对替换字符串的 后向引用替换之后, 将替换后的字符串作为php 代码评估执行(eval 函数方式),并使用执行结果 作为实际参与替换的字符串。单引号、双引号、反斜线()和 NULL 字符在 后向引用替换时会被用反斜线转义。

<?php

$str = "<p>This is an example</p>";

$pattern = "/^<p>(.*)<\/p>$/e";

$str = preg_replace($pattern,"add_tr('\\1')",$str);

var_dump($str);

function add_tr($str)
{
    return "<tr>$str</tr>";
}

这里要使用 php5+ 版本来执行,而不能使用php7 版本。执行结果

string(27) "<tr>This is an example</tr>"

注意,对于 php5 高版本的会出现提示说该修饰符已经被降级

PHP Deprecated:  preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /Users/liuhanzeng/workspace/php/reg.php on line 7

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /Users/liuhanzeng/workspace/php/reg.php on line 7
string(27) "<tr>This is an example</tr>"

如果不指定e$pattern = '/^<p>(.*)<\/p>$/' 那结果就成了 add_tr('This is an example')。也就是不能使用回调函数了,直接当成字符串去把目标字符串替换掉。

如果说设置了e之后是使用回调函数的话,这种说法是不正确的。而是将preg_replace函数的第二个参数使用eval()函数来执行,然后将执行后的结果替换掉目标字符串。 下面再举几个例子来说明

<?php

$str = "<p>This is an example</p>";
$pattern = "/^<p>(.*)<\/p>$/e";

$str = preg_replace($pattern,"\\1",$str);

当匹配成功以后,\\1是捕获的第一个子组的内容——This is an example。 设置了e,就会将\\1eval函数执行。所以就会报错

Fatal error: preg_replace(): Failed evaluating code:
This is an example in ...

因为This is an example 不是一段有效的PHP代码。

注意,因为我们在preg_replace中给的第二个参数是\\1,所以在eval看来This is an example 并不是一个字符串。如果我们给的第二个参数是 '\\1',那在eval看来是这样的'This is an example'。所以就不会报错。 看例子

<?php

$str = "<p>This is an example</p>";
$pattern = "/^<p>(.*)<\/p>$/e";

$str = preg_replace($pattern,"'\\1'",$str);
var_dump($str);

正确替换了目标字符串

string(18) "This is an example"

所以说我们回过头来再看下面这个例子

<?php

$str = "<p>This is an example</p>";

$pattern = "/^<p>(.*)<\/p>$/e";

$str = preg_replace($pattern,"add_tr('\\1')",$str);

var_dump($str);

function add_tr($str)
{
    return "<tr>$str</tr>";
}

仔细看的话发现这种形式并不是严格意义上的指定一个回调函数,它就是一个对函数的调用代码。因为通常的指定回调函数是不能加小括号()的。

由于ePHP7中已经被废弃了,所以要想使用上面那种回调函数,可以用preg_replace_callback来代替。

<?php

$str = "<p>This is an example</p>";

$pattern = "/^<p>(.*)<\/p>$/";

$str = preg_replace_callback($pattern,function ($matches) {
    return add_tr($matches[1]);
},$str);

var_dump($str);

function add_tr($str)
{
    return "<tr>$str</tr>";
}

使用PHP7执行结果就正常了

string(27) "<tr>This is an example</tr>"

注意:在function($matches){}中最后一定要有return

通过上面preg_replace_callback的回调函数,然后对比之前例子中使用e指定的回调函数,发现形式是不是不一样的。

其实,是不是可以认为e就是使用的eval的第一个字符。就是为了对preg_replace第二个参数使用eval函数执行。由此也知道,e只是在使用preg_replace函数的时候设置,其他函数和它就没有关系了。

由于eval函数是存在很大的风险的,容易造成远程执行任何代码。所以不推荐使用。 这也是为什么废弃它的原因。

查看笔记

扫码一下
查看教程更方便