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


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 相关文章推荐
ip签名探针
Oct 09 PHP
使用PHP数组实现无限分类,不使用数据库,不使用递归.
Dec 09 PHP
php生成随机密码的三种方法小结
Sep 04 PHP
PHP和.net中des加解密的实现方法
Feb 27 PHP
php中通过curl检测页面是否被百度收录
Sep 27 PHP
PHP+Mysql树型结构(无限分类)数据库设计的2种方式实例
Jul 15 PHP
PHP中读取文件的8种方法和代码实例
Aug 05 PHP
php中获取主机名、协议及IP地址的方法
Nov 18 PHP
PHP针对JSON操作实例分析
Jan 12 PHP
php从csv文件读取数据并输出到网页的方法
Mar 14 PHP
PHP观察者模式示例【Laravel框架中有用到】
Jun 15 PHP
PHP利用curl发送HTTP请求的实例代码
Jul 09 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动态变量定义及使用
2015/06/10 PHP
PHP微信企业号开发之回调模式开启与用法示例
2017/11/25 PHP
TextArea 控件的最大长度问题(js json)
2009/12/16 Javascript
JavaScript Event学习第十一章 按键的检测
2010/02/10 Javascript
使用AngularJS实现可伸缩的页面切换的方法
2015/06/19 Javascript
jquery插件jquery.nicescroll实现图片无滚动条左右拖拽的方法
2015/08/10 Javascript
AngularJS使用ngOption实现下拉列表的实例代码
2016/01/23 Javascript
javaScript中的原型解析【推荐】
2016/05/05 Javascript
jQuery EasyUI框架中的Datagrid数据表格组件结构详解
2016/06/09 Javascript
使用jQuery卸载全部事件的思路详解
2017/04/03 jQuery
vue js秒转天数小时分钟秒的实例代码
2018/08/08 Javascript
详解如何在Node.js的httpServer中接收前端发送的arraybuffer数据
2018/11/11 Javascript
Vue render函数实战之实现tabs选项卡组件
2019/04/22 Javascript
微信小程序实现的五星评价功能示例
2019/04/25 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
Python 的 with 语句详解
2014/06/13 Python
Python实现扫描指定目录下的子目录及文件的方法
2014/07/16 Python
Python把csv数据写入list和字典类型的变量脚本方法
2018/06/15 Python
Sanic框架路由用法实例分析
2018/07/16 Python
简单了解python代码优化小技巧
2019/07/08 Python
python mock测试的示例
2020/10/19 Python
使用python对excel表格处理的一些小功能
2021/01/25 Python
Python用SSH连接到网络设备
2021/02/18 Python
CSS3与动画有关的属性transition、animation、transform对比(史上最全版)
2017/08/18 HTML / CSS
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
阿迪达斯芬兰官方网站:adidas芬兰
2017/01/30 全球购物
一家专门经营包包的英国网站:MyBag
2019/09/08 全球购物
大学同学十年聚会感言
2014/02/21 职场文书
国家励志奖学金个人先进事迹材料
2014/05/04 职场文书
社区先进事迹材料
2014/05/19 职场文书
企业安全生产目标责任书
2014/07/23 职场文书
小学生校园广播稿
2014/09/28 职场文书
教师个人年终总结
2015/02/11 职场文书
六一亲子活动感想
2015/08/07 职场文书
幼儿园安全教育随笔
2015/08/14 职场文书
安全生产协议书
2016/03/22 职场文书