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


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执行速率优化技巧小结
Mar 15 PHP
php删除页面记录 同时刷新页面 删除条件用GET方式获得
Jan 10 PHP
PHP中call_user_func_array()函数的用法演示
Feb 05 PHP
PHP实现邮件群发的源码
Jun 18 PHP
详解PHP序列化反序列化的方法
Oct 27 PHP
解决ThinkPHP下使用上传插件Uploadify浏览器firefox报302错误的方法
Dec 18 PHP
PHP数组函数知识汇总
May 12 PHP
CodeIgniter记录错误日志的方法全面总结
May 17 PHP
php readfile下载大文件失败的解决方法
May 22 PHP
php微信公众号开发之二级菜单
Oct 20 PHP
PHP常用函数之格式化时间操作示例
Oct 21 PHP
PHP实现chrome表单请求数据转换为接口使用的json数据
Mar 04 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 提速工具eAccelerator 配置参数详解
2010/05/16 PHP
php四种基础算法代码实例
2013/10/29 PHP
实现获取http内容的php函数分享
2014/02/16 PHP
Yii列表定义与使用分页方法小结(3种方法)
2016/07/15 PHP
PHP入门教程之自定义函数用法详解(创建,调用,变量,参数,返回值等)
2016/09/11 PHP
CI框架表单验证实例详解
2016/11/21 PHP
详解yii2使用多个数据库的案例
2017/06/16 PHP
PHP基于Closure类创建匿名函数的方法详解
2017/08/17 PHP
使用JS操作页面表格,元素的一些技巧
2007/02/02 Javascript
jquery 实现的全选和反选
2009/04/15 Javascript
jquery下onpropertychange事件的绑定方法
2010/08/01 Javascript
JavaScript高级程序设计阅读笔记(六) ECMAScript中的运算符(二)
2012/02/27 Javascript
用Javascript来生成ftp脚本的小例子
2013/07/03 Javascript
很实用的js选项卡切换效果
2016/08/12 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
2017/03/30 jQuery
Javascript 严格模式use strict详解
2017/09/16 Javascript
Vue实现导出excel表格功能
2018/03/30 Javascript
Vue唯一可以更改vuex实例中state数据状态的属性对象Mutation的讲解
2019/01/18 Javascript
一个超级简单的python web程序
2014/09/11 Python
python实现文件路径和url相互转换的方法
2015/07/06 Python
Python画图学习入门教程
2016/07/01 Python
python opencv 图像尺寸变换方法
2018/04/02 Python
python 字符串追加实例
2019/07/20 Python
python selenium爬取斗鱼所有直播房间信息过程详解
2019/08/09 Python
Python包,__init__.py功能与用法分析
2020/01/07 Python
python批量处理txt文件的实例代码
2020/01/13 Python
python 操作excel表格的方法
2020/12/05 Python
OpenCV+Python3.5 简易手势识别的实现
2020/12/21 Python
CSS实现圆形放大镜狙击镜效果 只有圆圈里的放大
2012/12/10 HTML / CSS
canvas如何实现多张图片编辑的图片编辑器
2020/03/10 HTML / CSS
预订从美国飞往印度的机票:MyTicketsToIndia
2017/05/19 全球购物
买卖正宗运动鞋:GOAT
2019/12/06 全球购物
重阳节登山活动方案
2014/02/03 职场文书
经典而简洁的婚礼主持词
2014/03/13 职场文书
电影建国大业观后感
2015/06/01 职场文书
分享几种python 变量合并方法
2022/03/20 Python