PHP中,4种方式定义字符串时的细节(单引号,双引号,heredoc,nowdoc)
先上总结:
字符串用单引号来定义时,只有两个字符需要转义,一个是单引号,一个是反斜线。
字符串用双引号来定义时,双引号想表示字面值需要转义,反斜线想表示字面值需要转义,$想表示字面值需要转义,\r\n表示换行(windows下),\t表示tab,$xx表示变量xx,还有\v等不常用的略
换行符就是一个长相怪异的普通字符,说它长相怪异,是因为字母a就是占一个字母的位置,字母空格就是一个空格,而换行符占了一个行尾,且导致它后面的内容要到下一行显示,不要看成多特殊。唯一的特殊之处在于在双引号定义的时候,有个替身可用\r\n,同样的字符有tab用\t这个替身演员,不用替身演员的话,直接键盘打出也是可以的。
php中对字符串的处理(下面内容是在php5.4.45下测试的)
php中字符串是 用单引号或者双引号来括起来的方式。
先说说用单引号定义字符串的情况。
$str = '这是一个字符串';
这是个很普通的符合人类的直觉的字符串,但是如果在字符串内容含有单引号呢?
如下这样用可以吗?
$str = '这是一个'字符串';
有问题了:不加以处理,系统怎么知道中间的单引号是内容,还是边界符呢?
PHP中是用反斜线(\)转义,就是 \' 表示 '
$str = '这是一个\'字符串';
这又产生了一个新问题,用了反斜线(\)转义,那内容中有反斜线怎么表示呢?
系统怎么知道反斜线是反斜线本身,还是具有转义功能的转义符呢?
所以,想在字符串中表示反斜线,那么,还需要一个反斜线转义,就是\\表示\
$str1 = '这是一个\\\'字符串';
echo $str1;
显示结果如下图:
在用单引号定义字符串的情况下,只有两个字符需要转义!英文状态的单引号'和英文状态反斜线(\)【注:反斜线在中文输入法状态下是顿号】
在我测试时发现,如果不是为了转义单引号,反斜线是不会被认为是转义符的,而是被认为是内容(但是最好别这样用,就用\\表示\最好)。如下:
$str1 = '这是一个\字符串';
echo $str1;
执行结果:
这里又有问题了,反斜线如果不和单引号在一起,就不作为转义符出现的话,反斜线和反斜线在一起,是不是转义符呢?
答:反斜线和反斜线在一起,前面的是转义符,后面的是内容,也就是说,一个反斜线是反斜线,二个反斜线是一个反斜线,3个反斜线是2个反斜线,4个反斜线是2个反斜线,5个反斜线是3个反斜线。以此类推。
如下;
$str1 = '这是一个\"字符串';
$str2 = '这是一个\\"字符串';
var_dump($str1 === $str2); //bool(true),因为$str1中反斜线后面没有要转义的字符,所以\和\\一样)
总结:字符串用单引号来定义时,单引号内,只有两个字符需要转义,一个是单引号,一个是反斜线。其中反斜线又特殊了,
反斜线后面有反斜线或单引号时,它就表示转义符,反斜线后面无反斜线或单引号时,它表示它的字面值,是字符串内容的一部分。
为何反斜线不和单引号一样,需要严格的转义才能用?搞不清楚。
1 $str1 = '这是一个\字符串'; 2 echo $str1; //这是一个\字符串 3 4 $str1 = '这是一个\\字符串'; 5 echo $str1; //这是一个\字符串 6 7 $str1 = '这是一个\\\字符串'; 8 echo $str1; //这是一个\\字符串 9 10 $str1 = '这是一个\\\\字符串'; 11 echo $str1; //这是一个\\字符串
反正就是从左往右看,\\和\'表示\和',其他情况下,\就是\
$str1 = '这是一个\\'字符串';
echo $str1; //报错,\\表示了内容\,单引号缺转义符
我们知道,在php中#、//、/* */都是注释,那么下面的情况
$str1 = '这是一个//字符串';
$str2 = '这是一个#字符串';
会把绿色阴影部分当成注释,而报错吗?
答:实验可知,php单引号括起来的字符串中,只有反斜线和单引号需要转义,其他的一切视为字符,//和#也就是普通字符,不会被视为注释了代码,不会报错。
结果如图
到目前为止,字符串都是一行搞定的,那如果字符串中有换行,空白,等视觉上看不到的字符呢?怎么定义?
试着把\n写到字符串中。
1 $str1 = '这是一个\n字符串';
2 echo $str1; // \的后面不是\或',\将被视同内容,而非转义符。因此,这里\n是内容\和n,而不是换行的意思。
3 //这是一个\n字符串
下面这段代码和上面一样,虽然多了个\
1 $str1 = '这是一个\\n字符串';
2 echo $str1; // \的后面是\或',视同内容\或',因此,这里\\n是字符\n,显示结果如下
3 //这是一个\n字符串
下面的代码,浏览器得到的是(查看源代码中看)
$str1 = '这是一个<br />字符串';
echo $str1;
\n被认为是字符\n,那如果想让字符串中有控制字符\n,就是换行,而不是字符\n,怎么办?
答案是:可以跨行写,如下
可见:php中,控制字符和常接触的字符一样,只不过不像ABCD那样直观,但是是存在的,直接在变量赋值等情况时打印即可。
导致的结果是在php代码中看,代码跨度好几行。
并且在双引号中来定义。如下是等效的。
下面说字符串用双引号定义的情况。
$str1 = "这是'一个"; echo $str1; //这是'一个
双引号中的单引号是不需要转义的,但是出现双引号必须转义
$str1 = "这是"一个";
echo $str1; //报错
echo "这是\'个"; //这是\'个
echo "这是\\'个"; //这是\'个
字符串用双引号定义表示时,字符串内容本身若有双引号,则需要转义双引号。
同时,反斜线后面跟某些特定字符时,它是作为转义字符,如下。
\r\n表示换行(windows平台下),\t表示tab,\$表示$(要不然会被认为是变量),\v垂直制表 等。
反斜线后面跟的不是特定字符时,和单引号时一样,反斜线作为反斜线内容本身。
1 $str1 = "我\n\r是"; 2 $str2 = "我 3 是"; 4 var_dump($str1 === $str2); //true, 注意:编辑器和浏览器都是windows平台下的, windows平台下\r\n是换行符,unix下\n是换行符,mac下\r是换行符 5 echo $str1;
这个字符串就是 : 我[换行]是
显示结果如下图
总结一下,单引号和双引号来表示字符串时候的区别。
把自己当成解析器,
看到两个单引号中间夹着内容的时候,从左往右开始解析,\'表示' ,\\表示\,\其他的时候\还是\
看到双引号夹着内容的时候,\"表示",\\表示\,\$表示$,\r\n表示换行(windows下),\t表示tab,$xx表示变量xx,还有\v等不常用的略
单引号因为需要转义的少,性能高。
在双引号中,\r\n是换行的意思,如果在代码中直接回车也行,不一定要用\r\n,直接写的话,代码就是下面这样子
如果是用单引号的话,想写换行,就只能用上图中$str2中的方式,不能用\r\n替代换行,因为单引号下它不转义!
在php源代码文件中,换行是\r\n还是\n,还是\r,是可以设置的,如下图
如果字符串内容很多,还需要换行,heredoc和nowdoc的方式更方便点,因为不用考虑字符串中有单引号,双引号还要转义的事情了。
heredoc和双引号相比,也就是不用对双引号特殊处理这点优势,其他的优势不明显。
你能换行写,我也能换行写。你会对变量解析,我也一样,你支持控制字符\r\n等,我也一样。但是在html中,常用引号,可以不对引号特殊处理,也算是个实用的有点了。
nowdoc是php5.3新出的,网上可找,类似于单引号的方式,不再多说。
到这里,我觉得是纠正了以前的模糊不清的概念——控制字符也是字符,把控制字符当成普通字符看,在用双引号定义字符串时,控制字符多个物化的替身。
比如,在编辑php源代码时候,写下如下代码在文件中。
1 $str = "我是字符串 2 呀!"; 3 echo $str;
上面在文本编辑器中,是三行代码,不清楚这一块的可能会把变量$str理解成“我是字符串呀!”因为有个回车是看不见摸不到的,其实,把回车看出普通字符更好理解。变量$str是“我是字符串[回车]呀!”,windows下\r\n也是控制字符回车的意思因此下面的代码和上面的一样!
1 $str = "我是字符串\r\n呀!"; 2 echo $str;
变量$str是“我是字符串[回车]呀!”(不含引号),那么在双引号可以解析控制字符的情况下,\r\n和你单独打一个回车,在文本编辑器中显示不同,一个是看得见的\r\n,一个是看不见但起了变化的控制符,效果却是相同的
变量的内容,就是php输出的内容,也就是浏览器接到的内容,也就是浏览器上查看html源代码时的内容,至于在显示层面上怎么变化,那是另外的话题了。
另外,看看用户表单输入获得的变量和字符串之间的关系。
我在表单中input输入了 aaa'bbb ,如下图,那么提交后,通过$c = $_POST得到的是什么情况呢?
如下图:得到的变量和下面的变量是一样一样的。
1 $a = 'aaa\'bbb'; 2 $b = "aaa'bbb";
这时候我就疑惑了,没有开启魔术引号的情况下。如上面代码的行1,怎么已经将单引号转义了?这样的情况还会有SQL注入问题吗?为什么会自动加反斜线?
其实,这个逻辑是这样的,为了便于理解,我就称呼 aaa'bbb 为 矮矮矮单引号比比比,共有7个字符
用户在input里输入:矮矮矮单引号比比比
php页面post收到字符串内容:矮矮矮单引号比比比
我们用单引号定义变量时显示:矮矮矮反斜线单引号比比比,这里就是疑惑所在了。
这样理解,之所以有反斜线显示出来,就是把脑海中的字符串内容显示成带有单引号包装的代码,碰到单引号,所以加反斜杠转义。
但它的实质是,这个变量是一个字符串,这个字符串内容就是,矮矮矮单引号比比比。
所以,用双引号定义变量时,没有反斜线,它们也是完全相等的,就是,矮矮矮单引号比比比
$a = 'aaa\'bbb';解释为变量a就是内容为矮矮矮单引号比比比这7个字符的字符串。
echo 这个变量,也是矮矮矮单引号比比比
在组成传统的sql语句过程中,变量带有单引号,sql语句就变成了一个内容为带有不正确数目的单引号的新字符串。
通过addslashes函数后,变量加了反斜线,变成了矮矮矮反斜线单引号比比比,这时候再组成的sql语句,数据库执行的时候,读反斜线单引号为单引号,存到数据库中,于是恢复了原貌。
有点绕,所以按照新的sql方式,数据和定界符分开,也就没这么多破事了。