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 很多其它、更强大的功能须要你自己去挖掘。而它由于宝石般缓缓掉漆。散发着灿烂的能力。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/yxwkf/p/4642785.html