手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆

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

首页 > PHP >

风雪之隅的网站上大多是对PHP的底层进行关注的文章,如果对PHP的核心内容有兴趣不妨多翻阅一下他的网站。

本文的标题,其实是一个老问题了。
大家都知道,PHP对于没有引号的字符串,会当成常量来处理,如果该常量不存在,则直接输出该字符串。也就是多做了几步处理。
事实上,上面的这个知识点,很早就知道,但,不是我自己研究出来的。虽然自己写过代码进行测试过。

雪候鸟则直接从OPCODE上进行查看,给你一个直观印象。好,我们来看看原文吧
地址:http://www.laruence.com/2009/04/24/695.html
内容:
我看到过很多人操作数组的时候, 对于数组中的非数字键名不使用引号,

PHP代码
  1. $array[key] = $value;  

我可以理解有些人可能会觉得这样的代码很”整洁”, 并且也能正常执行.
更甚至,如果他很”幸运的”php配置的好:

PHP代码
  1. error_reporting = ~E_NOTICE  

他也许永远都沉浸在自己的”整洁”风格中, 看不到任何的NOTICE提示, 也不会意识到, 他这么做, 能损失多少的性能~

来, 我们一起来看看:

PHP代码
  1. good.php:  
  2. <?php  
  3.    $array = array();  
  4.    $i = 0;  
  5.    while(++$i < 1000){  
  6.        $array['good'] = 2;  
  7.    }  
  8. ?>  
  9.    
  10. bad.php:  
  11. <?php  
  12.    $array = array();  
  13.    $i = 0;  
  14.    while(++$i < 1000){  
  15.        $array[good] = 2;  
  16.    }  
  17. ?>  
分别看运行时间(多次平均时间):
加引号的:

XML/HTML代码
  1. $ time php -f good.php  
  2.   
  3. real    0m0.013s  
  4. user    0m0.005s  
  5. sys     0m0.007s  
不加引号的:

XML/HTML代码
  1. $ time php -f bad.php  
  2.   
  3. PHP Notice:  Use of undefined constant bad - assumed 'bad' in /home/huixinchen/tmp/bad.php on line  
  4. (此处省略999行NOTICE)  
  5. real    0m0.100s  
  6. user    0m0.020s  
  7. sys     0m0.029s  
看看,差别有多大?
哦, 或许我们应该模拟一下那些”幸运的”人们的情况, 去掉花费在记录NOTICE的开销, 看看~

XML/HTML代码
  1. $ time php -f bad.php  
  2.   
  3. real    0m0.037s  
  4. user    0m0.018s  
  5. sys     0m0.018s  
我们可以看出, 基本上, 使用引号,和不使用引号的效率损失在3倍以上

那么, 这些效率损失到哪里去了呢?

我们分别看下, 俩个文件生成的OPCODE序列:

good.php :

C++代码
  1. filename:       /home/huixinchen/tmp/good.php  
  2. compiled vars:  !0 = $array, !1 = $i  
  3. line     #  op                           fetch          ext  return  operands  
  4. -------------------------------------------------------------------------------  
  5.    2     0  INIT_ARRAY                                       ~0  
  6.          1  ASSIGN                                                   !0, ~0  
  7.    3     2  ASSIGN                                                   !1, 0  
  8.    4     3  PRE_INC                                          $3      !1  
  9.          4  IS_SMALLER                                       ~4      $3, 1000  
  10.          5  JMPZ                                                     ~4, ->9  
  11.    5     6  ZEND_ASSIGN_DIM                                          !0, 'good'  
  12.          7  ZEND_OP_DATA                                             2, $6  
  13.    6     8  JMP                                                      ->3  
  14.    8     9  RETURN                                                   1  
  15.         10* ZEND_HANDLE_EXCEPTION  
bad.php :
C++代码
  1. filename:       /home/huixinchen/tmp/bad.php  
  2. compiled vars:  !0 = $array, !1 = $i  
  3. line     #  op                           fetch          ext  return  operands  
  4. -------------------------------------------------------------------------------  
  5.    2     0  INIT_ARRAY                                       ~0  
  6.          1  ASSIGN                                                   !0, ~0  
  7.    3     2  ASSIGN                                                   !1, 0  
  8.    4     3  PRE_INC                                          $3      !1  
  9.          4  IS_SMALLER                                       ~4      $3, 1000  
  10.          5  JMPZ                                                     ~4, ->10  
  11.    5     6  FETCH_CONSTANT                                   ~5      'bad'  
  12.          7  ZEND_ASSIGN_DIM                                          !0, ~5  
  13.          8  ZEND_OP_DATA                                             2, $7  
  14.    6     9  JMP                                                      ->3  
  15.    8    10  RETURN   

我们可以看出(其实,根据NOTICE的提示也知道), PHP会把没有引号引起来的键名当作是常量去获取, 当找不到的时候, 抛出一个NOTICE, 然后再根据”常量明”生成一个字符串, 然后再讲这个字符串做为键名继续~

聪明的你一定会想到, 可能会出现如下不可预期的错误:

PHP代码
  1. define('key_name' , 'laruence');  
  2. ....  
  3. //省略很多行代码  
  4. $array[key_name] = 2; //变成了 $array['laruence'] = 2;  
  5. //这样的错误, 你会很郁闷吧?  
明白了么? 数组中的非数字键的键名一定要有引号啊~
哦, 还记得有人会说, 那在字符串变量替换的时候, 写引号会导致错误,
恩, 标准写法:
PHP代码
  1. $string = "variable value is {$array['key']}"  

我很赞同:”be lazy”, 但是, lazy也是应该有原则的.

最后, 好的代码,不应该通过关闭error_reporting来伪装.

附注, FETCH_CONSTANT OPCODE中找不到常量的相关逻辑:

C++代码
  1. ....  
  2.         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)) {  
  3.             zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",  
  4.                         opline->op2.u.constant.value.str.val,  
  5.                         opline->op2.u.constant.value.str.val);  
  6.             EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;//获取"常量"名字符串  
  7.             zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);//分配空间,生成字符串  
  8.         }  
  9. ....  

 

 

——EOF——

膘叔最受不了的,就是discuz,特别是模版中的变量,全部是不含单引号的。写起来是方便啊。但是性能不敢恭维。所以common.inc.php的前面几句就是error_reporting了。。隐藏掉,看你怎么办,有本事你咬我呀。。

我还能怎么办?




本站采用创作共享版权协议, 要求署名、非商业和保持一致. 本站欢迎任何非商业应用的转载, 但须注明出自"易栈网-膘叔", 保留原始链接, 此外还必须标注原文标题和链接.

Tags: 风雪之隅, 细节

« 上一篇 | 下一篇 »

只显示10条记录相关文章

PHP调试技术手册发布 (浏览: 20324, 评论: 1)
客户端和服务端的编码“陷阱” (浏览: 19068, 评论: 0)
杂谈 (浏览: 18728, 评论: 2)

1条记录访客评论

phpwind也是这样
不知道论坛为什么都这样做

Post by ryl on 2009, May 12, 4:16 PM 引用此文发表评论 #1


发表评论

评论内容 (必填):