解析数组非数字键名引号的必要性


Posted in PHP onAugust 09, 2013

我看到过很多人操作数组的时候, 对于数组中的非数字键名不使用引号

  $array[key] = $value;

我可以理解有些人可能会觉得这样的代码很”整洁”, 并且也能正常执行.
更甚至,如果他很”幸运的”php配置的好:
error_reporting = ~E_NOTIC

他也许永远都沉浸在自己的”整洁”风格中, 看不到任何的NOTICE提示, 也不会意识到, 他这么做, 能损失多少的性能~
来, 我们一起来看看:
good.php:
<?php
   $array = array();
   $i = 0;
   while(++$i < 1000){
       $array['good'] = 2;
   }
?>

bad.php:
<?php
   $array = array();
   $i = 0;
   while(++$i < 1000){
       $array[good] = 2;
   }
?>

分别看运行时间(多次平均时间):
加引号的:
$ time php -f good.php
real 0m0.013s
user 0m0.005s
sys 0m0.007

不加引号的:
$ time php -f bad.php
PHP Notice: Use of undefined constant bad - assumed 'bad' in /home/huixinchen/tmp/bad.php
on line (此处省略999行NOTICE)
real 0m0.100s
user 0m0.020s
sys 0m0.029

看看,差别有多大?
哦, 或许我们应该模拟一下那些”幸运的”人们的情况, 去掉花费在记录NOTICE的开销, 看看~
$ time php -f bad.php
real 0m0.037s
user 0m0.018s
sys 0m0.018

我们可以看出, 基本上, 使用引号,和不使用引号的效率损失在3倍以上
那么, 这些效率损失到哪里去了呢?
我们分别看下, 俩个文件生成的OPCODE序列:
good.php :
filename: /home/huixinchen/tmp/good.php
compiled vars: !0 = $array, !1 = $i
line # op fetch ext return operands
-------------------------------------------------------------------------------
   2 0 INIT_ARRAY ~0
         1 ASSIGN !0, ~0
   3 2 ASSIGN !1, 0
   4 3 PRE_INC $3 !1
         4 IS_SMALLER ~4 $3, 1000
         5 JMPZ ~4, ->9
   5 6 ZEND_ASSIGN_DIM !0, 'good'
         7 ZEND_OP_DATA 2, $6
   6 8 JMP ->3
   8 9 RETURN 1
        10* ZEND_HANDLE_EXCEPTIO

bad.php :
filename: /home/huixinchen/tmp/bad.php
compiled vars: !0 = $array, !1 = $i
line # op fetch ext return operands
-------------------------------------------------------------------------------
   2 0 INIT_ARRAY ~0
         1 ASSIGN !0, ~0
   3 2 ASSIGN !1, 0
   4 3 PRE_INC $3 !1
         4 IS_SMALLER ~4 $3, 1000
         5 JMPZ ~4, ->10
   5 6 FETCH_CONSTANT ~5 'bad'
         7 ZEND_ASSIGN_DIM !0, ~5
         8 ZEND_OP_DATA 2, $7
   6 9 JMP ->3
   8 10 RETURN 1
        11* ZEND_HANDLE_EXCEPTIO

我们可以看出(其实,根据NOTICE的提示也知道), PHP会把没有引号引起来的键名当作是常量去获取, 当找不到的时候, 抛出一个NOTICE, 然后再根据”常量明”生成一个字符串, 然后再讲这个字符串做为键名继续~
聪明的你一定会想到, 可能会出现如下不可预期的错误:
define('key_name' , 'laruence');
....
//省略很多行代码
$array[key_name] = 2; //变成了 $array['laruence'] = 2;
//这样的错误, 你会很郁闷吧?

明白了么? 数组中的非数字键的键名一定要有引号啊~
哦, 还记得有人会说, 那在字符串变量替换的时候, 写引号会导致错误,
恩, 标准写法:
$string = "variable value is {$array['key']}"

我很赞同:”be lazy”, 但是, lazy也是应该有原则的.
最后, 好的代码,不应该通过关闭error_reporting来伪装.
附注, FETCH_CONSTANT OPCODE中找不到常量的相关逻辑:
....
if (!zend_get_constant(opline->op2.u.constant.value.str.val,
     opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
       zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
                opline->op2.u.constant.value.str.val,
                opline->op2.u.constant.value.str.val);
       EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;//获取"常量"名字符串
       zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);//分配空间,生成字符串
}
....
PHP 相关文章推荐
PHP安装问题
Oct 09 PHP
一段php加密解密的代码
Oct 09 PHP
php中CI操作多个数据库的代码
Jul 05 PHP
PHP设置images目录不充许http访问的方法
Nov 01 PHP
thinkPHP5 ACL用户权限模块用法详解
May 10 PHP
PHP判断一个数组是另一个数组子集的方法详解
Jul 31 PHP
php微信公众号开发之欢迎老朋友
Oct 20 PHP
PDO::getAttribute讲解
Jan 28 PHP
Codeigniter里的无刷新上传的实现代码
Apr 14 PHP
php中用unset销毁变量并释放内存
May 10 PHP
PHP var关键字相关原理及使用实例解析
Jul 11 PHP
基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作
Aug 17 PHP
php防注入及开发安全详细解析
Aug 09 #PHP
分割GBK中文遭遇乱码的解决方法
Aug 09 #PHP
解析isset与is_null的区别
Aug 09 #PHP
PHP中怎样保持SESSION不过期 原理及方案介绍
Aug 08 #PHP
php中用socket模拟http中post或者get提交数据的示例代码
Aug 08 #PHP
浅析php变量作用域的一些问题
Aug 08 #PHP
解析php开发中的中文编码问题
Aug 08 #PHP
You might like
php for 循环语句使用方法详细说明
2010/05/09 PHP
利用浏览器的Javascript控制台调试PHP程序
2014/01/08 PHP
php图片缩放实现方法
2014/02/20 PHP
跨浏览器PHP下载文件名中的中文乱码问题解决方法
2015/03/05 PHP
PHP使用反射机制实现查找类和方法的所在位置
2016/04/22 PHP
PHP cookie与session会话基本用法实例分析
2019/11/18 PHP
javascript 类定义的4种方法
2009/09/12 Javascript
javascript中replace( )方法的使用
2015/04/24 Javascript
javascript排序函数实现数字排序
2015/06/26 Javascript
JavaScript去除数组里重复值的方法
2015/07/13 Javascript
JavaScript简单下拉菜单实例代码
2015/09/07 Javascript
express文件上传中间件Multer详解
2016/10/24 Javascript
JavaScript实现经纬度转换成地址功能
2017/03/28 Javascript
详解angular笔记路由之angular-router
2017/09/12 Javascript
详解从买域名到使用pm2部署node.js项目全过程
2018/03/07 Javascript
Node.JS段点续传:Nginx配置文件分段下载功能的实现方法
2018/03/12 Javascript
JavaScript分步实现一个出生日期的正则表达式
2018/03/22 Javascript
谈谈为什么你的 JavaScript 代码如此冗长
2019/01/30 Javascript
微信小程序使用websocket通讯的demo,含前后端代码,亲测可用
2019/05/22 Javascript
JavaScript语句错误throw、try及catch实例解析
2020/08/18 Javascript
js实现网页随机验证码
2020/10/19 Javascript
Python验证码识别处理实例
2015/12/28 Python
python GUI库图形界面开发之PyQt5表格控件QTableView详细使用方法与实例
2020/03/01 Python
keras模型保存为tensorflow的二进制模型方式
2020/05/25 Python
详解BeautifulSoup获取特定标签下内容的方法
2020/12/07 Python
html+js 实现markdown编辑器效果
2019/10/23 HTML / CSS
美国面料纺织品商城:Fabric.com
2017/06/28 全球购物
荷兰街头时尚之家:Funkie House
2019/03/18 全球购物
Vans澳大利亚官网:购买鞋子、服装及配件
2019/09/05 全球购物
LUISAVIAROMA德国官网:时尚奢侈品牌购物网站
2020/11/12 全球购物
天鹅的故事教学反思
2014/02/04 职场文书
充分就业社区汇报材料
2014/05/07 职场文书
“九一八事变纪念日”国旗下讲话稿
2014/09/14 职场文书
校园安全广播稿范文
2014/09/25 职场文书
营业员岗位职责
2015/02/11 职场文书
2015年大班保育员工作总结
2015/05/18 职场文书