spl转换器_使用SPL迭代器,第1部分

spl转换器

When I first came across the term iteration and saw the overwhelming list of classes related to it in the SPL, I was taken aback. It seemed maybe iteration was too complex for me to grasp. I soon realized it was just a fancy word for something we programmers do all the time.

当我第一次遇到术语迭代并在SPL中看到与之相关的绝大多数类时,我大吃一惊。 似乎迭代太复杂了,我无法掌握。 我很快意识到这只是我们程序员一直在做的事情的幻想。

If you use PHP, you’ve most likely used arrays. And if you’ve used arrays, then most definitely you’ve looped through its elements. Look through any code and almost certainly you’ll find a foreach loop. Yes, iteration is just the process of traversing a list of values. An iterator then is an object that traverses a list, be it an array, a directory listing, or even a database result set.

如果使用PHP,则很可能使用了数组。 而且,如果您使用过数组,那么绝对可以遍历其元素。 查看任何代码,几乎可以肯定您会发现一个foreach循环。 是的,迭代只是遍历值列表的过程。 然后,迭代器是遍历列表的对象,它可以是数组,目录列表,甚至是数据库结果集。

In the first part of this two-part series I’ll introduce you to iteration and how you can take advantage of some of the built-in classes from the Standard PHP Library (SPL). SPL comes with a large number of iterators, and using them in your code can make your code more efficient and in most cases, more readable.

在这个由两部分组成的系列的第一部分中,我将向您介绍迭代以及如何利用标准PHP库(SPL)中的一些内置类。 SPL带有大量的迭代器,并且在代码中使用它们可以使您的代码更高效,并且在大多数情况下,更具可读性。

为什么以及何时使用SPL迭代器 (Why and When to Use SPL Iterators)

As you will see, iterating iterator objects is basically the same as iterating arrays, and so many people wonder if it wouldn’t be easier to just stick with using arrays in the first place. However, the real benefit of iterators show through when traversing a large amount of data or anything more complex than a simple array.

正如您将看到的,迭代迭代器对象与迭代数组基本相同,因此许多人想知道首先坚持使用数组是否会更容易。 但是,遍历大量数据或比简单数组更复杂的数据时,迭代器的真正好处就体现出来了。

The foreach loop makes a copy of any array passed to it. If you are processing a large amount of data, having the large arrays copied each time you use them in a foreach loop might be undesirable. SPL iterators encapsulate the list and expose visibility to one element at a time making them far more efficient.

foreach循环会复制传递给它的任何数组 。 如果要处理大量数据,则每次在foreach循环中使用大型数组时都要复制大型数组可能是不希望的。 SPL迭代器封装了该列表,并一次将可见性公开给一个元素,从而使其效率更高。

When creating data providers, iterators are a great construct as they allow you to lazy load your data. Lazy loading here is simply retrieving the required data only if and when it is needed. You can also manipulate (filter, transform etc) the data you are working on before giving it to the user.

创建数据提供程序时,迭代器是一个很好的构造,因为它们允许您延迟加载数据。 延迟加载只是在需要和需要时才检索所需的数据。 您还可以在将数据处理给用户之前处理(过滤,转换等)数据。

The decision to use iterators is always at your discretion, however. Iterators have numerous benefits, but in some cases (as with smaller array sets) can cause unwanted overhead. The decision of when to use them rests with you; your choice of style, and their suitability in the given situation, are all factors you should consider.

但是,使用迭代器的决定始终由您自行决定。 迭代器有很多好处,但是在某些情况下(如较小的数组集)会导致不必要的开销。 何时使用它们取决于您。 您对样式的选择以及它们在给定情况下的适用性都是您应考虑的所有因素。

迭代数组 (Iterating Arrays)

This first iterator I’d like to introduce you to is ArrayIterator. The constructor accepts an array for a parameter and provides methods that can be used to iterate through it. Here’s an example:

我想向您介绍的第一个迭代器是ArrayIterator 。 构造函数接受一个参数数组,并提供可用于迭代它的方法。 这是一个例子:

<?php
// an array (using PHP 5.4's new shorthand notation)
$arr = ["sitepoint", "phpmaster", "buildmobile", "rubysource",
    "designfestival", "cloudspring"];

// create a new ArrayIterator and pass in the array
$iter = new ArrayIterator($arr);

// loop through the object
foreach ($iter as $key => $value) {
    echo $key . ":  " . $value . "<br>";
}

The output of the above code is:

上面代码的输出是:

0: sitepoint
1: phpmaster
2: buildmobile
3: rubysource
4: designfestival
5: cloudspring

Usually, however, you will use ArrayObject, a class that allows you to work with objects as if they were arrays in certain contexts, instead of using ArrayIterator directly. This automatically creates an ArrayIterator for you when you use a foreach loop or call ArrayIterator::getIterator() directly.

但是,通常,您将使用ArrayObject ,该类使您可以像在某些上下文中将它们当作数组一样使用对象,而不是直接使用ArrayIterator 。 当您使用foreach循环或直接调用ArrayIterator::getIterator()时,这将自动为您创建ArrayIterator

Please note that while ArrayObject and ArrayIterator behave like arrays in this context, they are still objects; trying to use built-in array functions like sort() and array_keys() on them will fail dismally.

请注意,虽然ArrayObjectArrayIterator在此上下文中的行为类似于数组,但它们仍然是对象; 尝试在其上使用诸如sort()array_keys() sort()内置数组函数将失败。

The use of ArrayIterator is straight forward, but limited to single dimensional arrays. Sometimes you’ll have a multidimensional array and you’ll want to iterate through the nested arrays recursively. In this case you can use RecursiveArrayIterator.

ArrayIterator的使用很简单,但仅限于一维数组。 有时,您将拥有一个多维数组,并且希望递归地遍历嵌套数组。 在这种情况下,您可以使用RecursiveArrayIterator

One common scenario is to nest foreach loops or to create a recursive function which checks all items of a multidimensional array. For example:

一种常见的情况是嵌套foreach循环或创建检查多维数组所有项的递归函数。 例如:

<?php
// a multidimensional array
$arr = [
    ["sitepoint", "phpmaster"],
    ["buildmobile", "rubysource"],
    ["designfestival", "cloudspring"],
    "not an array"
];

// loop through the object
foreach ($arr as $key => $value) {
    // check for arrays
    if (is_array($value)) {
        foreach ($value as $k => $v) {
            echo $k . ": " . $v . "<br>";
        }
    }
    else {
        echo $key . ": " . $value . "<br>";
    }
}

The output of the above code is:

上面代码的输出是:

0: sitepoint
1: phpmaster
0: buildmobile
1: rubysource
0: designfestival
1: cloudspring
3: not an array

A more elegant approach makes use of RecursiveArrayIterator.

一种更优雅的方法是使用RecursiveArrayIterator

<?php
...
$iter = new RecursiveArrayIterator($arr);

// loop through the object
// we need to create a RecursiveIteratorIterator instance
foreach(new RecursiveIteratorIterator($iter) as $key => $value) {
    echo $key . ": " . $value . "<br>";
}

The output is the same as the previous example.

输出与前面的示例相同。

Note that you need to create an instance of RecursiveIteratorIterator and pass it the RecursiveArrayIterator object here or else all you would get would be the values in the root array (and a ton of notices depending on your settings).

请注意,您需要创建一个RecursiveIteratorIterator实例,并将其传递给RecursiveArrayIterator对象,否则您将获得的只是根数组中的值(以及大量的通知,具体取决于您的设置)。

You should use RecursiveArrayIterator when dealing with multidimensional arrays as it allows you to iterate over the current entry as well, but leaves this up to you to do. RecursiveIteratorIterator is a decorator which does this for you. It takes the RecursiveArrayIterator, iterates over it and iterates over any Iterable entry it finds (and so on). Essentially, it “flattens” the RecursiveArrayIterator. You can get the current depth of iteration by calling RecursiveIteratorIterator::getDepth() to keep track. Be careful with RecursiveArrayIterator and RecursiveIteratorIterator though if you want to return objects; objects are treated as Iterable and will therefore be iterated.

在处理多维数组时,应该使用RecursiveArrayIterator ,因为它还允许您迭代当前条目,但是由您自己决定。 RecursiveIteratorIterator是为您执行此操作的装饰器 。 它使用RecursiveArrayIterator ,对其进行迭代,并对其找到的任何Iterable条目进行迭代(依此类推)。 本质上,它“展平”了RecursiveArrayIterator 。 您可以通过调用RecursiveIteratorIterator::getDepth()来跟踪当前深度。 但是,如果要返回对象,请小心使用RecursiveArrayIteratorRecursiveIteratorIterator 。 对象被视为Iterable ,因此将重复。

迭代目录列表 (Iterating Directory Listings)

You will undoubtedly need to traverse a directory and its files at some point in time or another, and there are various ways of accomplishing this with the built-in functions provided by PHP already, such as with scandir() or glob(). But you can also use DirectoryIterator. In its simplest form, DirectoryIterator is quite powerful, but it can also be subclassed and enhanced.

毫无疑问,您将需要在某个时间点或另一个时间遍历目录及其文件,并且有多种方法可以通过PHP已经提供的内置函数(例如scandir()glob()来完成此任务。 但是您也可以使用DirectoryIterator 。 以最简单的形式, DirectoryIterator非常强大,但也可以对其进行子类化和增强。

Here’s an example of iterating a directory with DirectoryIterator:

这是使用DirectoryIterator迭代目录的示例:

<?php
// create new DirectoryIterator object
$dir = new DirectoryIterator("/my/directory/path");

// loop through the directory listing
foreach ($dir as $item) {
    echo $item . "<br>";
}

The output obviously will depend on the path you specify and what the directory’s contents are. For instance:

输出显然取决于您指定的路径以及目录的内容。 例如:

.
..
api
index.php
lib
workspace

Don’t forget that with DirectoryIterator, as well as many of the other SPL iterators, you have the added benefit of using exceptions to handle any errors.

不要忘记,通过DirectoryIterator以及许多其他SPL迭代器,您可以使用异常处理任何错误,从而获得更多好处。

<?php
try {
    $dir = new DirectoryIterator("/non/existent/path");
    foreach ($dir as $item) {
        echo $item . "<br>";
    }
}
catch (Exception $e) {
    echo get_class($e) . ": " . $e->getMessage();
}
UnexpectedValueException: DirectoryIterator::__construct(/non/existent/path,/non/existent/path): The system cannot find the file specified. (code: 2)

With a host of other methods like DirectoryIterator::isDot(), DirectoryIterator::getType() and DirectoryIterator::getSize(), pretty much all of your basic directory information needs are covered. You can even combine DirectoryIterator with FilterIterator or RegexIterator to return files matching specific criteria. For example:

使用DirectoryIterator::isDot()DirectoryIterator::getType()DirectoryIterator::getSize()等许多其他方法,几乎​​可以满足您的所有基本目录信息需求。 您甚至可以将DirectoryIteratorFilterIteratorRegexIterator结合使用以返回符合特定条件的文件。 例如:

<?php
class FileExtensionFilter extends FilterIterator
{
    // whitelist of file extensions
    protected $ext = ["php", "txt"];

    // an abstract method which must be implemented in subclass
    public function accept() {
        return in_array($this->getExtension(), $this->ext);
    }
}

//create a new iterator
$dir = new FileExtensionFilter(new DirectoryIterator("./"));
...

SPL also provides RecursiveDirectoryIterator which can be used in the same way as RecursiveArrayIterator. A function that traverses directories recursively will usually be littered with conditional checks for valid directories and files, and RecursiveDirectoryIterator can do much of the work for you resulting in cleaner code. There is one caveat, however. RecursiveDirectoryIterator does not return empty directories; if a directory contains many subdirectories but no files, it will return an empty result (much like how Git behaves).

SPL还提供RecursiveDirectoryIterator ,可以与RecursiveArrayIterator相同的方式使用。 递归遍历目录的功能通常会带有条件检查有效目录和文件,而RecursiveDirectoryIterator可以为您做很多工作,从而使代码更简洁。 但是,有一个警告。 RecursiveDirectoryIterator不返回空目录。 如果目录包含许多子目录但没有文件,它将返回空结果(非常类似于Git的行为)。

<?php
// create new RecursiveDirectoryIterator object
$iter = new RecursiveDirectoryIterator("/my/directory/path");

// loop through the directory listing
// we need to create a RecursiveIteratorIterator instance
foreach (new RecursiveIteratorIterator($iter) as $item) {
    echo $item . "<br>";
}

My output resembles:

我的输出类似于:

./api/.htaccess
./api/index.php
./index.php
...

摘要 (Summary)

Hopefully you now realize that iteration isn’t a complex beast like I first thought, and that it’s something we do every day as programmers. In this article I’ve introduced iteration and some of the classes that SPL provides to make iterating easier and more robust. Of course I’ve only dealt with a very small sampling of the available classes; SPL provides many, many more and I urge you to take a look at them.

希望您现在意识到迭代并不是像我最初想到的那样复杂的野兽,这是我们作为程序员每天都在做的事情。 在本文中,我介绍了迭代以及SPL提供的一些类,这些类使迭代更容易且更可靠。 当然,我只处理了可用类的非常小的样本。 SPL提供了许多其他功能,我促请您仔细阅读它们

SPL is a “standard” library. Sometimes you may find the classes too general and they may not always do what you need. In such cases you can easily extend the classes to add your own functionality or tweak existing functionality as needed. In the next part of this series I’ll show you how to use SPL interfaces to make your very own custom classes that can be traversed and accessed like arrays.

SPL是一个“标准”库。 有时,您可能会发现这些类太笼统,并且它们可能并不总是能够满足您的需求。 在这种情况下,您可以轻松扩展类以添加您自己的功能或根据需要调整现有功能。 在本系列的下一部分中,我将向您展示如何使用SPL接口创建自己的自定义类,这些类可以像数组一样被遍历和访问。

Image via Mushakesa / Shutterstock

图片来自Mushakesa / Shutterstock

翻译自: https://www.sitepoint.com/using-spl-iterators-1/

spl转换器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值