Day 9805 看似好用的PHP字母循环

最近给单位写了一个内网用的工资条查询页面,结构很简单:财务人员将从集团财务系统中导出的Excel表格上传,处理后为每位员工建立账户(当然已存在的不会重建,重名的也有处理方案,因为和主题无关不详细展开),建立对应年月数据表并填充数据,员工使用账号密码登录后可查看自己的「电子工资条」。做这个东西的初衷据说是财务不愿意打印纸质工资条了,ft。

整套程序中其他部分都是基本的PHP+MySQL流程,唯独如何对Excel表处理是个难点,必须要感谢PHPExcel,使得读取Excel表格不再是最困难的部分。在编写表格读取代码的过程中,还发现了PHP一个有趣的特性:

  在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中 $a = ‘Z’; $a++; 将把 $a 变成’AA’,而在 C 中,a = ‘Z’; a++; 将把 a 变成 ‘[‘(’Z’ 的 ASCII 值是 90,'[‘ 的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。

——PHP文档《递增/递减运算符》

也就是说,如果要以列为单位递增读取表格中的内容,无需手工编写代码处理列名称(Excel的列名称是A、B、C……AA、AB、AC……XFD之类,不同版本的Excel末列名称不同,但都是1-3个字母的顺序组合),只需要使用类似下面的代码即可:

……
for($col = 'A'; $col < 'ZZ'; $col++) {
$phpExcel_Sheet -> getCell($col.$row);
}
……

一番努力后,程序已可以正确处理财务部早先给出的样表,但是由于本单位的特殊情况,还有另一套工资表要处理,这个版本的工资表格式上与先前的样表无异,只是工资项目比较多,即:先前的样表最大到Z列,而另一版本的最大列为AW。

由于PHP没有简便的方式将关联数组按索引进行读取(话说为啥不支持?),程序中拼合最终入库的数据时是这样处理的:

……
$lastcol = array_keys($xls_itemname)[sizeof($gz_itemname)-1]; //获取末列Key
foreach($xls_data as $data_row) {
for($col = 'E'; $col < $lastcol; $col++) {
$json_array[$xls_itemname[$col]] = $data_row[$col]; //为生成类似 {'基本工资':'800.00', '岗位薪酬':'1000.00',...}这样的JSON做准备
}
$json = json_encode($json_array);
……
}
……

结果,以上代码在处理第一批样表(末列为Z)时工作良好;但到了第二批样表,上传后直接运行超时,将debug信息打印出来,发现虽然$lastcol的值正确取到了AW,但程序在处理到AW列后并未停止,一路飙到了不知道哪里去,直到达到PHP的最大运行时间被掐断为止。

调试了很久都不知所措,最后只好用另一种方式进行临时补救:

……
//不再取$lastcol
foreach($xls_data as $data_row) {
for($col = 'E'; $col < 'ZZ'; $col++) {
if(isset($xls_itemname[$col]) == FALSE) break; //当取到未定义的列名时跳出
……
}
}
……

这种方法的运行效率想必比较低,但是至少可以正常运行。

猜测与PHP特殊的字母递增运算的实现有关系,但是我还是不知道为什么。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

 剩余字数 ( Characters available )

Your comment will be available after auditing.
您的评论将在通过审核后显示。

Please DO NOT add any links in your comment, otherwise it would be identified as SPAM automatically and never be audited.
请不要在评论中插入任何链接,否则将被自动归类为垃圾评论,且永远不会被提交给博主进行复审。

*