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


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上传文件中文文件名乱码的解决方法
Nov 01 PHP
Thinkphp搭建包括JS多语言的多语言项目实现方法
Nov 24 PHP
新浪微博OAuth认证和储存的主要过程详解
Mar 27 PHP
基于php实现随机合并数组并排序(原排序)
Nov 26 PHP
thinkPHP js文件中U方法不被解析问题的解决方法
Dec 05 PHP
Windows 下安装 swoole 图文教程(php)
Jun 05 PHP
阿里云PHP SMS短信服务验证码发送方法
Jul 11 PHP
PHP数据分析引擎计算余弦相似度算法示例
Aug 08 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
Dec 21 PHP
PHP常用函数之根据生日计算年龄功能示例
Oct 21 PHP
php实现简易计算器
Aug 28 PHP
PHP 判断字符串是中文还是英文, 或者是中英混合
Mar 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的preg_match匹配字符串长度问题解决方法
2014/05/03 PHP
PHP使用strtotime获取上个月、下个月、本月的日期
2015/12/30 PHP
Laravel 5.3 学习笔记之 配置
2016/08/28 PHP
PHP基于自定义类随机生成姓名的方法示例
2017/08/05 PHP
PHP实现的随机红包算法示例
2017/08/14 PHP
PJBlog插件 防刷新的在线播放器
2006/10/25 Javascript
img的onload的另类用法
2008/01/10 Javascript
关于B/S判断浏览器断开的问题讨论
2008/10/29 Javascript
JavaScript 闭包深入理解(closure)
2009/05/27 Javascript
JQuery 学习笔记 选择器之二
2009/07/23 Javascript
Jquery对数组的操作技巧整理
2014/03/25 Javascript
jquery实现简单的自动播放幻灯片效果
2015/06/13 Javascript
JQuery和HTML5 Canvas实现弹幕效果
2017/01/04 Javascript
jquery与ajax获取特殊字符实例详解
2017/01/08 Javascript
JS操作时间 - UNIX时间戳的简单介绍(必看篇)
2017/08/16 Javascript
vue2.0 父组件给子组件传递数据的方法
2018/01/15 Javascript
Vue中 v-if/v-show/插值表达式导致闪现的原因及解决办法
2018/10/12 Javascript
解决vue-loader加载不上的问题
2020/10/21 Javascript
Python实现控制台输入密码的方法
2015/05/29 Python
详解设计模式中的工厂方法模式在Python程序中的运用
2016/03/02 Python
Python基于回溯法子集树模板解决马踏棋盘问题示例
2017/09/11 Python
详解python算法之冒泡排序
2019/03/05 Python
TensorFlow实现简单的CNN的方法
2019/07/18 Python
Python generator生成器和yield表达式详解
2019/08/08 Python
Jupyter Notebook远程登录及密码设置操作
2020/04/10 Python
Keras loss函数剖析
2020/07/06 Python
PyQt中使用QtSql连接MySql数据库的方法
2020/07/28 Python
Python字符串及文本模式方法详解
2020/09/10 Python
语文教育专业推荐信范文
2013/11/25 职场文书
文科生自我鉴定
2014/02/15 职场文书
《再见了,亲人》教学反思
2014/02/26 职场文书
2014年网管工作总结
2014/12/11 职场文书
首席执行官观后感
2015/06/03 职场文书
2016领导干部廉洁自律心得体会
2016/01/13 职场文书
Python中的np.argmin()和np.argmax()函数用法
2021/06/02 Python
排查MySQL生产环境索引没有效果
2022/04/11 MySQL