网络上充斥着各种“X个PHP代码片段”类型的文章,为什么还要再写一篇呢?原因很简单:大多数文章中的代码片段都乏善可陈。生成随机字符串或返回$_SERVER["REMOTE_ADDR"]
获取客户端IP地址之类的片段实在缺乏趣味性和实用性。本文将分享五个实用且有趣的PHP代码片段,并介绍它们背后的灵感来源。希望这些富有创意的代码片段能启发您在日常编程中编写更出色、更具创意的代码。
关键要点
fputcsv()
函数生成CSV数据、使用PSR-0标准自动加载类、使用unpack()
函数解析定长数据、使用一个简单的PHP类进行HTML模板化以及使用file_get_contents
作为cURL的替代方案来发出HTTP GET和POST请求。1. 生成CSV
我们经常看到这样的代码,试图将多维数组数据转换为CSV:
<?php $csv = ""; foreach ($data as $row) { $csv .= join(",", $row) . "\n"; } echo $csv; ?>
问题在于各个元素没有正确转义,单个值中包含引号或逗号都可能导致后续解析CSV数据时出错。最好使用内置的fputcsv()
函数;它的实现是用C代码编写的,因此执行速度更快,并且会为您处理必要的引用/转义。以下代码封装了从数据数组构造CSV输出的逻辑。它包含可选参数,允许使用标题列,以及是否将CSV直接刷新到浏览器或将输出作为字符串返回。其巧妙之处在于将流与fputcsv()
一起使用,因为该函数需要打开的文件句柄才能操作。
<?php function toCSV(array $data, array $colHeaders = array(), $asString = false) { $stream = ($asString) ? fopen("php://temp/maxmemory", "w+") : fopen("php://output", "w"); if (!empty($colHeaders)) { fputcsv($stream, $colHeaders); } foreach ($data as $record) { fputcsv($stream, $record); } if ($asString) { rewind($stream); $returnVal = stream_get_contents($stream); fclose($stream); return $returnVal; } else { fclose($stream); } } ?>
有了toCSV()
函数,生成CSV变得简单且可靠。
2. 自动加载类
自动加载类文件很常见,但您可能不喜欢各种PHP框架提供的那些臃肿、重量级的自动加载器,或者您可能只是喜欢自己编写解决方案。幸运的是,您可以编写自己的最小加载器,并且仍然符合PHP标准工作组采用的PSR-0标准,我曾在自己的博客上首次演示了这一点。该标准并未描述PSR-0兼容的自动加载器必须提供的支持功能(注册方法、配置选项等)。如果它能够自动在<vendor name>(<namespace>)
模式中找到类定义,那么它就是PSR-0兼容的。此外,它没有指定<vendor name>
的父目录。大多数自动加载器实现的额外“填充”如果您需要通过代码指定位置则很方便,但如果您只是使用PHP的include路径中已有的目录,则没有必要。
<?php $csv = ""; foreach ($data as $row) { $csv .= join(",", $row) . "\n"; } echo $csv; ?>
这里的巧妙之处在于正则表达式,它将传入的名称拆分为其组成部分;类名始终位于$match[2]
中,$match[1]
是命名空间名称,它可能是空字符串。必须识别这些部分,因为下划线在命名空间部分中没有任何特殊含义,因此对下划线和反斜杠进行盲目替换是不正确的。
3. 使用unpack()解析定长数据
在当今充斥着XML和JSON的现代世界中,您可能会认为定长格式已经灭绝……但您错了。仍然存在大量的定长数据,例如某些日志条目、MARC 21(书目信息)、NACHA(财务信息)等。老实说,我对定长数据仍然情有独钟。
在C等语言中,定长数据相对容易处理,因为数据一旦加载到内存中,就会与访问数据结构完美对齐。但是对于某些人来说,在PHP等动态语言中处理定长数据可能是一场斗争;该语言的松散类型使得这种内存访问变得不可能。因此,我们经常看到这样的代码:
<?php function toCSV(array $data, array $colHeaders = array(), $asString = false) { $stream = ($asString) ? fopen("php://temp/maxmemory", "w+") : fopen("php://output", "w"); if (!empty($colHeaders)) { fputcsv($stream, $colHeaders); } foreach ($data as $record) { fputcsv($stream, $record); } if ($asString) { rewind($stream); $returnVal = stream_get_contents($stream); fclose($stream); return $returnVal; } else { fclose($stream); } } ?>
您可能感到不适。没关系,我也不想在我的应用程序中使用这样的代码!它冗长且索引容易出错。幸运的是,有一个更好的替代方案:unpack()
。
PHP手册中unpack()
的文档指出:“根据给定的格式将二进制字符串解包到数组中”,并显示了使用二进制数据转义的用法示例。可能并非立即显而易见的是,由于格式说明符“A”表示字符(毕竟,字符串不只是一系列位和字节吗?),因此该函数可用于解析定长字符串。
使用unpack()
,上述示例可以更优雅地改写如下:
<?php spl_autoload_register(function ($classname) { $classname = ltrim($classname, "\"); preg_match('/^(.+)?([^\]+)$/U', $classname, $match); $classname = str_replace("\", "/", $match[1]) . str_replace(["\", "_"], "/", $match[2]) . ".php"; include_once $classname; }); ?>
在这种情况下,格式字符串只是一系列A,指定字符数据、特定字段的字符数以及检索到的数据将在最终数组中分配的键名,用斜杠分隔。例如,A6date
会解析出6个字符,并将其作为$header["date"]
提供。
4. HTML模板化
在PHP社区中,关于模板化一直没有达成太多共识。我们都同意将HTML和PHP分开是可取的,但在使用Smarty或Twig等模板库的适用性上存在冲突。一些人指出PHP本身就是一个模板引擎,并反对库的速度、语法等。其他人声称从使用模板系统提供的DSL中获益匪浅。一种折衷方案是使用用PHP编写的非常小的类来模板化您的HTML以保持代码简洁。
<?php $csv = ""; foreach ($data as $row) { $csv .= join(",", $row) . "\n"; } echo $csv; ?>
它不是一个成熟的模板引擎;而是一个简洁的辅助类,充当“存储桶”,收集键/值数据对,您可以在指定为模板的包含文件中访问这些数据对。首先,您在视图中创建一个Template
类的实例,可以选择传递一个目录名称来查找后续的模板文件(允许您对相关文件进行分组)。然后,将应填充模板的值提供给set()
方法或作为裸属性。一旦指定所有值,您就可以调用out()
方法来呈现模板。
<?php function toCSV(array $data, array $colHeaders = array(), $asString = false) { $stream = ($asString) ? fopen("php://temp/maxmemory", "w+") : fopen("php://output", "w"); if (!empty($colHeaders)) { fputcsv($stream, $colHeaders); } foreach ($data as $record) { fputcsv($stream, $record); } if ($asString) { rewind($stream); $returnVal = stream_get_contents($stream); fclose($stream); return $returnVal; } else { fclose($stream); } } ?>
示例的mytemplate.php
文件可能如下所示:
<?php spl_autoload_register(function ($classname) { $classname = ltrim($classname, "\"); preg_match('/^(.+)?([^\]+)$/U', $classname, $match); $classname = str_replace("\", "/", $match[1]) . str_replace(["\", "_"], "/", $match[2]) . ".php"; include_once $classname; }); ?>
在模板文件中,您可以访问PHP功能的全部范围,以根据需要格式化值、过滤值等。
out()
的第二个可选参数可以指定将模板内容作为字符串返回,而不是直接将其刷新到浏览器,您可以利用它来用先前填充的模板的结果替换一个模板中的占位符。
5. 使用file_get_contents作为cURL的替代方案
cURL是一个用于通过各种协议进行通信的强大库。它确实功能非常强大,有时没有其他方法可以做到。如果您明确需要cURL公开的功能来完成您的任务,那么请使用cURL!但是,PHP中日常cURL使用的大部分内容都围绕发出HTTP GET和POST请求,这可以使用PHP内置函数轻松完成。
依赖cURL发出HTTP请求的问题有两个:1)即使是最简单的交易,也经常需要设置许多选项,以及2)它是一个扩展,根据您的托管和安装情况,它可能可用也可能不可用;它是一个常见的扩展,但默认情况下未启用。
file_get_contents()
和stream_context_create()
是自4.3版本以来一直可用的两个原生PHP函数。结合使用,它们可以执行许多与cURL通常执行的相同类型的请求。
对于基本的GET请求,可以使用file_get_contents()
本身:
<?php // 解析NACHA报头记录 $row = fread($fp, 94); $header = array(); $header["type"] = substr($row, 0, 1); $header["priority"] = substr($row, 1, 2); $header["immDest"] = substr($row, 3, 10); $header["immOrigin"] = substr($row, 13, 10); $header["date"] = substr($row, 23, 6); $header["time"] = substr($row, 29, 4); $header["sequence"] = substr($row, 33, 1); $header["size"] = substr($row, 34, 3); $header["blockFactor"] = substr($row, 37, 2); $header["format"] = substr($row, 39, 1); $header["destName"] = substr($row, 40, 23); $header["originName"] = substr($row, 63, 23); $header["reference"] = substr($row, 86, 8); print_r($header); ?>
对于需要指定HTTP标头的请求(无论是GET还是其他任何HTTP方法),您可以通过将一个特殊键控数组传递给stream_context_create()
来创建一个上下文,然后将上下文传递给file_get_contents()
。
<?php // 解析NACHA报头记录 $row = fread($fp, 94); $header = unpack("A1type/A2priority/A10immDest/A10immOrigin/" . "A6date/A4time/A1sequence/A3size/A2blockFactor/A1format/" . "A23destName/A23originName/A8reference", $row); print_r($header); ?>
上面的示例显示了通过POST上传文件,上下文数组使用键“method”、“header”和“content”指定事务所需的信
息。
当将file_get_contents()
用于复杂的请求(例如文件上传)时,首先创建一个模拟Web表单并通过启用了firebug的Firefox或类似工具运行它,然后检查请求中包含的内容可能会有所帮助。从那里您可以推断出要包含的重要标头元素。
总结
希望您觉得本文中介绍的代码片段很有趣。它们展示了创造性的问题解决方法以及将PHP的内置功能用于新的效果。我希望您发现它们有用且鼓舞人心。如果您有自己鼓舞人心的代码片段,请随时在下面的评论中分享。
(图片来自Fotolia)
(关于PHP代码片段的常见问题)
(此处省略了FAQ部分,因为原文FAQ部分内容与代码片段本身关系不大,属于补充说明,可以根据实际需求自行添加或修改。)
以上是PHP主| 5启发性(有用)PHP片段的详细内容。更多信息请关注PHP中文网其他相关文章!