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


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 各种排序算法实现代码
Aug 20 PHP
php获取post中的json数据的实现方法
Jun 08 PHP
php中$_REQUEST、$_POST、$_GET的区别和联系小结
Nov 23 PHP
phpmyadmin显示utf8_general_ci中文乱码的问题终级篇
Apr 08 PHP
Codeigniter整合Tank Auth权限类库详解
Jun 12 PHP
linux下安装php的memcached客户端
Aug 03 PHP
微信公众平台消息接口校验与消息接口响应实例
Dec 23 PHP
php修改文件上传限制方法汇总
Apr 07 PHP
Zend Framework实现将session存储在memcache中的方法
Mar 22 PHP
PHP中PDO的事务处理分析
Apr 07 PHP
php构造方法中析构方法在继承中的表现
Apr 12 PHP
PHP对接阿里云虚拟号的实现(号码隐私保护)
Apr 06 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
Memcache 在PHP中的使用技巧
2010/02/08 PHP
关于IIS php调用com组件的权限问题
2012/01/11 PHP
php cli换行示例
2014/04/22 PHP
TP5框架实现签到功能的方法分析
2020/04/05 PHP
JavaScript入门教程(5) js Screen屏幕对象
2009/01/31 Javascript
javascript AOP 实现ajax回调函数使用比较方便
2010/11/20 Javascript
兼容FF和IE的动态table示例自写
2013/10/21 Javascript
javaScript array(数组)使用字符串作为数组下标的方法
2013/11/19 Javascript
js对字符的验证方法汇总
2015/02/04 Javascript
Bootstrap每天必学之js插件
2015/11/30 Javascript
SpringMVC restful 注解之@RequestBody进行json与object转换
2015/12/10 Javascript
全面解析Bootstrap布局组件应用
2016/02/22 Javascript
jQuery获取file控件中图片的宽高与大小
2016/08/04 Javascript
详解node.js平台下Express的session与cookie模块包的配置
2017/04/26 Javascript
JS在Array数组中按指定位置删除或添加元素对象方法示例
2019/11/19 Javascript
Jquery Fade用法详解
2020/11/06 jQuery
详解Vue.js3.0 组件是如何渲染为DOM的
2020/11/10 Javascript
python文本数据相似度的度量
2018/03/12 Python
Python之两种模式的生产者消费者模型详解
2018/10/26 Python
利用python开发app实战的方法
2019/07/09 Python
python微信公众号开发简单流程实现
2020/03/09 Python
pytorch 常用函数 max ,eq说明
2020/06/28 Python
Python实现GIF图倒放
2020/07/16 Python
Python 利用Entrez库筛选下载PubMed文献摘要的示例
2020/11/24 Python
Django与AJAX实现网页动态数据显示的示例代码
2021/02/24 Python
Europcar葡萄牙:葡萄牙汽车和货车租赁
2017/10/13 全球购物
纽约和芝加哥当天送花:Ode à la Rose
2019/07/05 全球购物
澳大利亚当地社区首选的光学商店:1001 Optical
2019/08/24 全球购物
后勤岗位职责
2013/11/26 职场文书
《白鹅》教学反思
2014/04/13 职场文书
电子商务专业自荐信
2014/06/02 职场文书
防邪知识进家庭活动方案
2014/08/26 职场文书
2015年人事专员工作总结
2015/04/29 职场文书
OpenCV-Python实现图像平滑处理操作
2021/06/08 Python
JS的深浅复制详细
2021/10/16 Javascript
MySQL图形化管理工具Navicat安装步骤
2021/12/04 MySQL