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


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 相关文章推荐
第1次亲密接触PHP5(1)
Oct 09 PHP
PHP+MYSQL的文章管理系统(二)
Oct 09 PHP
php数组应用之比较两个时间的相减排序
Aug 18 PHP
php 无限级缓存的类的扩展
Mar 16 PHP
PHP中的strtr函数使用介绍(str_replace)
Oct 20 PHP
PHP中将ip地址转成十进制数的两种实用方法
Aug 15 PHP
PHP导入导出Excel代码
Jul 07 PHP
PHP 微信支付类 demo
Nov 30 PHP
PHP简单读取PDF页数的实现方法
Jul 21 PHP
老生常谈php 正则中的i,m,s,x,e分别表示什么
Mar 02 PHP
PHP实现的简单操作SQLite数据库类与用法示例
Jun 19 PHP
php通过header发送自定义数据方法
Jan 18 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边学边教》(01.开篇――准备工作)
2006/12/13 PHP
PHP验证信用卡卡号是否正确函数
2015/05/27 PHP
简单PHP会话(session)说明介绍
2016/08/21 PHP
PHP PDO和消息队列的个人理解与应用实例分析
2019/11/25 PHP
网页和浏览器兼容性问题汇总(draft1)
2009/06/01 Javascript
jQuery fadeTo方法调整图片的透明度使用介绍
2013/05/06 Javascript
利用JQuery和Servlet实现跨域提交请求示例分享
2014/02/12 Javascript
如何判断微信内置浏览器(通过User Agent实现)
2014/09/01 Javascript
一个JavaScript获取元素当前高度的实例
2014/10/29 Javascript
基于jQuery创建鼠标悬停效果的方法
2015/03/07 Javascript
js实现交换运动效果的方法
2015/04/10 Javascript
js计算文本框输入的字符数
2015/10/23 Javascript
实现高性能JavaScript之执行与加载
2016/01/30 Javascript
vue.js通过自定义指令实现数据拉取更新的实现方法
2016/10/18 Javascript
vue-cli构建项目使用 less的方法
2017/10/04 Javascript
jQuery实现动态控制页面元素的方法分析
2017/12/20 jQuery
p5.js入门教程之平滑过渡(Easing)
2018/03/16 Javascript
jQuery插件实现弹性运动完整示例
2018/07/07 jQuery
小程序数据通信方法大全(推荐)
2019/04/15 Javascript
vue实现购物车结算功能
2020/06/18 Javascript
python计算最大优先级队列实例
2013/12/18 Python
Python实现XML文件解析的示例代码
2018/02/05 Python
python 获得任意路径下的文件及其根目录的方法
2019/02/16 Python
Python集中化管理平台Ansible介绍与YAML简介
2019/06/12 Python
关于Python内存分配时的小秘密分享
2019/09/05 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
2019/10/21 Python
python中删除某个元素的方法解析
2019/11/05 Python
Python中BeautifuSoup库的用法使用详解
2019/11/15 Python
torch 中各种图像格式转换的实现方法
2019/12/26 Python
Python类成员继承重写的实现
2020/09/16 Python
python日志通过不同的等级打印不同的颜色(示例代码)
2021/01/13 Python
python自动生成证件号的方法示例
2021/01/14 Python
h5移动端调用支付宝、微信支付的实现
2020/06/08 HTML / CSS
Html5移动端网页端适配(js+rem)
2021/02/03 HTML / CSS
面试自我评价范文
2014/09/17 职场文书
Python正则表达式中flags参数的实例详解
2022/04/01 Python