PHP美元符和花括号组合那些事—${${}}
双美元符+{}:${${variable}}是一种比较常见的用法,但是它的实现原理是什么呢?今天来探究一下:
提及这种用法,还得先说一下PHP的String类型
php.net上指出,一个字符串可以用4种方式表达:单引号,双引号,heredoc语法结构,nowdoc语法结构
这里heredoc语法结构和双引号形式类似,同样nowdoc结构对应单引号
单引号:单引号包围起来的字符串中,单引号必须转义才能使用(\'),否则会报语法错误;而用于转义的反斜线自身,则要用两个反斜线(\\),即也需要转义. 文档说"其他任何形式的反斜线都被当成反斜线本身:也就是说如果想使用其它转义序列例如 \r 或者 \n,并不代表任何特殊含义,就单纯是这两个字符本身",这就是说单引号包围起来的其他转义序列根本没有实现转义.
反过来说,\是可以直接作为反斜线使用的,因此单引号包围的字符串中\\和\其实都能表示反斜线本身,验证实例如下:
<?php
echo 'You deleted C:\\*.*?';
echo 'You deleted C:\*.*?';
echo 'This will not expand: \n a newline';
echo 'Variables do not $expand $either';
?>
双引号:当字符串包围在双引号中,PHP会对一些特殊字符解析,这里\n,\r,\t都正常解析为转义符,而且反斜线、美元符、双引号都需要转义:\\, \$, \"
heredoc和nowdoc不如引号用起来方便,但是可以实现相同的目的
再说变量解析,文档的说法是当字符串遇到双引号或heredoc结构定义时,其中的变量将会被解析;变量解析有两种语法规则,简单的和复杂的,其中复杂规则的显著标记是用花括号包围的表达式;
对于简单规则而言,当 PHP 解析器遇到一个美元符号($)时,它会和其它很多解析器一样,去组合尽量多的标识以形成一个合法的变量名。可以用花括号来明确变量名的界线。
<?php
$juice = "apple";
echo "He drank some juice made of ${juice}s.";
?>
复杂语法:复杂语法不是因为其语法复杂而得名,而是因为它可以使用复杂的表达式。
任何具有 string 表达的标量变量,数组单元或对象属性都可使用此语法。只需简单地像在 string 以外的地方那样写出表达式,然后用花括号 { 和 } 把它括起来即可。由于 { 无法被转义,只有 $ 紧挨着 { 时才会被识别。可以用 {\$ 来表达 {$。
<?php
$great = 'fantastic'; // 无效,输出: This is { fantastic}
echo "This is { $great}"; // 有效,输出: This is fantastic
echo "This is {$great}";
echo "This is ${great}";
echo "This is the value of the var named $name: {${$name}}";
?>
测试得到以上两条echo变量great的语句输出同样的结果,所以{${$name}}其实和${${name}}也是一样的
另外,php.net的文档中给出了Note:
"函数、方法、静态类变量和类常量只有在 PHP 5 以后才可在 {$} 中使用。然而,只有在该字符串被定义的命名空间中才可以将其值作为变量名来访问。只单一使用花括号 ({}) 无法处理从函数或方法的返回值或者类常量以及类静态变量的值。"
这里说的很清楚,只有单一{}无法处理返回值等,因为像${name}只是得到变量的名字,告诉我们这是变量name,即得到一个$name,假如我需要$name的值,那我就得对他再解析一次
所以像:
<!--
#GOAL: gather some phpinfo(); $str=@(string)$_GET['str'];
eval('$str="'.addslashes($str).'";');
-->
实现的方法是传入参数:str=${${phpinfo()}}
这里如果直接上phpinfo(),由于有addslashes的作用会出现\"的情况使得命令无法执行
${phpinfo()}告诉我们最里面这个是变量,名为phpinfo(),接下来的一层花括号将其解析为字符串"phpinfo()"
另外,{}有时候也可以当[]使用,文档中有说明:"Note: string 也可用花括号访问,比如 $str{42}",这里$str{42}==$str[42]
在《白帽子讲web安全》一书中也提到了同样的应用:
”PHP的curly systax能导致代码执行,它将执行花括号间的代码,并将结果替换回去,如下例:
<?php $var = "I was innocent until ${`ls`}" appeared here; ?>"
ls得到执行,列出本地目录并将结果返回
随机推荐
- 转载----How fast is Redis?
How fast is Redis? Redis includes the redis-benchmark utility that simulates running commands done b ...
- Android基于mAppWidget实现手绘地图(十二)–显示当前用户位置
若显示当前用户位置,你需要执行以下步骤: 1.添加ACCESS_COARSE_LOCATION 和ACCESS_FINE_LOCATION权限在AndroidManifest.xml中 2.用mapW ...
- Deep learning:五十(Deconvolution Network简单理解)
深度网络结构是由多个单层网络叠加而成的,而常见的单层网络按照编码解码情况可以分为下面3类: 既有encoder部分也有decoder部分:比如常见的RBM系列(由RBM可构成的DBM, DBN等),a ...
- RHEL6 某业务用户ulimit -a命令找不到
最终确定是shell环境问题,临时改为/bin/bash即可查看. 1.问题现象 # su - jingyu $ id uid=(jingyu) gid=(jingyu) (jingyu) $ uli ...
- [git]Git log 输出格式化(转载)
转载于:https://havee.me/linux/2015-05/git-pretty-output.html 美化完的格式: git log --graph --pretty=format:'% ...
- javascript小技巧:同步服务器时间、同步倒计时
之前在网上看到有人提问,如何在页面上同步显示服务器的时间,其实实现方法有几种,可能一般人立马就想到可以使用Ajax每隔一秒去请求服务器,然后将服务器获取到时间显示在页面上,这样虽然能够实现,但存在一个 ...
- CP/IP,SPDY,WebSocket 三者之间的关系
按照OSI网络分层模型,IP是网络层协议,TCP是传输层协议,而HTTP是应用层的协议.在这三者之间,SPDY和WebSocket都是与HTTP相关的协议,而TCP是HTTP底层的协议.一.HTTP的 ...
- angularjs input上传图片前获取图片的Size
首先我们需要一个指令来追踪input的change.ngChage不适用input[file]. app.directive("fileread", [function () { ...
- LeetCode - Flatten Binary Tree to Linked List
题目: Given a binary tree, flatten it to a linked list in-place. For example, Given 1 / \ 2 5 / \ \ 3 ...
- LINQ的Except方法
在两个集合中,左边集合减去右边集合的元素: source code: List<int> a = new List<int>{ { }, { }, { } }; List< ...