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


·        作者Laruence(   )

·        本文地址http://www.laruence.com/2009/04/24/695.html

·        转载请注明出处

我看到过很多人操作数组的时候, 对于数组中的非数字键名不使用引号,

1.         $array[key] = $value;

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

1.       error_reporting = ~E_NOTICE

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

, 我们一起来看看:

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.    ?>

分别看运行时间(多次平均时间):
加引号的:

1.       $ time php -f good.php

2.        

3.       real    0m0.013s

4.       user    0m0.005s

5.       sys     0m0.007s

不加引号的:

1.       $ time php -f bad.php

2.        

3.       PHP Notice:  Use ofundefined constant bad - assumed 'bad' in /home/huixinchen/tmp/bad.php

4.       on line (此处省略999NOTICE)

5.       real    0m0.100s

6.       user    0m0.020s

7.       sys     0m0.029s

看看,差别有多大?
, 或许我们应该模拟一下那些幸运的人们的情况, 去掉花费在记录NOTICE的开销, 看看~

1.       $ time php -f bad.php

2.        

3.       real    0m0.037s

4.       user    0m0.018s

5.       sys     0m0.018s

我们可以看出, 基本上, 使用引号,和不使用引号的效率损失在3倍以上

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

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

good.php:

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:

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                                                  1

16.            11*ZEND_HANDLE_EXCEPTION

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

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

1.       define('key_name' , 'laruence');

2.       ....

3.       //省略很多行代码

4.       $array[key_name] = 2;//变成了 $array['laruence'] = 2;

5.       //这样的错误, 你会很郁闷吧?

明白了么? 数组中的非数字键的键名一定要有引号啊~
, 还记得有人会说, 那在字符串变量替换的时候,写引号会导致错误,
, 标准写法:

1.       $string = "variable value is {$array['key']}"

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

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

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

1.       ....

2.       if (!zend_get_constant(opline->op2.u.constant.value.str.val,

3.            opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {

4.              zend_error(E_NOTICE, "Use of undefined constant %s - assumed'%s'",

5.                       opline->op2.u.constant.value.str.val,

6.                       opline->op2.u.constant.value.str.val);

7.              EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;//获取"常量"名字符串

8.              zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);//分配空间,生成字符串

9.       }

10.    ....

内容概要:该论文研究增程式电动汽车(REEV)的能量管理策略,针对现有优化策略实时性差的问题,提出基于工况识别的自适应等效燃油消耗最小策略(A-ECMS)。首先建立整车Simulink模型和基于规则的策略;然后研究动态规划(DP)算法和等效燃油最小策略;接着通过聚类分析将道路工况分为四类,并设计工况识别算法;最后开发基于工况识别的A-ECMS,通过高德地图预判工况类型并自适应调整SOC分配。仿真显示该策略比规则策略节油8%,比简单SOC规划策略节油2%,并通过硬件在环实验验证了实时可行性。 适合人群:具备一定编程基础,特别是对电动汽车能量管理策略有兴趣的研发人员和技术爱好者。 使用场景及目标:①理解增程式电动汽车能量管理策略的基本原理;②掌握动态规划算法和等效燃油消耗最小策略的应用;③学习工况识别算法的设计和实现;④了解基于工况识别的A-ECMS策略的具体实现及其优化效果。 其他说明:此资源不仅提供了详细的MATLAB/Simulink代码实现,还深入分析了各算法的原理和应用场景,适合用于学术研究和工业实践。在学习过程中,建议结合代码调试和实际数据进行实践,以便更好地理解策略的优化效果。此外,论文还探讨了未来的研究方向,如深度学习替代聚类、多目标优化以及V2X集成等,为后续研究提供了思路。
内容概要:论文《基于KANN-DBSCAN带宽优化的核密度估计载荷谱外推》针对传统核密度估计(KDE)载荷外推中使用全局固定带宽的局限性,提出了一种基于改进的K平均最近邻DBSCAN(KANN-DBSCAN)聚类算法优化带宽选择的核密度估计方法。该方法通过对载荷数据进行KANN-DBSCAN聚类分组,采用拇指法(ROT)计算各簇最优带宽,再进行核密度估计和蒙特卡洛模拟外推。实验以电动汽车实测载荷数据为对象,通过统计参数、拟合度和伪损伤三个指标验证了该方法的有效性,误差显著降低,拟合度R²>0.99,伪损伤接近1。 适合人群:具备一定编程基础和载荷数据分析经验的研究人员、工程师,尤其是从事汽车工程、机械工程等领域的工作1-5年研发人员。 使用场景及目标:①用于电动汽车载荷谱编制,提高载荷预测的准确性;②应用于机械零部件的载荷外推,特别是对称载荷分布和多峰扭矩载荷;③实现智能网联汽车载荷预测与数字孪生集成,提供动态更新的载荷预测系统。 其他说明:该方法不仅解决了传统KDE方法在复杂工况下的“过平滑”与“欠拟合”问题,还通过自适应参数机制提高了方法的普适性和计算效率。实际应用中,建议结合MATLAB代码实现,确保数据质量,优化参数并通过伪损伤误差等指标进行验证。此外,该方法可扩展至风电装备、航空结构健康监测等多个领域,未来研究方向包括高维载荷扩展、实时外推和多物理场耦合等。
<think>我们有一个Python字典`can_signal_receive_cfg_c_header`,它的键是字符串形式的数字(如"0"、"1"等),值是对应的C代码行或注释。这个字典的目的是按顺序构建一个C语言文件的头部,包括文件注释和头文件包含部分。字典中的每个键值对代表C文件中的一行(键表示行号,值表示该行的内容)。下面我们逐一解释每个键值对的作用:1. `"0":"/*"`:这是C语言多行注释的开始符号。2. `"1":" *@Author: bydong bydong@iflytek.com"`:注释行,说明作者信息。3.`"2":"* @Date:" +current_time`:注释行,显示文件创建日期,其中`current_time`是一个变量,表示当前时间。4. `"3":" *@LastEditors: bydong bydong@iflytek.com"`:注释行,最后编辑者的信息。5.`"4":"* @LastEditTime:" +current_time`:注释行,最后编辑时间,同样使用`current_time`。6.注意:键"5"和"6"之间没有"6",所以这里键"5"之后直接是键"7"。但原字典中键"5"是存在的,而键"6"缺失。7. `"5":" *@FilePath: \\App\\ASW\\audio_manager\\can_signal_deal\\can_signal_receive_cfg.c"`:注释行,表示该文件在项目中的路径。8.`"7":"* @Description:应用层Can信号音频接收处理文件(脚本生成)"`:注释行,文件描述,说明这个文件的作用。9.`"8":"* @version:2.1"`:注释行,文件版本号。 10. `"9":" */\n"`:多行注释结束符,后面的`\n`表示换行(空行)。11.`"10":"/**********************************************************************头文件包含*********************************************************************/"`:一行注释,用于分隔并说明接下来是头文件包含部分。12.`"11":"/****************************************************************************************************************************************************/"`:一行装饰性注释,与上一行配合,形成注释块。13.`"12":"#include\"ccl_par.h\""`:包含头文件`ccl_par.h`。14.`"13":"#include\"il_par.h\""`:包含头文件`il_par.h`。 15. `"14":"#include \"Platform_Types.h\""`:包含平台相关的类型定义头文件。 16. `"15":"#include \"audio_ctrl_cfg.h\""`:包含音频控制配置头文件。17.`"16":"#include\"can_signal_send_cfg.h\""`:包含CAN信号发送配置头文件。 18. `"17":"#include \"can_signal_receive_cfg.h\""`:包含本文件对应的头文件(即`can_signal_receive_cfg.h`)。19.`"18":"\n/********************************************************************变量、宏、结构体定义**************************************************************/"`:换行后开始一个注释块,说明接下来是变量、宏和结构体定义部分。 20. `"19":"/****************************************************************************************************************************************************/\n"`:装饰性注释,与上一行配合,并换行。注意:原字典中缺少键"6",所以从"5"直接跳到了"7"。这可能是原代码的笔误,或者故意为之(例如,跳过一行)。但是,在生成文件时,我们通常希望行号是连续的,所以这里可能需要注意。这个字典的作用是生成C文件的开头部分,包括:-文件注释(作者、日期、描述等)-包含必要的头文件-为后续的变量、宏和结构体定义提供分隔注释在生成文件时,我们可以按照键的数字顺序(注意,键是字符串,但内容都是数字)将值写入文件,从而形成C文件的开头部分。另外,注意到在键"9"的值中有一个换行符`\n`,键"18"的值以`\n`开头,这些都是为了在生成的C文件中形成空行,使结构清晰。总结:这个字典实际上是一个模板,用于生成C语言源文件的头部信息,包括注释和头文件包含。通过按顺序拼接这些值,就可以得到完整的文件头部。§§相关问题§§1.在C语言文件头注释中,常见的元数据标签(如@Author,@Date)有哪些?分别代表什么含义? 2.为什么在包含头文件时使用双引号`""`而不是尖括号`<>`?3.如何通过Python脚本自动生成这样的C文件头部?</think>### Python字典`can_signal_receive_cfg_c_header`解析 该字典用于**自动生成C语言源文件的头部结构**,包含文件注释、作者信息、头文件包含等关键部分。以下是逐行解析: #### 文件注释部分(键0-9) | 键 | 值 | 作用 | |-----|----|------| | `"0"` | `"/*"` | 多行注释起始符 | | `"1"` | `" * @Author: bydong bydong@iflytek.com"` | 作者声明 | | `"2"` | `" * @Date: " + current_time` | 文件创建日期(动态插入当前时间) | | `"3"` | `" * @LastEditors: bydong bydong@iflytek.com"` | 最后编辑者 | | `"4"` | `" * @LastEditTime: " + current_time` | 最后编辑时间(动态时间) | | `"5"` | `" * @FilePath: \\App\\...\\can_signal_receive_cfg.c"` | 文件在项目中的路径 | | `"7"` | `" * @Description: 应用层Can信号音频接收处理文件(脚本生成)"` | 文件功能描述 | | `"8"` | `" * @version: 2.1"` | 文件版本号 | | `"9"` | `" */\n"` | 注释结束符并换行 | #### 头文件包含部分(键10-17) | 键 | 值 | 作用 | |-----|----|------| | `"10"` | 分隔注释 | 标识头文件区块开始 | | `"11"` | 分隔符 | 视觉分隔线 | | `"12"` | `#include "ccl_par.h"` | CAN通信层参数头文件 | | `"13"` | `#include "il_par.h"` | 交互层参数头文件 | | `"14"` | `#include "Platform_Types.h"` | 平台基础类型定义 | | `"15"` | `#include "audio_ctrl_cfg.h"` | 音频控制配置文件 | | `"16"` | `#include "can_signal_send_cfg.h"` | CAN信号发送配置文件 | | `"17"` | `#include "can_signal_receive_cfg.h"` | 当前文件对应的头文件 | #### 变量定义区(键18-19) | 键 | 值 | 作用 | |-----|----|------| | `"18"` | 分隔注释 | 标识变量/宏定义区块开始 | | `"19"` | 分隔符 | 视觉分隔线(结尾换行) | ### 关键设计特点 1. **动态内容注入** `current_time`变量实现时间戳的动态生成(如`"2"`和`"4"`键),确保每次生成文件时自动更新日期信息。 2. **结构化分区** 通过分隔注释(如`"10"`和`"18"`)将文件划分为: ```plaintext 文件注释 → 头文件包含 → 变量定义 ``` 3. **路径转义处理** `"5"`键中的双反斜杠`\\`是Windows路径的Python转义表示,实际生成C文件时会显示为`\`。 4. **版本控制** `"8"`键显式声明文件版本(`2.1`),便于追踪代码变更历史。 ### 典型应用场景 此类字典常用于**代码生成工具**中,例如: ```python # 生成C文件头部 with open("can_signal_receive_cfg.c", "w") as f: for key in sorted(can_signal_receive_cfg_c_header, key=int): f.write(can_signal_receive_cfg_c_header[key] + "\n") # 后续写入实际业务代码... ``` 通过字典键的数字顺序控制内容写入顺序,确保文件结构符合规范[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值