PHP SPL 被遗落的宝石【SPL应用浅析】


Posted in PHP onApril 20, 2018

本文实例讲述了PHP SPL应用方法。分享给大家供大家参考,具体如下:

Rafael Dohms 上面的篇文章 让我为之惊艳,忍不住就翻译了下来,同时补充了部分内容。

SPL,PHP 标准库(Standard PHP Library) ,从 PHP 5.0 起内置的组件和接口,并且从 PHP5.3 已逐渐的成熟。SPL 其实在所有的 PHP5 开发环境中被内置,同时无需任何设置。

似乎众多的 PHP 开发人员基本没有使用它,甚至闻所未闻。究其原因,可以追述到它那阳春白雪般的说明文档,使你忽略了「它的存在」。SPL 这块宝石犹如铁达尼的「海洋之心」般,被沉入海底。而现在它应该被我们捞起,并将它穿戴在应有的位置 ,而这也是这篇文章所要表述的观点。

那么,SPL 提供了什么?

SPL 对 PHP 引擎进行了扩展,例如 ArrayAccessCountable SeekableIterator 等接口,它们用于以数组形式操作对象。同时,你还可以使用 RecursiveIteratorArrayObejcts 等其他迭代器进行数据的迭代操作。

它还内置几个的对象例如 ExceptionsSplObserverSpltorage 以及 splautoloadregistersplclassesiteratorapply 等的帮助函数(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 中)。

那到底有多快呢,下面的组数据可以让你窥其究竟。

PHP SPL 被遗落的宝石【SPL应用浅析】

如果你需要大量的数组操作,那么你可以尝试下,相信它是值得信赖的。

数据结构

同时 SPL 还提供了些数据结构基本类型的实现 。虽然我们可以使用传统的变量类型来描述数据结构,例如用数组来描述堆栈(Strack)-- 然后使用对应的方式 pop 和 push(arraypop()arraypush()),但你得时刻小心,·因为毕竟它们不是专门用于描述数据结构的 -- 一次误操作就有可能破坏该堆栈。

而 SPL 的 SplStack 对象则严格以堆栈的形式描述数据,并提供对应的方法。同时,这样的代码应该也能理解它在操作堆栈而非某个数组,从而能让你的同伴更好的理解相应的代码,并且它更快。

最后,可能上述那些惨白的例子还不足矣「诱惑你」去使用 SPL。实践出真知,SPL 更多、更强大的功能需要你自己去挖掘。而它正如宝石般的慢慢雕砌,才能散发光辉。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php一句话cmdshell新型 (非一句话木马)
Apr 18 PHP
php面向对象全攻略 (二) 实例化对象 使用对象成员
Sep 30 PHP
一步一步学习PHP(6) 面向对象
Feb 16 PHP
PHP初学者最感迷茫的问题小结
Mar 27 PHP
Drupal读取Excel并导入数据库实例
Mar 02 PHP
PHP函数getenv简介和使用实例
May 12 PHP
php之readdir函数用法实例
Nov 13 PHP
为百度UE编辑器上传图片添加水印功能
Apr 16 PHP
Joomla简单判断用户是否登录的方法
May 04 PHP
微信支付PHP SDK ―― 公众号支付代码详解
Sep 13 PHP
PHP7中I/O模型内核剖析详解
Apr 14 PHP
搭建PhpStorm+PhpStudy开发环境的超详细教程
Sep 17 PHP
Laravel 加载第三方类库的方法
Apr 20 #PHP
PHP迭代器和迭代的实现与使用方法分析
Apr 19 #PHP
详解php curl带有csrf-token验证模拟提交方法
Apr 18 #PHP
php-app开发接口加密详解
Apr 18 #PHP
PHPMAILER实现PHP发邮件功能
Apr 18 #PHP
PHP实现数据库的增删查改功能及完整代码
Apr 18 #PHP
php无限级评论嵌套实现代码
Apr 18 #PHP
You might like
PHP命名空间(namespace)的动态访问及使用技巧
2014/08/18 PHP
在云虚拟主机部署thinkphp5项目的步骤详解
2017/12/21 PHP
Laravel框架定时任务2种实现方式示例
2018/12/08 PHP
ThinkPHP3.2.3框架实现的空模块、空控制器、空操作,跳转到错误404页面图文详解
2019/04/03 PHP
PHP中number_format()函数的用法讲解
2019/04/08 PHP
php使用redis的有序集合zset实现延迟队列应用示例
2020/02/20 PHP
JavaScript 学习笔记(十二) dom
2010/01/21 Javascript
js本身的局限性 别让javascript做太多事
2010/03/23 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
2012/12/26 Javascript
jQuery事件之键盘事件(ctrl+Enter回车键提交表单等)
2014/05/11 Javascript
jQuery实现首页图片淡入淡出效果的方法
2015/06/10 Javascript
浅谈jQuery双事件多重加载的问题
2016/10/05 Javascript
深入理解js中的加载事件
2017/02/08 Javascript
Angular2.js实现表单验证详解
2017/06/23 Javascript
Angular4项目中添加i18n国际化插件ngx-translate的步骤详解
2017/07/02 Javascript
快速理解 JavaScript 中的 LHS 和 RHS 查询的用法
2017/08/24 Javascript
Bootstrap Tooltip显示换行和左对齐的解决方案
2017/10/11 Javascript
基于node搭建服务器,写接口,调接口,跨域的实例
2018/05/13 Javascript
JS实现的全选、全不选及反选功能【案例】
2019/02/19 Javascript
vue-cli的build的文件夹下没有dev-server.js文件配置mock数据的方法
2019/04/17 Javascript
Vue中消息横向滚动时setInterval清不掉的问题及解决方法
2019/08/23 Javascript
详解JavaScript中的链式调用
2020/11/27 Javascript
JS中锚点链接点击平滑滚动并自由调整到顶部位置
2021/02/06 Javascript
PyChar学习教程之自定义文件与代码模板详解
2017/07/17 Python
Python协程的用法和例子详解
2017/09/09 Python
python实现百度语音识别api
2018/04/10 Python
详解Python绘图Turtle库
2019/10/12 Python
Currentbody法国:健康与美容高科技产品
2020/08/16 全球购物
行政管理专业推荐信
2013/11/02 职场文书
家长给小学生的评语
2014/01/30 职场文书
高中毕业自我评价
2014/02/08 职场文书
小学优秀学生评语
2014/12/29 职场文书
2015新学期开学寄语
2015/02/26 职场文书
考试没考好检讨书
2015/05/06 职场文书
2015年大班保育员工作总结
2015/05/18 职场文书
浅谈怎么给Python添加类型标注
2021/06/08 Python