PHP SPL他们留下的宝石
Rafael Dohms 上面的篇文章 让我为之惊艳,忍不住就翻译了下来,同一时候补充了部分内容。
SPL,PHP 标准库(Standard PHP Library) ,此从 PHP 5.0 起内置的组件和接口,而且从 PHP5.3 已逐渐的成熟。SPL 事实上在全部的 PHP5 开发环境中被内置,同一时候无需不论什么设置。
似乎众多的 PHP 开发者基本没有使用它,甚至闻所未闻。究其原因,能够追述到它那阳春白雪般的说明文档,使你忽略了「它的存在」。
SPL 这块宝石宛如铁达尼的「海洋之心」般,被沉入海底。而如今它应该被我们捞起。并将它穿戴在应有的位置 ,而这也是这篇文章所要表述的观点。
那么。SPL 提供了什么?
SPL 对 PHP 引擎进行了扩展,比如 ArrayAccess、Countable 和 SeekableIterator 等接口,它们用于以数组形式操作对象。同一时候,你还能够使用 RecursiveIterator、ArrayObejcts 等其它迭代器进行数据的迭代操作。
它还内置几个的对象比如 Exceptions、SplObserver、Spltorage 以及 splautoloadregister、splclasses、iteratorapply 等的帮助函数(helper functions),用于重载相应的功能。
这些工具聚合在一起就好比是把多功能的瑞士军刀,善用它们能够从质上提升 PHP 的代码效率。那么,我们怎样发挥它的威力?
重载 autoloader
假设你是位「教科书式的程序猿」,那么你保证了解怎样使用 __autoload 去取代 includes/requires 操作惰性加载相应的类,对不?
但久之,你会发现你已经陷入了困境,首先是你要保证你的类文件必须在指定的文件路径中,比如在 Zend 框架中你必须使用「_」来切割类、方法名称(你怎样解决这一问题?)。
另外的一个问题。就是当项目变得越来越复杂, __autoload 内的逻辑也会变得对应的复杂。到最后,甚至你会增加异常推断。以及将全部的加载类的逻辑如数写到当中。
大家都知道「鸡蛋不能放到一个篮子中」,利用 SPL 能够分离 __autoload 的加载逻辑。仅仅须要写个你自己的 autoload 函数,然后利用 SPL 提供的函数重载它。
比如上述 Zend 框架的问题。你能够重载 Zend loader 相应的方法。假设它没有找到相应的类。那么就使用你先前定义的函数。
<?php class MyLoader { public static function doAutoload($class) { // 本模块相应的 autoload 操作 } } spl_autoload_register( array('MyLoader', 'doAutoload') ); ?>
正如你所见, spl autoload register 还能以数组的形式增加多个加载逻辑。
同一时候,你还能够利用spl autoload unregister 移除已经不再须要的加载逻辑。这功能总会用到的。
迭代器
迭代是常见设计模式之中的一个,普遍应用于一组数据中的统一的遍历操作。
能够毫不夸张的说,SPL 提供了全部你须要的相应数据类型的迭代器。
有个很好的案例就是遍历文件夹。常规的做法就是使用 scandir 。然后跳过「.「 和 「..」。以及其他未满足条件的文件。
比如你须要遍历个某个文件夹抽取当中的图片文件,就须要推断是否是 jpg、gif 结尾。
以下的代码就是使用 SPL 的迭代器运行上述递归寻找指定文件夹中的图片文件的样例:
<?php class RecursiveFileFilterIterator extends FilterIterator { // 满足条件的扩展名 protected $ext = array('jpg','gif'); /** * 提供 $path 并生成相应的文件夹迭代器 */ public function __construct($path) { parent::__construct(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path))); } /** * 检查文件扩展名是否满足条件 */ public function accept() { $item = $this->getInnerIterator(); if ($item->isFile() && in_array(pathinfo($item->getFilename(), PATHINFO_EXTENSION), $this->ext)) { return TRUE; } } } // 实例化 foreach (new RecursiveFileFilterIterator('/path/to/something') as $item) { echo $item . PHP_EOL; } ?>
你可能会说,这不是花了很多其它的代码去办同一件事情吗?那么,查看上面的代码,你不是拥有了具有高度重用并且能够測试的代码了吗 :)
以下是 SPL 提供的其它的迭代器:
- RecursiveIterator
- RecursiveIteratorIterator
- OuterIterator
- IteratorIterator
- FilterIterator
- RecursiveFilterIterator
- ParentIterator
- SeekableIterator
- LimitIterator
- GlobIterator
- CachingIterator
- RecursiveCachingIterator
- NoRewindIterator
- AppendIterator
- RecursiveIteratorIterator
- InfiniteIterator
- RegexIterator
- RecursiveRegexIterator
- EmptyIterator
- RecursiveTreeIterator
- ArrayIterator
自 PHP5.3 開始。会内置其它很多其它的迭代器,我想你都能够尝试下。也许它能改变你编写传统代码的习惯。
SplFixedArray
SPL 还内置了一系列的数组操作工具。比如能够使用 SplFixedArray 实例化一个固定长度的数组。那么为什么要使用它?由于它更快。甚至它关系着你的工资问题 :)
我们知道 PHP 常规的数组包括不同类型的键。比如数字、字符串等,而且长度是可变的。
正是由于这些「高级功能」,PHP 以散列(hash)的方式通过键得到相应的值 -- 事实上这在特定情况这会造成性能问题。
而 SplFixedArray 由于是使用固定的数字键。所以它并没有使用散列存储方式。不确切的说,甚至你能够觉得它就是个 C 数组。这就是为什么 SplFixedArray 会比通常数组要快的原因(仅在 PHP5.3 中)。
那究竟有多快呢。以下的组数据能够让你窥其究竟。
假设你须要大量的数组操作,那么你能够尝试下,相信它是值得信赖的。
数据结构
同一时候 SPL 还提供了些数据结构基本类型的实现 。尽管我们能够使用传统的变量类型来描写叙述数据结构。比如用数组来描写叙述堆栈(Strack)-- 然后使用相应的方式 pop 和 push(arraypop()、arraypush())。但你得时刻小心。·由于毕竟它们不是专门用于描写叙述数据结构的 -- 一次误操作就有可能破坏该堆栈。
而 SPL 的 SplStack 对象则严格以堆栈的形式描写叙述数据,并提供相应的方法。同一时候,这种代码应该也能理解它在操作堆栈而非某个数组,从而能让你的同伴更好的理解相应的代码,而且它更快。
最后,可能上述那些慘白的样例还不足矣「诱惑你」去使用 SPL。
实践出真知,SPL 很多其它、更强大的功能须要你自我们不得不挖。它慢慢宝石般掉漆。散发着灿烂的能力。
版权声明:本文博客原创文章。博客,未经同意,不得转载。