【澳门葡京备用网址】PHP设计方式漫谈之迭代器情势

PHP SPL笔记

这几天,笔者在求学PHP语言中的SPL。

其一事物应该属于PHP中的高级内容,看上去很复杂,然则这个有用,所以小编做了长篇笔记。不然记不住,现在要用的时候,如故要起来学起。

出于那是供自身参考的笔记,不是课程,所以写得相比简单,没有多解释。不过我想,如若你是2个熟识的PHP5程序员,应该能够看懂上面包车型地铁质地,而且会发现它很有用。今后除外,网上根本未曾别的深入的SPL中文介绍。

================

PHP SPL笔记

目录

先是某些 简介

  1. 什么是SPL?

  2. 什么是Iterator?

第一有的 SPL Interfaces

  1. Iterator界面

  2. ArrayAccess界面

  3. IteratorAggregate界面

  4. RecursiveIterator界面

  5. SeekableIterator界面

  6. Countable界面

其三片段 SPL Classes

  1. SPL的内置类

  2. DirectoryIterator类

  3. ArrayObject类

  4. ArrayIterator类

  5. RecursiveArrayIterator类和RecursiveIteratorIterator类

  6. FilterIterator类

  7. SimpleXMLIterator类

  8. CachingIterator类

  9. LimitIterator类

  10. SplFileObject类

第一部 简介

1. 什么是SPL?

SPL是Standard PHP Library(PHP标准库)的缩写。

基于官方概念,它是“a collection of interfaces and classes that are meant
to solve standard
problems”。但是,近期在使用中,SPL越来越多地被看作是一种使object(物体)模仿array(数组)行为的interfaces和classes。

2. 什么是Iterator?

SPL的骨干概念便是Iterator。那指的是一种Design Pattern,依照《Design
Patterns》一书的概念,Iterator的成效是“provide an object which traverses
some aggregate structure, abstracting away assumptions about the
implementation of that structure.”

wikipedia中说,”an iterator is an object which allows a programmer to
traverse through all the elements of a collection, regardless of its
specific implementation”.……”the iterator pattern is a design pattern in
which iterators are used to access the elements of an aggregate object
sequentially without exposing its underlying representation”.

浅显地说,Iterator能够使广大例外的数据结构,都能有联合的操作界面,比如贰个数据库的结果集、同三个索引中的文件集、或然二个文件中每一行构成的晤面。

假使遵照平常情形,遍历一个MySQL的结果集,程序必要那样写:

// Fetch the "aggregate structure"
$result = mysql_query("SELECT * FROM users");

// Iterate over the structure
while ( $row = mysql_fetch_array($result) ) {
// do stuff with the row here
}

读出多个索引中的内容,需求如此写:

// Fetch the "aggregate structure"
$dh = opendir('/home/harryf/files');

// Iterate over the structure
while ( $file = readdir($dh) ) {
// do stuff with the file here
}

读出2个文本文件的始末,要求如此写:

// Fetch the "aggregate structure"
$fh = fopen("/home/hfuecks/files/results.txt", "r");

// Iterate over the structure
while (!feof($fh)) {

$line = fgets($fh);
// do stuff with the line here

}

上边三段代码,即便处理的是见仁见智的resource(财富),可是效果都是遍历结果集(loop
over
contents),因此Iterator的基本思维,正是将这二种分化的操作统一起来,用同一的下令界面,处理差异的能源。

第贰片段 SPL Interfaces

3. Iterator界面

SPL规定,全数配置了Iterator界面包车型大巴class,都能够用在foreach
Loop中。Iterator界面中隐含七个必须布置的格局:

    * current()

This method returns the current index’s value. You are solely
responsible for tracking what the current index is as the
interface does not do this for you.

    * key()

This method returns the value of the current index’s key. For
foreach loops this is extremely important so that the key
value can be populated.

    * next()

This method moves the internal index forward one entry.

    * rewind()

This method should reset the internal index to the first element.

    * valid()

This method should return true or false if there is a current
element. It is called after rewind() or next().

上面就是二个安排了Iterator界面的class示例:

/**
* An iterator for native PHP arrays, re-inventing the wheel
*
* Notice the "implements Iterator" - important!
*/
class ArrayReloaded implements Iterator {

/**

   * A native PHP array to iterate over
   */
 private $array = array();

/**

   * A switch to keep track of the end of the array
   */
 private $valid = FALSE;

/**

   * Constructor
   * @param array native PHP array to iterate over
   */
 function __construct($array) {
   $this->array = $array;
 }

/**

   * Return the array "pointer" to the first element
   * PHP's reset() returns false if the array has no elements
   */
 function rewind(){
   $this->valid = (FALSE !== reset($this->array));
 }

/**

   * Return the current array element
   */
 function current(){
   return current($this->array);
 }

/**

   * Return the key of the current array element
   */
 function key(){
   return key($this->array);
 }

/**

   * Move forward by one
   * PHP's next() returns false if there are no more elements
   */
 function next(){
   $this->valid = (FALSE !== next($this->array));
 }

/**

   * Is the current element valid?
   */
 function valid(){
   return $this->valid;
 }
}

选取办法如下:

// Create iterator object
$colors = new ArrayReloaded(array ('red','green','blue',));

// Iterate away!
foreach ( $colors as $color ) {
echo $color.”
“;
}

您也得以在foreach循环中动用key()方法:

// Display the keys as well
foreach ( $colors as $key => $color ) {
 echo "$key: $color<br>";
}

除此之外foreach循环外,也得以应用while循环,

// Reset the iterator - foreach does this automatically
$colors->rewind();

// Loop while valid
while ( $colors->valid() ) {

echo $colors->key().”: “.$colors->current().”
“;
$colors->next();

}

听大人说测试,while循环要稍快于foreach循环,因为运维时少了一层中间调用。

4. ArrayAccess界面

安插ArrayAccess界面,能够使得object像array那样操作。ArrayAccess界面包括七个必须计划的艺术:

    * offsetExists($offset)

This method is used to tell php if there is a value
for the key specified by offset. It should return
true or false.

    * offsetGet($offset)

This method is used to return the value specified
by the key offset.

    * offsetSet($offset, $value)

This method is used to set a value within the object,
you can throw an exception from this function for a
read-only collection.

    * offsetUnset($offset)

This method is used when a value is removed from
an array either through unset() or assigning the key
a value of null. In the case of numerical arrays, this
offset should not be deleted and the array should
not be reindexed unless that is specifically the
behavior you want.

下边就是二个陈设ArrayAccess界面包车型客车实例:

/**
* A class that can be used like an array
*/
class Article implements ArrayAccess {

public $title;

public $author;

public $category;

function __construct($title,$author,$category) {
$this->title = $title;
$this->author = $author;
$this->category = $category;
}

/**

 * Defined by ArrayAccess interface
 * Set a value given it's key e.g. $A['title'] = 'foo';
 * @param mixed key (string or integer)
 * @param mixed value
 * @return void
 */
 function offsetSet($key, $value) {
   if ( array_key_exists($key,get_object_vars($this)) ) {
     $this->{$key} = $value;
   }
 }

/**

 * Defined by ArrayAccess interface
 * Return a value given it's key e.g. echo $A['title'];
 * @param mixed key (string or integer)
 * @return mixed value
 */
 function offsetGet($key) {
   if ( array_key_exists($key,get_object_vars($this)) ) {
     return $this->{$key};
   }
 }

/**

 * Defined by ArrayAccess interface
 * Unset a value by it's key e.g. unset($A['title']);
 * @param mixed key (string or integer)
 * @return void
 */
 function offsetUnset($key) {
   if ( array_key_exists($key,get_object_vars($this)) ) {
     unset($this->{$key});
   }
 }

/**

 * Defined by ArrayAccess interface
 * Check value exists, given it's key e.g. isset($A['title'])
 * @param mixed key (string or integer)
 * @return boolean
 */
 function offsetExists($offset) {
   return array_key_exists($offset,get_object_vars($this));
 }

}

接纳方法如下:

// Create the object
$A = new Article('SPL Rocks','Joe Bloggs', 'PHP');

// Check what it looks like
echo ‘Initial State:

‘;
print_r($A);
echo ‘

‘;

// Change the title using array syntax
$A[‘title’] = ‘SPL really rocks’;

// Try setting a non existent property (ignored)
$A[‘not found’] = 1;

// Unset the author field
unset($A[‘author’]);

// Check what it looks like again
echo ‘Final State:

‘;
print_r($A);
echo ‘

‘;

运作结果如下:

Initial State:

Article Object
(
[title] => SPL Rocks
[author] => Joe Bloggs
[category] => PHP
)

Final State:

Article Object
(
[title] => SPL really rocks
[category] => PHP
)

能够看出,$A即便是二个object,不过完全能够像array这样操作。

您还足以在读取数据时,扩张程序内部的逻辑:

function offsetGet($key) {
   if ( array_key_exists($key,get_object_vars($this)) ) {
     return strtolower($this->{$key});
   }
 }

5. IteratorAggregate界面

可是,固然$A可以像数组那样操作,却力不从心使用foreach遍历,除非安顿了近年来提到的Iterator界面。

另多少个化解办法是,有时会须要将数据和遍历部分分离,这时就足以安插IteratorAggregate界面。它规定了二个getIterator()方法,重临三个行使Iterator界面包车型大巴object。

要么以上一节的阿特icle类为例:

class Article implements ArrayAccess, IteratorAggregate {

/**

 * Defined by IteratorAggregate interface
 * Returns an iterator for for this object, for use with foreach
 * @return ArrayIterator
 */
 function getIterator() {
   return new ArrayIterator($this);
 }

利用方法如下:

$A = new Article('SPL Rocks','Joe Bloggs', 'PHP');

// Loop (getIterator will be called automatically)
echo ‘Looping with foreach:

‘;
foreach ( $A as $field => $value ) {
echo “$field : $value
“;
}
echo ‘

‘;

// Get the size of the iterator (see how many properties are left)
echo “Object has “.sizeof($A->getIterator()).” elements”;

展示结果如下:

Looping with foreach:

title : SPL Rocks
author : Joe Bloggs
category : PHP

Object has 3 elements

6. RecursiveIterator界面

这几个界面用于遍历多层数据,它再三再四了Iterator界面,由此也颇具标准的current()、key()、next()、
rewind()和valid()方法。同时,它和谐还规定了getChildren()和hasChildren()方法。The
getChildren() method must return an object that implements
RecursiveIterator.

7. SeekableIterator界面

SeekableIterator界面也是Iterator界面包车型客车拉开,除了Iterator的几个办法以外,还规定了seek()方法,参数是因素的地点,重返该因素。要是该岗位不存在,则抛出OutOfBoundsException。

上面是1个是实例:

<?php

class PartyMemberIterator implements SeekableIterator
{
public function __construct(PartyMember $member)
{
// Store $member locally for iteration
}

public function seek($index)
{
$this->rewind();
$position = 0;

while ($position < $index && $this->valid()) {
$this->next();
$position++;
}

if (!$this->valid()) {
throw new OutOfBoundsException(‘Invalid position’);
}
}

// Implement current(), key(), next(), rewind()
// and valid() to iterate over data in $member
}

?>

8. Countable界面

那几个界面规定了几个count()方法,重返结果集的多少。

其三局地 SPL Classes

9. SPL的内置类

SPL除了定义一名目繁多Interfaces以外,还提供一连串的内置类,它们对应分化的职务,大大简化了编制程序。

查看全数的内置类,能够利用下边包车型客车代码:

<?php
// a simple foreach() to traverse the SPL class names
foreach(spl_classes() as $key=>$value)
        {
        echo $key.' -&gt; '.$value.'<br />';
        }
?>

10. DirectoryIterator类

其一类用来查阅二个目录中的全体文件和子目录:

<?php

try{
/ class create new DirectoryIterator Object /
foreach ( new DirectoryIterator(‘./’) as $Item )
{
echo $Item.’
‘;
}
}
/ if an exception is thrown, catch it here /
catch(Exception $e){
echo ‘No files Found!
‘;
}
?>

查阅文件的详细新闻:

<table>
<?php

foreach(new DirectoryIterator(‘./’ ) as $file )
{
if( $file->getFilename() == ‘foo.txt’ )
{
echo ‘

getFilename() ‘; var_dump($file->getFilename()); echo ‘

‘;
echo ‘

getBasename() ‘; var_dump($file->getBasename()); echo ‘

‘;
echo ‘

isDot() ‘; var_dump($file->isDot()); echo ‘

‘;
echo ‘

__toString() ‘; var_dump($file->__toString()); echo ‘

‘;
echo ‘

getPath() ‘; var_dump($file->getPath()); echo ‘

‘;
echo ‘

getPathname() ‘; var_dump($file->getPathname()); echo ‘

‘;
echo ‘

getPerms() ‘; var_dump($file->getPerms()); echo ‘

‘;
echo ‘

getInode() ‘; var_dump($file->getInode()); echo ‘

‘;
echo ‘

getSize() ‘; var_dump($file->getSize()); echo ‘

‘;
echo ‘

getOwner() ‘; var_dump($file->getOwner()); echo ‘

‘;
echo ‘

$file->getGroup() ‘; var_dump($file->getGroup()); echo ‘

‘;
echo ‘

getATime() ‘; var_dump($file->getATime()); echo ‘

‘;
echo ‘

getMTime() ‘; var_dump($file->getMTime()); echo ‘

‘;
echo ‘

getCTime() ‘; var_dump($file->getCTime()); echo ‘

‘;
echo ‘

getType() ‘; var_dump($file->getType()); echo ‘

‘;
echo ‘

isWritable() ‘; var_dump($file->isWritable()); echo ‘

‘;
echo ‘

isReadable() ‘; var_dump($file->isReadable()); echo ‘

‘;
echo ‘

isExecutable( ‘; var_dump($file->isExecutable()); echo ‘

‘;
echo ‘

isFile() ‘; var_dump($file->isFile()); echo ‘

‘;
echo ‘

isDir() ‘; var_dump($file->isDir()); echo ‘

‘;
echo ‘

isLink() ‘; var_dump($file->isLink()); echo ‘

‘;
echo ‘

getFileInfo() ‘; var_dump($file->getFileInfo()); echo ‘

‘;
echo ‘

getPathInfo() ‘; var_dump($file->getPathInfo()); echo ‘

‘;
echo ‘

openFile() ‘; var_dump($file->openFile()); echo ‘

‘;
echo ‘

setFileClass() ‘; var_dump($file->setFileClass()); echo ‘

‘;
echo ‘

setInfoClass() ‘; var_dump($file->setInfoClass()); echo ‘

‘;
}
}
?>

除外foreach循环外,还足以采纳while循环:

<?php
/*** create a new iterator object ***/
$it = new DirectoryIterator('./');

/ loop directly over the object /
while($it->valid())
{
echo $it->key().’ — ‘.$it->current().’
‘;
/ move to the next iteration /
$it->next();
}
?>

假定要过滤全体子目录,能够在valid()方法中过滤:

<?php
/*** create a new iterator object ***/
$it = new DirectoryIterator('./');

/ loop directly over the object /
while($it->valid())
{
/ check if value is a directory /
if($it->isDir())
{
/ echo the key and current value /
echo $it->key().’ — ‘.$it->current().’
‘;
}
/ move to the next iteration /
$it->next();
}
?>

11. ArrayObject类

【澳门葡京备用网址】PHP设计方式漫谈之迭代器情势。这一个类能够将Array转化为object。

<?php

/ a simple array /
$array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

/ create the array object /
$arrayObj = new ArrayObject($array);

/ iterate over the array /
for($iterator = $arrayObj->getIterator();
/ check if valid /
$iterator->valid();
/ move to the next array member /
$iterator->next())
{
/ output the key and current array value /
echo $iterator->key() . ‘ => ‘ . $iterator->current() . ‘
‘;
}
?>

追加一个成分:

$arrayObj->append('dingo');

对成分排序:

$arrayObj->natcasesort();

展现成分的数目:

echo $arrayObj->count();

删除1个因素:

$arrayObj->offsetUnset(5);

某一个成分是不是存在:

 if ($arrayObj->offsetExists(3))
    {
       echo 'Offset Exists<br />';
    }

改变有个别地点的成分值:

 $arrayObj->offsetSet(5, "galah");

来得某些地点的成分值:

echo $arrayObj->offsetGet(4);

12. ArrayIterator类

以此类实际上是对ArrayObject类的填补,为后人提供遍历功用。

示范如下:

<?php
/*** a simple array ***/
$array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

try {
$object = new ArrayIterator($array);
foreach($object as $key=>$value)
{
echo $key.’ => ‘.$value.’
‘;
}
}
catch (Exception $e)
{
echo $e->getMessage();
}
?>

ArrayIterator类也援助offset类措施和count()方法:

<ul>
<?php
/*** a simple array ***/
$array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

try {
$object = new ArrayIterator($array);
/ check for the existence of the offset 2 /
if($object->offSetExists(2))
{
/ set the offset of 2 to a new value /
$object->offSetSet(2, ‘Goanna’);
}
/ unset the kiwi /
foreach($object as $key=>$value)
{
/ check the value of the key /
if($object->offSetGet($key) === ‘kiwi’)
{
/ unset the current key /
$object->offSetUnset($key);
}
echo ‘

  • ‘.$key.’ – ‘.$value.’
  • ‘.”\n”;
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    13. RecursiveArrayIterator类和RecursiveIteratorIterator类

    ArrayIterator类和ArrayObject类,只支持遍历一维数组。若是要遍历多维数组,必须先用RecursiveIteratorIterator生成3个Iterator,然后再对那个Iterator使用RecursiveIteratorIterator。

    <?php
    $array = array(
        array('name'=>'butch', 'sex'=>'m', 'breed'=>'boxer'),
        array('name'=>'fido', 'sex'=>'m', 'breed'=>'doberman'),
        array('name'=>'girly','sex'=>'f', 'breed'=>'poodle')
    );
    

    foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key=>$value)
    {
    echo $key.’ — ‘.$value.’
    ‘;
    }
    ?>

    14. FilterIterator类

    FilterIterator类能够对成分实行过滤,只要在accept()方法中设置过滤条件就能够了。

    演示如下:

    <?php
    /*** a simple array ***/
    $animals = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ'=>'kiwi', 'kookaburra', 'platypus');
    

    class CullingIterator extends FilterIterator{

    / The filteriterator takes a iterator as param: /
    public function construct( Iterator $it ){
    parent::
    construct( $it );
    }

    / check if key is numeric /
    function accept(){
    return is_numeric($this->key());
    }

    }/ end of class /
    $cull = new CullingIterator(new ArrayIterator($animals));

    foreach($cull as $key=>$value)
    {
    echo $key.’ == ‘.$value.’
    ‘;
    }
    ?>

    上边是另一个回去质数的例证:

    <?php
    

    class PrimeFilter extends FilterIterator{

    / The filteriterator takes a iterator as param: /
    public function construct(Iterator $it){
    parent::
    construct($it);
    }

    / check if current value is prime /
    function accept(){
    if($this->current() % 2 != 1)
    {
    return false;
    }
    $d = 3;
    $x = sqrt($this->current());
    while ($this->current() % $d != 0 && $d < $x) { $d += 2; } return (($this->current() % $d == 0 && $this->current() != $d) 1) == 0 ? true : false;
    }

    }/**
    end of class /

    /
    an array of numbers /
    $numbers = range(212345,212456);

    /
    create a new FilterIterator object ***/
    $primes = new primeFilter(new ArrayIterator($numbers));

    foreach($primes as $value)
    {
    echo $value.’ is prime.
    ‘;
    }
    ?>

    15. SimpleXMLIterator类

    以此类用来遍历xml文件。

    示范如下:

    <?php
    

    / a simple xml tree /
    $xmlstring = <<



    Phascolarctidae
    koala
    Bruce




    macropod
    kangaroo
    Bruce




    diprotodon
    wombat
    Bruce




    macropod
    wallaby
    Bruce




    dromaius
    emu
    Bruce




    Apteryx
    kiwi
    Troy




    kingfisher
    kookaburra
    Bruce




    monotremes
    platypus
    Bruce




    arachnid
    funnel web
    Bruce
    8



    XML;

    / a new simpleXML iterator object /
    try {
    / a new simple xml iterator /
    $it = new SimpleXMLIterator($xmlstring);
    / a new limitIterator object /
    foreach(new RecursiveIteratorIterator($it,1) as $name => $data)
    {
    echo $name.’ — ‘.$data.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    new RecursiveIteratorIterator($it,1)表示展现全部包涵父成分在内的子成分。

    展现某多个一定的因素值,能够这么写:

    <?php
    try {
        /*** a new simpleXML iterator object ***/
        $sxi =  new SimpleXMLIterator($xmlstring);
    

    foreach ( $sxi as $node )
    {
    foreach($node as $k=>$v)
    {
    echo $v->species.’
    ‘;
    }
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    相呼应的while循环写法为:

    <?php
    

    try {
    $sxe = simplexml_load_string($xmlstring, ‘SimpleXMLIterator’);

    for ($sxe->rewind(); $sxe->valid(); $sxe->next())
    {
    if($sxe->hasChildren())
    {
    foreach($sxe->getChildren() as $element=>$value)
    {
    echo $value->species.’
    ‘;
    }
    }
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    最有益的写法,照旧利用xpath:

    <?php
    try {
        /*** a new simpleXML iterator object ***/
        $sxi =  new SimpleXMLIterator($xmlstring);
    

    / set the xpath /
    $foo = $sxi->xpath(‘animal/category/species’);

    / iterate over the xpath /
    foreach ($foo as $k=>$v)
    {
    echo $v.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    下边包车型地铁例证,展现有namespace的状态:

    <?php
    

    / a simple xml tree /
    $xmlstring = <<

    Phascolarctidae
    Speed Hump
    koala
    Bruce




    macropod
    Boonga
    kangaroo
    Bruce




    diprotodon
    pot holer
    wombat
    Bruce




    macropod
    Target
    wallaby
    Bruce




    dromaius
    Road Runner
    emu
    Bruce




    Apteryx
    Football
    kiwi
    Troy




    kingfisher
    snaker
    kookaburra
    Bruce




    monotremes
    Swamp Rat
    platypus
    Bruce




    arachnid
    Killer
    funnel web
    Bruce
    8



    XML;

    / a new simpleXML iterator object /
    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    $sxi-> registerXPathNamespace(‘spec’, ”);

    / set the xpath /
    $result = $sxi->xpath(‘//spec:name’);

    / get all declared namespaces /
    foreach($sxi->getDocNamespaces(‘animal’) as $ns)
    {
    echo $ns.’
    ‘;
    }

    / iterate over the xpath /
    foreach ($result as $k=>$v)
    {
    echo $v.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    充实1个节点:

    <?php 
     $xmlstring = <<<XML
    <?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
    <document>
      <animal>koala</animal>
      <animal>kangaroo</animal>
      <animal>wombat</animal>
      <animal>wallaby</animal>
      <animal>emu</animal>
      <animal>kiwi</animal>
      <animal>kookaburra</animal>
      <animal>platypus</animal>
      <animal>funnel web</animal>
    </document>
    XML;
    

    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    / add a child /
    $sxi->addChild(‘animal’, ‘Tiger’);

    / a new simpleXML iterator object /
    $new = new SimpleXmlIterator($sxi->saveXML());

    / iterate over the new tree /
    foreach($new as $val)
    {
    echo $val.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    日增品质:

    <?php 
    $xmlstring =<<<XML
    <?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
    <document>
      <animal>koala</animal>
      <animal>kangaroo</animal>
      <animal>wombat</animal>
      <animal>wallaby</animal>
      <animal>emu</animal>
      <animal>kiwi</animal>
      <animal>kookaburra</animal>
      <animal>platypus</animal>
      <animal>funnel web</animal>
    </document>
    XML;
    

    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    / add an attribute with a namespace /
    $sxi->addAttribute(‘id:att1’, ‘good things’, ‘urn::test-foo’);

    / add an attribute without a namespace /
    $sxi->addAttribute(‘att2’, ‘no-ns’);

    echo htmlentities($sxi->saveXML());
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    16. CachingIterator类

    其一类有一个hasNext()方法,用来判定是还是不是还有下三个要素。

    示范如下:

    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    / create a new object /
    $object = new CachingIterator(new ArrayIterator($array));
    foreach($object as $value)
    {
    echo $value;
    if($object->hasNext())
    {
    echo ‘,’;
    }
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    17. LimitIterator类

    那些类用来界定再次回到结果集的多寡和岗位,必须提供offset和limit五个参数,与SQL命令中limit语句看似。

    示范如下:

    <?php
    /*** the offset value ***/
    $offset = 3;
    

    / the limit of records to show /
    $limit = 2;

    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    $it = new LimitIterator(new ArrayIterator($array), $offset, $limit);

    foreach($it as $k=>$v)
    {
    echo $it->getPosition().’
    ‘;
    }
    ?>

    另一个例证是:

    <?php
    

    / a simple array /
    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    $it = new LimitIterator(new ArrayIterator($array));

    try
    {
    $it->seek(5);
    echo $it->current();
    }
    catch(OutOfBoundsException $e)
    {
    echo $e->getMessage() . “
    “;
    }
    ?>

    18. SplFileObject类

    以此类用来对文件文件进行遍历。

    以身作则如下:

    <?php
    

    try{
    // iterate directly over the object
    foreach( new SplFileObject("/usr/local/apache/logs/access_log") as $line)
    // and echo each line of the file
    echo $line.’
    ‘;
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    回到文本文件的第叁行,能够这么写:

    <?php
    

    try{
    $file = new SplFileObject(“/usr/local/apache/logs/access_log”);

    $file->seek(3);

    echo $file->current();
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    [参考文献]

    1. Introduction to Standard PHP Library (SPL), By Kevin
      Waterson

    2. Introducing PHP 5’s Standard Library, By Harry
      Fuecks

    3.The Standard PHP Library (SPL), By Ben
    Ramsey

    1. SPL – Standard PHP Library
      Documentation

    (完)

    PHP SPL笔记

    这几天,小编在上学PHP语言中的SPL。

    那些事物应该属于PHP中的高级内容,看上去很复杂,然则非常有用,所以自身做了长篇笔记。不然记不住,今后要用的时候,依然要初叶学起。

    由于那是供自个儿参考的笔记,不是课程,所以写得比较简单,没有多解释。可是自个儿想,假如您是1个科班出身的PHP5程序员,应该能够看懂上面包车型大巴素材,而且会发觉它很有用。今后除外,网上根本未曾其他深入的SPL中文介绍。

    ================

    PHP SPL笔记

    目录

    首先部分 简介

    1. 什么是SPL?

    2. 什么是Iterator?

    第②有的 SPL Interfaces

    1. Iterator界面

    2. ArrayAccess界面

    3. IteratorAggregate界面

    4. RecursiveIterator界面

    5. SeekableIterator界面

    6. Countable界面

    其三片段 SPL Classes

    1. SPL的内置类

    2. DirectoryIterator类

    3. ArrayObject类

    4. ArrayIterator类

    5. RecursiveArrayIterator类和RecursiveIteratorIterator类

    6. FilterIterator类

    7. SimpleXMLIterator类

    8. CachingIterator类

    9. LimitIterator类

    10. SplFileObject类

    第一部 简介

    1. 什么是SPL?

    SPL是Standard PHP Library(PHP标准库)的缩写。

    依照官方概念,它是“a collection of interfaces and classes that are meant
    to solve standard
    problems”。不过,近期在采取中,SPL更多地被看作是一种使object(物体)模仿array(数组)行为的interfaces和classes。

    2. 什么是Iterator?

    SPL的中央概念正是Iterator。那指的是一种Design 帕特tern,依据《Design
    Patterns》一书的定义,Iterator的效用是“provide an object which traverses
    some aggregate structure, abstracting away assumptions about the
    implementation of that structure.”

    wikipedia中说,”an iterator is an object which allows a programmer to
    traverse through all the elements of a collection, regardless of its
    specific implementation”.……”the iterator pattern is a design pattern in
    which iterators are used to access the elements of an aggregate object
    sequentially without exposing its underlying representation”.

    深切浅出地说,Iterator能够使很多两样的数据结构,都能有统一的操作界面,比如叁个数据库的结果集、同多少个目录中的文件集、可能一个文件中每一行构成的会见。

    若果依照普通情形,遍历多个MySQL的结果集,程序需求这么写:

    // Fetch the "aggregate structure"
    $result = mysql_query("SELECT * FROM users");
    

    // Iterate over the structure
    while ( $row = mysql_fetch_array($result) ) {
    // do stuff with the row here
    }

    读出一个索引中的内容,须求如此写:

    // Fetch the "aggregate structure"
    $dh = opendir('/home/harryf/files');
    

    // Iterate over the structure
    while ( $file = readdir($dh) ) {
    // do stuff with the file here
    }

    读出叁个文本文件的内容,须求那样写:

    // Fetch the "aggregate structure"
    $fh = fopen("/home/hfuecks/files/results.txt", "r");
    

    // Iterate over the structure
    while (!feof($fh)) {

    $line = fgets($fh);
    // do stuff with the line here

    }

    上边三段代码,固然处理的是不一样的resource(能源),然则效果都是遍历结果集(loop
    over
    contents),因而Iterator的为主考虑,就是将那二种不一样的操作统一起来,用平等的下令界面,处理分化的能源。

    其次片段 SPL Interfaces

    3. Iterator界面

    SPL规定,全数配置了Iterator界面包车型客车class,都能够用在foreach
    Loop中。Iterator界面中包括5个必须配备的点子:

        * current()
    

    This method returns the current index’s value. You are solely
    responsible for tracking what the current index is as the
    interface does not do this for you.

        * key()
    

    This method returns the value of the current index’s key. For
    foreach loops this is extremely important so that the key
    value can be populated.

        * next()
    

    This method moves the internal index forward one entry.

        * rewind()
    

    This method should reset the internal index to the first element.

        * valid()
    

    This method should return true or false if there is a current
    element. It is called after rewind() or next().

    下边正是三个布置了Iterator界面包车型大巴class示例:

    /**
    * An iterator for native PHP arrays, re-inventing the wheel
    *
    * Notice the "implements Iterator" - important!
    */
    class ArrayReloaded implements Iterator {
    

    /**

       * A native PHP array to iterate over
       */
     private $array = array();
    

    /**

       * A switch to keep track of the end of the array
       */
     private $valid = FALSE;
    

    /**

       * Constructor
       * @param array native PHP array to iterate over
       */
     function __construct($array) {
       $this->array = $array;
     }
    

    /**

       * Return the array "pointer" to the first element
       * PHP's reset() returns false if the array has no elements
       */
     function rewind(){
       $this->valid = (FALSE !== reset($this->array));
     }
    

    /**

       * Return the current array element
       */
     function current(){
       return current($this->array);
     }
    

    /**

       * Return the key of the current array element
       */
     function key(){
       return key($this->array);
     }
    

    /**

       * Move forward by one
       * PHP's next() returns false if there are no more elements
       */
     function next(){
       $this->valid = (FALSE !== next($this->array));
     }
    

    /**

       * Is the current element valid?
       */
     function valid(){
       return $this->valid;
     }
    }
    

    选拔情势如下:

    // Create iterator object
    $colors = new ArrayReloaded(array ('red','green','blue',));
    

    // Iterate away!
    foreach ( $colors as $color ) {
    echo $color.”
    “;
    }

    您也得以在foreach循环中应用key()方法:

    // Display the keys as well
    foreach ( $colors as $key => $color ) {
     echo "$key: $color<br>";
    }
    

    除了foreach循环外,也得以运用while循环,

    // Reset the iterator - foreach does this automatically
    $colors->rewind();
    

    // Loop while valid
    while ( $colors->valid() ) {

    echo $colors->key().”: “.$colors->current().”
    “;
    $colors->next();

    }

    传说测试,while循环要稍快于foreach循环,因为运转时少了一层中间调用。

    4. ArrayAccess界面

    安插ArrayAccess界面,可以使得object像array那样操作。ArrayAccess界面包涵多个必须配备的法子:

        * offsetExists($offset)
    

    This method is used to tell php if there is a value
    for the key specified by offset. It should return
    true or false.

        * offsetGet($offset)
    

    This method is used to return the value specified
    by the key offset.

        * offsetSet($offset, $value)
    

    This method is used to set a value within the object,
    you can throw an exception from this function for a
    read-only collection.

        * offsetUnset($offset)
    

    This method is used when a value is removed from
    an array either through unset() or assigning the key
    a value of null. In the case of numerical arrays, this
    offset should not be deleted and the array should
    not be reindexed unless that is specifically the
    behavior you want.

    上边就是3个配置ArrayAccess界面包车型大巴实例:

    /**
    * A class that can be used like an array
    */
    class Article implements ArrayAccess {
    

    public $title;

    public $author;

    public $category;

    function __construct($title,$author,$category) {
    $this->title = $title;
    $this->author = $author;
    $this->category = $category;
    }

    /**

     * Defined by ArrayAccess interface
     * Set a value given it's key e.g. $A['title'] = 'foo';
     * @param mixed key (string or integer)
     * @param mixed value
     * @return void
     */
     function offsetSet($key, $value) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         $this->{$key} = $value;
       }
     }
    

    /**

     * Defined by ArrayAccess interface
     * Return a value given it's key e.g. echo $A['title'];
     * @param mixed key (string or integer)
     * @return mixed value
     */
     function offsetGet($key) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         return $this->{$key};
       }
     }
    

    /**

     * Defined by ArrayAccess interface
     * Unset a value by it's key e.g. unset($A['title']);
     * @param mixed key (string or integer)
     * @return void
     */
     function offsetUnset($key) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         unset($this->{$key});
       }
     }
    

    /**

     * Defined by ArrayAccess interface
     * Check value exists, given it's key e.g. isset($A['title'])
     * @param mixed key (string or integer)
     * @return boolean
     */
     function offsetExists($offset) {
       return array_key_exists($offset,get_object_vars($this));
     }
    

    }

    应用方法如下:

    // Create the object
    $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');
    

    // Check what it looks like
    echo ‘Initial State:

    ‘;
    print_r($A);
    echo ‘

    ‘;

    // Change the title using array syntax
    $A[‘title’] = ‘SPL really rocks’;

    // Try setting a non existent property (ignored)
    $A[‘not found’] = 1;

    // Unset the author field
    unset($A[‘author’]);

    // Check what it looks like again
    echo ‘Final State:

    ‘;
    print_r($A);
    echo ‘

    ‘;

    运营结果如下:

    Initial State:
    

    Article Object
    (
    [title] => SPL Rocks
    [author] => Joe Bloggs
    [category] => PHP
    )

    Final State:

    Article Object
    (
    [title] => SPL really rocks
    [category] => PHP
    )

    能够看来,$A即便是叁个object,然而完全能够像array那样操作。

    你还可以在读取数据时,扩张程序内部的逻辑:

    function offsetGet($key) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         return strtolower($this->{$key});
       }
     }
    

    5. IteratorAggregate界面

    然而,固然$A能够像数组那样操作,却无计可施接纳foreach遍历,除非布置了近年来提到的Iterator界面。

    另二个缓解方法是,有时会需求将数据和遍历部分分离,这时就足以安插IteratorAggregate界面。它规定了二个getIterator()方法,重临三个选择Iterator界面包车型客车object。

    抑或以上一节的Article类为例:

    class Article implements ArrayAccess, IteratorAggregate {
    

    /**

     * Defined by IteratorAggregate interface
     * Returns an iterator for for this object, for use with foreach
     * @return ArrayIterator
     */
     function getIterator() {
       return new ArrayIterator($this);
     }
    

    接纳形式如下:

    $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');
    

    // Loop (getIterator will be called automatically)
    echo ‘Looping with foreach:

    ‘;
    foreach ( $A as $field => $value ) {
    echo “$field : $value
    “;
    }
    echo ‘

    ‘;

    // Get the size of the iterator (see how many properties are left)
    echo “Object has “.sizeof($A->getIterator()).” elements”;

    显示结果如下:

    Looping with foreach:
    

    title : SPL Rocks
    author : Joe Bloggs
    category : PHP

    Object has 3 elements

    6. RecursiveIterator界面

    其一界面用于遍历多层数据,它连续了Iterator界面,因此也享有专业的current()、key()、next()、
    rewind()和valid()方法。同时,它本身还规定了getChildren()和hasChildren()方法。The
    getChildren() method must return an object that implements
    RecursiveIterator.

    7. SeekableIterator界面

    SeekableIterator界面也是Iterator界面包车型大巴拉开,除了Iterator的四个措施以外,还规定了seek()方法,参数是因素的地方,重临该因素。固然该岗位不存在,则抛出OutOfBoundsException。

    上面是八个是实例:

    <?php
    

    class PartyMemberIterator implements SeekableIterator
    {
    public function __construct(PartyMember $member)
    {
    // Store $member locally for iteration
    }

    public function seek($index)
    {
    $this->rewind();
    $position = 0;

    while ($position < $index && $this->valid()) {
    $this->next();
    $position++;
    }

    if (!$this->valid()) {
    throw new OutOfBoundsException(‘Invalid position’);
    }
    }

    // Implement current(), key(), next(), rewind()
    // and valid() to iterate over data in $member
    }

    ?>

    8. Countable界面

    那个界面规定了三个count()方法,返回结果集的数码。

    其三局地 SPL Classes

    9. SPL的内置类

    SPL除了定义一层层Interfaces以外,还提供一二种的内置类,它们对应分歧的任务,大大简化了编制程序。

    查阅全数的内置类,能够应用下边包车型的士代码:

    <?php
    // a simple foreach() to traverse the SPL class names
    foreach(spl_classes() as $key=>$value)
            {
            echo $key.' -&gt; '.$value.'<br />';
            }
    ?>
    

    10. DirectoryIterator类

    本条类用来查阅三个目录中的全数文件和子目录:

    <?php
    

    try{
    / class create new DirectoryIterator Object /
    foreach ( new DirectoryIterator(‘./’) as $Item )
    {
    echo $Item.’
    ‘;
    }
    }
    / if an exception is thrown, catch it here /
    catch(Exception $e){
    echo ‘No files Found!
    ‘;
    }
    ?>

    翻看文件的详细音讯:

    <table>
    <?php
    

    foreach(new DirectoryIterator(‘./’ ) as $file )
    {
    if( $file->getFilename() == ‘foo.txt’ )
    {
    echo ‘

    getFilename() ‘; var_dump($file->getFilename()); echo ‘

    ‘;
    echo ‘

    getBasename() ‘; var_dump($file->getBasename()); echo ‘

    ‘;
    echo ‘

    isDot() ‘; var_dump($file->isDot()); echo ‘

    ‘;
    echo ‘

    __toString() ‘; var_dump($file->__toString()); echo ‘

    ‘;
    echo ‘

    getPath() ‘; var_dump($file->getPath()); echo ‘

    ‘;
    echo ‘

    getPathname() ‘; var_dump($file->getPathname()); echo ‘

    ‘;
    echo ‘

    getPerms() ‘; var_dump($file->getPerms()); echo ‘

    ‘;
    echo ‘

    getInode() ‘; var_dump($file->getInode()); echo ‘

    ‘;
    echo ‘

    getSize() ‘; var_dump($file->getSize()); echo ‘

    ‘;
    echo ‘

    getOwner() ‘; var_dump($file->getOwner()); echo ‘

    ‘;
    echo ‘

    $file->getGroup() ‘; var_dump($file->getGroup()); echo ‘

    ‘;
    echo ‘

    getATime() ‘; var_dump($file->getATime()); echo ‘

    ‘;
    echo ‘

    getMTime() ‘; var_dump($file->getMTime()); echo ‘

    ‘;
    echo ‘

    getCTime() ‘; var_dump($file->getCTime()); echo ‘

    ‘;
    echo ‘

    getType() ‘; var_dump($file->getType()); echo ‘

    ‘;
    echo ‘

    isWritable() ‘; var_dump($file->isWritable()); echo ‘

    ‘;
    echo ‘

    isReadable() ‘; var_dump($file->isReadable()); echo ‘

    ‘;
    echo ‘

    isExecutable( ‘; var_dump($file->isExecutable()); echo ‘

    ‘;
    echo ‘

    isFile() ‘; var_dump($file->isFile()); echo ‘

    ‘;
    echo ‘

    isDir() ‘; var_dump($file->isDir()); echo ‘

    ‘;
    echo ‘

    isLink() ‘; var_dump($file->isLink()); echo ‘

    ‘;
    echo ‘

    getFileInfo() ‘; var_dump($file->getFileInfo()); echo ‘

    ‘;
    echo ‘

    getPathInfo() ‘; var_dump($file->getPathInfo()); echo ‘

    ‘;
    echo ‘

    openFile() ‘; var_dump($file->openFile()); echo ‘

    ‘;
    echo ‘

    setFileClass() ‘; var_dump($file->setFileClass()); echo ‘

    ‘;
    echo ‘

    setInfoClass() ‘; var_dump($file->setInfoClass()); echo ‘

    ‘;
    }
    }
    ?>

    除去foreach循环外,还足以应用while循环:

    <?php
    /*** create a new iterator object ***/
    $it = new DirectoryIterator('./');
    

    / loop directly over the object /
    while($it->valid())
    {
    echo $it->key().’ — ‘.$it->current().’
    ‘;
    / move to the next iteration /
    $it->next();
    }
    ?>

    假定要过滤全部子目录,能够在valid()方法中过滤:

    <?php
    /*** create a new iterator object ***/
    $it = new DirectoryIterator('./');
    

    / loop directly over the object /
    while($it->valid())
    {
    / check if value is a directory /
    if($it->isDir())
    {
    / echo the key and current value /
    echo $it->key().’ — ‘.$it->current().’
    ‘;
    }
    / move to the next iteration /
    $it->next();
    }
    ?>

    11. ArrayObject类

    以此类可以将Array转化为object。

    <?php
    

    / a simple array /
    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    / create the array object /
    $arrayObj = new ArrayObject($array);

    / iterate over the array /
    for($iterator = $arrayObj->getIterator();
    / check if valid /
    $iterator->valid();
    / move to the next array member /
    $iterator->next())
    {
    / output the key and current array value /
    echo $iterator->key() . ‘ => ‘ . $iterator->current() . ‘
    ‘;
    }
    ?>

    扩大3个因素:

    $arrayObj->append('dingo');
    

    对成分排序:

    $arrayObj->natcasesort();
    

    来得成分的多寡:

    echo $arrayObj->count();
    

    除去多少个因素:

    $arrayObj->offsetUnset(5);
    

    某贰个要素是不是存在:

     if ($arrayObj->offsetExists(3))
        {
           echo 'Offset Exists<br />';
        }
    

    变动有些地点的成分值:

     $arrayObj->offsetSet(5, "galah");
    

    展示有些地方的成分值:

    echo $arrayObj->offsetGet(4);
    

    12. ArrayIterator类

    以此类实际上是对ArrayObject类的补充,为继承者提供遍历效用。

    以身作则如下:

    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    $object = new ArrayIterator($array);
    foreach($object as $key=>$value)
    {
    echo $key.’ => ‘.$value.’
    ‘;
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    ArrayIterator类也支撑offset类方式和count()方法:

    <ul>
    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    $object = new ArrayIterator($array);
    / check for the existence of the offset 2 /
    if($object->offSetExists(2))
    {
    / set the offset of 2 to a new value /
    $object->offSetSet(2, ‘Goanna’);
    }
    / unset the kiwi /
    foreach($object as $key=>$value)
    {
    / check the value of the key /
    if($object->offSetGet($key) === ‘kiwi’)
    {
    / unset the current key /
    $object->offSetUnset($key);
    }
    echo ‘

  • ‘.$key.’ – ‘.$value.’
  • ‘.”\n”;
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    13. RecursiveArrayIterator类和RecursiveIteratorIterator类

    ArrayIterator类和ArrayObject类,只帮忙遍历一维数组。如若要遍历多维数组,必须先用RecursiveIteratorIterator生成二个Iterator,然后再对这几个Iterator使用RecursiveIteratorIterator。

    <?php
    $array = array(
        array('name'=>'butch', 'sex'=>'m', 'breed'=>'boxer'),
        array('name'=>'fido', 'sex'=>'m', 'breed'=>'doberman'),
        array('name'=>'girly','sex'=>'f', 'breed'=>'poodle')
    );
    

    foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key=>$value)
    {
    echo $key.’ — ‘.$value.’
    ‘;
    }
    ?>

    14. FilterIterator类

    FilterIterator类能够对成分进行过滤,只要在accept()方法中装置过滤条件就足以了。

    以身作则如下:

    <?php
    /*** a simple array ***/
    $animals = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ'=>'kiwi', 'kookaburra', 'platypus');
    

    class CullingIterator extends FilterIterator{

    / The filteriterator takes a iterator as param: /
    public function construct( Iterator $it ){
    parent::
    construct( $it );
    }

    / check if key is numeric /
    function accept(){
    return is_numeric($this->key());
    }

    }/ end of class /
    $cull = new CullingIterator(new ArrayIterator($animals));

    foreach($cull as $key=>$value)
    {
    echo $key.’ == ‘.$value.’
    ‘;
    }
    ?>

    下边是另一个回来质数的事例:

    <?php
    

    class PrimeFilter extends FilterIterator{

    / The filteriterator takes a iterator as param: /
    public function construct(Iterator $it){
    parent::
    construct($it);
    }

    / check if current value is prime /
    function accept(){
    if($this->current() % 2 != 1)
    {
    return false;
    }
    $d = 3;
    $x = sqrt($this->current());
    while ($this->current() % $d != 0 && $d < $x) { $d += 2; } return (($this->current() % $d == 0 && $this->current() != $d) 1) == 0 ? true : false;
    }

    }/**
    end of class /

    /
    an array of numbers /
    $numbers = range(212345,212456);

    /
    create a new FilterIterator object ***/
    $primes = new primeFilter(new ArrayIterator($numbers));

    foreach($primes as $value)
    {
    echo $value.’ is prime.
    ‘;
    }
    ?>

    15. SimpleXMLIterator类

    本条类用来遍历xml文件。

    以身作则如下:

    <?php
    

    / a simple xml tree /
    $xmlstring = <<



    Phascolarctidae
    koala
    Bruce




    macropod
    kangaroo
    Bruce




    diprotodon
    wombat
    Bruce




    macropod
    wallaby
    Bruce




    dromaius
    emu
    Bruce




    Apteryx
    kiwi
    Troy




    kingfisher
    kookaburra
    Bruce




    monotremes
    platypus
    Bruce




    arachnid
    funnel web
    Bruce
    8



    XML;

    / a new simpleXML iterator object /
    try {
    / a new simple xml iterator /
    $it = new SimpleXMLIterator($xmlstring);
    / a new limitIterator object /
    foreach(new RecursiveIteratorIterator($it,1) as $name => $data)
    {
    echo $name.’ — ‘.$data.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    new RecursiveIteratorIterator($it,1)表示展现全部包罗父成分在内的子成分。

    显示某1个特定的要素值,能够这么写:

    <?php
    try {
        /*** a new simpleXML iterator object ***/
        $sxi =  new SimpleXMLIterator($xmlstring);
    

    foreach ( $sxi as $node )
    {
    foreach($node as $k=>$v)
    {
    echo $v->species.’
    ‘;
    }
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    相对应的while循环写法为:

    <?php
    

    try {
    $sxe = simplexml_load_string($xmlstring, ‘SimpleXMLIterator’);

    for ($sxe->rewind(); $sxe->valid(); $sxe->next())
    {
    if($sxe->hasChildren())
    {
    foreach($sxe->getChildren() as $element=>$value)
    {
    echo $value->species.’
    ‘;
    }
    }
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    最有利于的写法,依然采纳xpath:

    <?php
    try {
        /*** a new simpleXML iterator object ***/
        $sxi =  new SimpleXMLIterator($xmlstring);
    

    / set the xpath /
    $foo = $sxi->xpath(‘animal/category/species’);

    / iterate over the xpath /
    foreach ($foo as $k=>$v)
    {
    echo $v.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    下边包车型客车例证,显示有namespace的情形:

    <?php
    

    / a simple xml tree /
    $xmlstring = <<

    Phascolarctidae
    Speed Hump
    koala
    Bruce




    macropod
    Boonga
    kangaroo
    Bruce




    diprotodon
    pot holer
    wombat
    Bruce




    macropod
    Target
    wallaby
    Bruce




    dromaius
    Road Runner
    emu
    Bruce




    Apteryx
    Football
    kiwi
    Troy




    kingfisher
    snaker
    kookaburra
    Bruce




    monotremes
    Swamp Rat
    platypus
    Bruce




    arachnid
    Killer
    funnel web
    Bruce
    8



    XML;

    / a new simpleXML iterator object /
    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    $sxi-> registerXPathNamespace(‘spec’, ”);

    / set the xpath /
    $result = $sxi->xpath(‘//spec:name’);

    / get all declared namespaces /
    foreach($sxi->getDocNamespaces(‘animal’) as $ns)
    {
    echo $ns.’
    ‘;
    }

    / iterate over the xpath /
    foreach ($result as $k=>$v)
    {
    echo $v.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    扩张1个节点:

    <?php 
     $xmlstring = <<<XML
    <?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
    <document>
      <animal>koala</animal>
      <animal>kangaroo</animal>
      <animal>wombat</animal>
      <animal>wallaby</animal>
      <animal>emu</animal>
      <animal>kiwi</animal>
      <animal>kookaburra</animal>
      <animal>platypus</animal>
      <animal>funnel web</animal>
    </document>
    XML;
    

    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    / add a child /
    $sxi->addChild(‘animal’, ‘Tiger’);

    / a new simpleXML iterator object /
    $new = new SimpleXmlIterator($sxi->saveXML());

    / iterate over the new tree /
    foreach($new as $val)
    {
    echo $val.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    追加属性:

    <?php 
    $xmlstring =<<<XML
    <?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
    <document>
      <animal>koala</animal>
      <animal>kangaroo</animal>
      <animal>wombat</animal>
      <animal>wallaby</animal>
      <animal>emu</animal>
      <animal>kiwi</animal>
      <animal>kookaburra</animal>
      <animal>platypus</animal>
      <animal>funnel web</animal>
    </document>
    XML;
    

    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    / add an attribute with a namespace /
    $sxi->addAttribute(‘id:att1’, ‘good things’, ‘urn::test-foo’);

    / add an attribute without a namespace /
    $sxi->addAttribute(‘att2’, ‘no-ns’);

    echo htmlentities($sxi->saveXML());
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    16. CachingIterator类

    那几个类有一个hasNext()方法,用来判定是或不是还有下三个要素。

    演示如下:

    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    / create a new object /
    $object = new CachingIterator(new ArrayIterator($array));
    foreach($object as $value)
    {
    echo $value;
    if($object->hasNext())
    {
    echo ‘,’;
    }
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    17. LimitIterator类

    以此类用来限制再次来到结果集的数额和职责,必须提供offset和limit五个参数,与SQL命令中limit语句看似。

    示范如下:

    <?php
    /*** the offset value ***/
    $offset = 3;
    

    / the limit of records to show /
    $limit = 2;

    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    $it = new LimitIterator(new ArrayIterator($array), $offset, $limit);

    foreach($it as $k=>$v)
    {
    echo $it->getPosition().’
    ‘;
    }
    ?>

    另三个例证是:

    <?php
    

    / a simple array /
    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    $it = new LimitIterator(new ArrayIterator($array));

    try
    {
    $it->seek(5);
    echo $it->current();
    }
    catch(OutOfBoundsException $e)
    {
    echo $e->getMessage() . “
    “;
    }
    ?>

    18. SplFileObject类

    那么些类用来对文本文件实行遍历。

    以身作则如下:

    <?php
    

    try{
    // iterate directly over the object
    foreach( new SplFileObject("/usr/local/apache/logs/access_log") as $line)
    // and echo each line of the file
    echo $line.’
    ‘;
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    回来文本文件的第一行,可以这么写:

    <?php
    

    try{
    $file = new SplFileObject(“/usr/local/apache/logs/access_log”);

    $file->seek(3);

    echo $file->current();
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    [参考文献]

    1. Introduction to Standard PHP Library (SPL), By Kevin
      Waterson

    2. Introducing PHP 5’s Standard Library, By Harry
      Fuecks

    3.The Standard PHP Library (SPL), By Ben
    Ramsey

    1. SPL – Standard PHP Library
      Documentation

    (完)

    **摘自:

    原稿出处:
    blogspot   译文出处:51cto   


    后天《PHP设计方式漫谈》种类的支柱是迭代器(Iterator)格局,它在多个很常见的进程上提供了3个架空:位于对象图不明部分的一组对象(或标量)集合上的迭代。迭代有二种不一致的切切实实执行措施:在数组属性,集合对象,数组,甚至一个询问结果集之上迭代。

    PHP SPL笔记

    在目的的社会风气里,迭代器情势要保全接近数组的成效,看作是一个非侵入性对象刻面(facet),Client类往往分离自真人真事对象完成,指iterator接口。只要有大概,大家得以给迭代器传送一个引用,代替未来大概发生变化的求实或抽象类。

    目录

    澳门葡京备用网址 1
    图1 迭代器情势

    首先有的 简介

    参与者:

    1. 什么是SPL?

    2. 什么是Iterator?

    ◆客户端(Client):引用迭代器形式的点子在一组值或对象上进行贰个循环。

    其次片段 SPL Interfaces

    ◆迭代器(Iterator):在迭代经过上的画饼充饥,包含next(),isFinished(),current()等艺术。

    1. Iterator界面

    2. ArrayAccess界面

    3. IteratorAggregate界面

    4. RecursiveIterator界面

    5. SeekableIterator界面

    6. Countable界面

    ◆具体迭代器(ConcreteIterators):在一个一定的对象集,如数组,树,组合,集合等上兑现迭代。

    其三有个别 SPL Classes

    通过Traversable接口,PHP原生态支撑迭代器方式,那么些接口由Iterator和IteratorAggregate做了扩展,那多少个子接口不仅是概念了一套标准的法门,种种Traversable对象都能够维持原状地传递给foreach(),foreach是迭代器的机要客户端,Iterator完结是的确的迭代器,而IteratorAggregate是有任何职责的Traversable对象,它经过getIterator()方法重回一个Iterator。

    1. SPL的内置类

    2. DirectoryIterator类

    3. ArrayObject类

    4. ArrayIterator类

    5. RecursiveArrayIterator类和RecursiveIteratorIterator类

    6. FilterIterator类

    7. SimpleXMLIterator类

    8. CachingIterator类

    9. LimitIterator类

    10. SplFileObject类

    澳门葡京备用网址 2

    第一部 简介

    行业内部PHP库是PHP中绑定的唯一通用指标面向对象库,定义了附加的接口和公用类。OuterIterator达成装饰一个Iterator,CachingIterator和LimitIterator是以此接口的多少个例证。

    **1. 什么是SPL?**

    RecursiveIterator是Iterator接口为树形结构完结的二个扩展,它定义了一组相当的措施行检查查迭代中当前成分的子对象是否存在。RecursiveArrayIterator和RecursiveDirectoryIterator是其一接口的兑现示例,那个项指标迭代器能够形容使用,或是用1个RecursiveIteratorIterator桥接到多个普普通通的迭代器契约。那一个OuterIterator完成将会遵照结构参数执行深度优先或广度优先遍历。

    SPL是Standard PHP Library(PHP标准库)的缩写。

    运用RecursiveIteratorIterator时,能够将其传递给foreach,请看后面包车型地铁代码示例,精晓RecursiveIterators的不等用法和它们的超集Iterator。最终,SeekableIterators向契约添加了三个seek()方法,它能够用于移动Iterator的在那之中情状到3个一定的迭代点。

    基于官方概念,它是“a collection of interfaces and classes that are meant
    to solve standard
    problems”。可是,方今在采用中,SPL越来越多地被看作是一种使object(物体)模仿array(数组)行为的interfaces和
    classes。

    专注,迭代器是比对象集更好的架空,因为我们能够让InfiniteIterators,NoRewindIterators等,不用与常常数组阵列与同一,因此,Iterator紧缺count()函数等成效。

    2. 什么是Iterator?

    在PHP官方手册中得以找到完整的SPL迭代器列表。得益于对PHP的暴力帮衬,使用迭代器方式的多数工作都席卷在行业内部兑现中,下边包车型地铁代码示例就应用了正规Iterator和RecursiveIterators的效益。

    SPL的主导概念就是Iterator。这指的是一种Design Pattern,根据《Design
    Patterns》一书的概念,Iterator的功效是“provide an object which traverses
    some aggregate structure, abstracting away assumptions about the
    implementation of that structure.”

    PHP

    wikipedia中说,”an iterator is an object which allows a programmer to
    traverse through all the elements of a collection, regardless of its
    specific implementation”.……”the iterator pattern is a design pattern in
    which iterators are used to access the elements of an aggregate object
    sequentially without exposing its underlying representation”.

    <?php /** * Collection that wraps a numeric array. * All five
    public methods are needed to implement * the Iterator interface. */
    class Collection implements Iterator { private $_content; private
    $_澳门葡京备用网址 ,index = 0; public function __construct(array $content) {
    $this->_content = $content; } public function rewind() {
    $this->_index = 0; } public function valid() { return
    isset($this->_content[$this->_index]); } public function
    current() { return $this->_content[$this->_index]; } public
    function key() { return $this->_index; } public function next() {
    $this->_index++; } } $arrayarray = array(‘A’, ‘B’, ‘C’, ‘D’); echo
    “Collection: “; foreach (new Collection($array) as $key => $value) {
    echo “$key => $value. “; } echo “\n”;

    浅显地说,Iterator能够使比比皆是不一样的数据结构,都能有统一的操作界面,比如1个数据库的结果集、同1个索引中的文件集、也许3个文件中每一行构成的汇聚。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    <?php
    /**
    * Collection that wraps a numeric array.
    * All five public methods are needed to implement
    * the Iterator interface.
    */
    class Collection implements Iterator
    {
    private $_content;
    private $_index = 0;
     
    public function __construct(array $content)
    {
    $this->_content = $content;
    }
     
    public function rewind()
    {
    $this->_index = 0;
    }
     
    public function valid()
    {
    return isset($this->_content[$this->_index]);
    }
     
    public function current()
    {
    return $this->_content[$this->_index];
    }
     
    public function key()
    {
    return $this->_index;
    }
     
    public function next()
    {
    $this->_index++;
    }
    }
     
    $arrayarray = array(‘A’, ‘B’, ‘C’, ‘D’);
    echo "Collection: ";
    foreach (new Collection($array) as $key => $value) {
    echo "$key => $value. ";
    }
    echo "\n";

    倘若依据一般景况,遍历四个MySQL的结果集,程序要求这么写:

     

    // Fetch the "aggregate structure"
    $result = mysql_query("SELECT * FROM users");
    

    // Iterate over the structure
    while ( $row = mysql_fetch_array($result) ) {
    // do stuff with the row here
    }

    PHP

    读出2个索引中的内容,供给这么写:

    /** * Usually IteratorAggregate is the interface to implement. * It
    has only one method, which must return an Iterator * already defined as
    another class (e.g. ArrayIterator) * Iterator gives a finer control
    over the algorithm, * because all the hook points of Iterator’ contract
    * are available for implementation. */ class NumbersSet implements
    IteratorAggregate { private $_content; public function
    __construct(array $content) { $this->_content = $content; } public
    function contains($number) { return in_array($number,
    $this->_content); } /** * Only this method is necessary to
    implement IteratorAggregate. * @return Iterator */ public function
    getIterator() { return new ArrayIterator($this->_content); } } echo
    “NumbersSet: “; foreach (new NumbersSet($array) as $key => $value) {
    echo “$key => $value. “; } echo “\n”;

    // Fetch the "aggregate structure"
    $dh = opendir('/home/harryf/files');
    

    // Iterate over the structure
    while ( $file = readdir($dh) ) {
    // do stuff with the file here
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /**
    * Usually IteratorAggregate is the interface to implement.
    * It has only one method, which must return an Iterator
    * already defined as another class (e.g. ArrayIterator)
    * Iterator gives a finer control over the algorithm,
    * because all the hook points of Iterator’ contract
    * are available for implementation.
    */
    class NumbersSet implements IteratorAggregate
    {
    private $_content;
     
    public function __construct(array $content)
    {
    $this->_content = $content;
    }
     
    public function contains($number)
    {
    return in_array($number, $this->_content);
    }
     
    /**
    * Only this method is necessary to implement IteratorAggregate.
    * @return Iterator
    */
    public function getIterator()
    {
    return new ArrayIterator($this->_content);
    }
    }
     
    echo "NumbersSet: ";
    foreach (new NumbersSet($array) as $key => $value) {
    echo "$key => $value. ";
    }
    echo "\n";

    读出1个文书文件的情节,需求这么写:

     

    // Fetch the "aggregate structure"
    $fh = fopen("/home/hfuecks/files/results.txt", "r");
    

    // Iterate over the structure
    while (!feof($fh)) {

    $line = fgets($fh);
    // do stuff with the line here

    }

    PHP

    上边三段代码,就算处理的是见仁见智的resource(资源),可是效果皆以遍历结果集(loop
    over
    contents),因而Iterator的基本思维,正是将那三种不一致的操作统一起来,用平等的吩咐界面,处理分歧的财富。

    // let’s play with RecursiveIterator implementations $it = new
    RecursiveArrayIterator(array( ‘A’, ‘B’, array( ‘C’, ‘D’ ), array( array(
    ‘E’, ‘F’ ), array( ‘G’, ‘H’, ‘I’ ) ) )); // $it is a RecursiveIterator
    but also an Iterator, // so it loops normally over the four elements //
    of the array. echo “Foreach over a RecursiveIterator: “; foreach ($it as
    $value) { echo $value; // but RecursiveIterators specify additional //
    methods to explore children nodes $children = $it->hasChildren() ?
    ‘{Yes}’ : ‘{No}’; echo $children, ‘ ‘; } echo “\n”; // we can bridge it
    to a different contract via // a RecursiveIteratorIterator, whose
    cryptic name // should be read as ‘an Iterator that spans over // a
    RecursiveIterator’. echo “Foreach over a RecursiveIteratorIterator: “;
    foreach (new RecursiveIteratorIterator($it) as $value) { echo $value; }
    echo “\n”;

    其次有个别 SPL Interfaces

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // let’s play with RecursiveIterator implementations
    $it = new RecursiveArrayIterator(array(
    ‘A’,
    ‘B’,
    array(
    ‘C’,
    ‘D’
    ),
    array(
    array(
    ‘E’,
    ‘F’
    ),
    array(
    ‘G’,
    ‘H’,
    ‘I’
    )
    )
    ));
    // $it is a RecursiveIterator but also an Iterator,
    // so it loops normally over the four elements
    // of the array.
    echo "Foreach over a RecursiveIterator: ";
    foreach ($it as $value) {
    echo $value;
    // but RecursiveIterators specify additional
    // methods to explore children nodes
    $children = $it->hasChildren() ? ‘{Yes}’ : ‘{No}’;
    echo $children, ‘ ‘;
    }
    echo "\n";
    // we can bridge it to a different contract via
    // a RecursiveIteratorIterator, whose cryptic name
    // should be read as ‘an Iterator that spans over
    // a RecursiveIterator’.
    echo "Foreach over a RecursiveIteratorIterator: ";
    foreach (new RecursiveIteratorIterator($it) as $value) {
    echo $value;
    }
    echo "\n";

    3. Iterator界面

    1 赞 收藏 1
    评论

    SPL规定,全数配置了Iterator界面包车型客车class,都得以用在foreach
    Loop中。Iterator界面中蕴藏陆个必须配备的法子:

        * current()
    

    This method returns the current index’s value. You are solely
    responsible for tracking what the current index is as the
    interface does not do this for you.

        * key()
    

    This method returns the value of the current index’s key. For
    foreach loops this is extremely important so that the key
    value can be populated.

        * next()
    

    This method moves the internal index forward one entry.

        * rewind()
    

    This method should reset the internal index to the first element.

        * valid()
    

    This method should return true or false if there is a current
    element. It is called after rewind() or next().

    上边正是1个铺排了Iterator界面包车型客车class示例:

    /**
    * An iterator for native PHP arrays, re-inventing the wheel
    *
    * Notice the "implements Iterator" - important!
    */
    class ArrayReloaded implements Iterator {
    

    /**

       * A native PHP array to iterate over
       */
     private $array = array();
    

    /**

       * A switch to keep track of the end of the array
       */
     private $valid = FALSE;
    

    /**

       * Constructor
       * @param array native PHP array to iterate over
       */
     function __construct($array) {
       $this->array = $array;
     }
    

    /**

       * Return the array "pointer" to the first element
       * PHP's reset() returns false if the array has no elements
       */
     function rewind(){
       $this->valid = (FALSE !== reset($this->array));
     }
    

    /**

       * Return the current array element
       */
     function current(){
       return current($this->array);
     }
    

    /**

       * Return the key of the current array element
       */
     function key(){
       return key($this->array);
     }
    

    /**

       * Move forward by one
       * PHP's next() returns false if there are no more elements
       */
     function next(){
       $this->valid = (FALSE !== next($this->array));
     }
    

    /**

       * Is the current element valid?
       */
     function valid(){
       return $this->valid;
     }
    }
    

    利用格局如下:

    // Create iterator object
    $colors = new ArrayReloaded(array ('red','green','blue',));
    

    // Iterate away!
    foreach ( $colors as $color ) {
    echo $color.”
    “;
    }

    您也足以在foreach循环中央银行使key()方法:

    // Display the keys as well
    foreach ( $colors as $key => $color ) {
     echo "$key: $color<br>";
    }
    

    除此之外foreach循环外,也足以使用while循环,

    // Reset the iterator - foreach does this automatically
    $colors->rewind();
    

    // Loop while valid
    while ( $colors->valid() ) {

    echo $colors->key().”: “.$colors->current().”
    “;
    $colors->next();

    }

    传闻测试,while循环要稍快于foreach循环,因为运转时少了一层中间调用。

    **4. ArrayAccess界面**

    配置ArrayAccess界面,能够使得object像array那样操作。ArrayAccess界面包蕴多少个必须安顿的方法:

        * offsetExists($offset)
    

    This method is used to tell php if there is a value
    for the key specified by offset. It should return
    true or false.

        * offsetGet($offset)
    

    This method is used to return the value specified
    by the key offset.

        * offsetSet($offset, $value)
    

    This method is used to set a value within the object,
    you can throw an exception from this function for a
    read-only collection.

        * offsetUnset($offset)
    

    This method is used when a value is removed from
    an array either through unset() or assigning the key
    a value of null. In the case of numerical arrays, this
    offset should not be deleted and the array should
    not be reindexed unless that is specifically the
    behavior you want.

    上边正是一个安顿ArrayAccess界面包车型地铁实例:

    /**
    * A class that can be used like an array
    */
    class Article implements ArrayAccess {
    

    public $title;

    public $author;

    public $category;

    function __construct($title,$author,$category) {
    $this->title = $title;
    $this->author = $author;
    $this->category = $category;
    }

    /**

     * Defined by ArrayAccess interface
     * Set a value given it's key e.g. $A['title'] = 'foo';
     * @param mixed key (string or integer)
     * @param mixed value
     * @return void
     */
     function offsetSet($key, $value) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         $this->{$key} = $value;
       }
     }
    

    /**

     * Defined by ArrayAccess interface
     * Return a value given it's key e.g. echo $A['title'];
     * @param mixed key (string or integer)
     * @return mixed value
     */
     function offsetGet($key) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         return $this->{$key};
       }
     }
    

    /**

     * Defined by ArrayAccess interface
     * Unset a value by it's key e.g. unset($A['title']);
     * @param mixed key (string or integer)
     * @return void
     */
     function offsetUnset($key) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         unset($this->{$key});
       }
     }
    

    /**

     * Defined by ArrayAccess interface
     * Check value exists, given it's key e.g. isset($A['title'])
     * @param mixed key (string or integer)
     * @return boolean
     */
     function offsetExists($offset) {
       return array_key_exists($offset,get_object_vars($this));
     }
    

    }

    动用办法如下:

    // Create the object
    $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');
    

    // Check what it looks like
    echo ‘Initial State:

    ‘;
    print_r($A);
    echo ‘

    ‘;

    // Change the title using array syntax
    $A[‘title’] = ‘SPL really rocks’;

    // Try setting a non existent property (ignored)
    $A[‘not found’] = 1;

    // Unset the author field
    unset($A[‘author’]);

    // Check what it looks like again
    echo ‘Final State:

    ‘;
    print_r($A);
    echo ‘

    ‘;

    运维结果如下:

    Initial State:
    

    Article Object
    (
    [title] => SPL Rocks
    [author] => Joe Bloggs
    [category] => PHP
    )

    Final State:

    Article Object
    (
    [title] => SPL really rocks
    [category] => PHP
    )

    能够看看,$A固然是1个object,可是完全能够像array那样操作。

    你仍可以够在读取数据时,扩大程序内部的逻辑:

    function offsetGet($key) {
       if ( array_key_exists($key,get_object_vars($this)) ) {
         return strtolower($this->{$key});
       }
     }
    

    5. IteratorAggregate界面

    可是,尽管$A能够像数组那样操作,却无力回天利用foreach遍历,除非安排了前边提到的Iterator界面。

    另八个解决措施是,有时会必要将数据和遍历部分分离,那时就足以配备IteratorAggregate界面。它规定了二个getIterator()方法,再次回到3个应用Iterator界面包车型大巴object。

    也许以上一节的阿特icle类为例:

    class Article implements ArrayAccess, IteratorAggregate {
    

    /**

     * Defined by IteratorAggregate interface
     * Returns an iterator for for this object, for use with foreach
     * @return ArrayIterator
     */
     function getIterator() {
       return new ArrayIterator($this);
     }
    

    动用方法如下:

    $A = new Article('SPL Rocks','Joe Bloggs', 'PHP');
    

    // Loop (getIterator will be called automatically)
    echo ‘Looping with foreach:

    ‘;
    foreach ( $A as $field => $value ) {
    echo “$field : $value
    “;
    }
    echo ‘

    ‘;

    // Get the size of the iterator (see how many properties are left)
    echo “Object has “.sizeof($A->getIterator()).” elements”;

    浮现结果如下:

    Looping with foreach:
    

    title : SPL Rocks
    author : Joe Bloggs
    category : PHP

    Object has 3 elements

    6. RecursiveIterator界面

    那个界面用于遍历多层数据,它再而三了Iterator界面,由此也富有标准的current()、key()、next()、
    rewind()和valid()方法。同时,它和谐还规定了getChildren()和hasChildren()方法。The
    getChildren() method must return an object that implements
    RecursiveIterator.

    7. SeekableIterator界面

    SeekableIterator界面也是Iterator界面包车型大巴延长,除了Iterator的4个主意以外,还规定了seek()方法,参数是因素的职责,再次来到该因素。如果该职位不存在,则抛出OutOfBoundsException。

    下边是贰个是实例:

    <?php
    

    class PartyMemberIterator implements SeekableIterator
    {
    public function __construct(PartyMember $member)
    {
    // Store $member locally for iteration
    }

    public function seek($index)
    {
    $this->rewind();
    $position = 0;

    while ($position < $index && $this->valid()) {
    $this->next();
    $position++;
    }

    if (!$this->valid()) {
    throw new OutOfBoundsException(‘Invalid position’);
    }
    }

    // Implement current(), key(), next(), rewind()
    // and valid() to iterate over data in $member
    }

    ?>

    8. Countable界面

    其一界面规定了一个count()方法,再次来到结果集的数额。

    其三局地 SPL Classes

    9. SPL的内置类

    SPL除了定义一名目繁多Interfaces以外,还提供一种类的内置类,它们对应不一样的职分,大大简化了编制程序。

    查看全数的内置类,可以利用下边包车型地铁代码:

    <?php
    // a simple foreach() to traverse the SPL class names
    foreach(spl_classes() as $key=>$value)
            {
            echo $key.' -&gt; '.$value.'<br />';
            }
    ?>
    

    10. DirectoryIterator类

    那些类用来查阅3个索引中的所有文件和子目录:

    <?php
    

    try{
    / class create new DirectoryIterator Object /
    foreach ( new DirectoryIterator(‘./’) as $Item )
    {
    echo $Item.’
    ‘;
    }
    }
    / if an exception is thrown, catch it here /
    catch(Exception $e){
    echo ‘No files Found!
    ‘;
    }
    ?>

    翻看文件的详细新闻:

    <table>
    <?php
    

    foreach(new DirectoryIterator(‘./’ ) as $file )
    {
    if( $file->getFilename() == ‘foo.txt’ )
    {
    echo ‘

    getFilename() ‘; var_dump($file->getFilename()); echo ‘

    ‘;
    echo ‘

    getBasename() ‘; var_dump($file->getBasename()); echo ‘

    ‘;
    echo ‘

    isDot() ‘; var_dump($file->isDot()); echo ‘

    ‘;
    echo ‘

    __toString() ‘; var_dump($file->__toString()); echo ‘

    ‘;
    echo ‘

    getPath() ‘; var_dump($file->getPath()); echo ‘

    ‘;
    echo ‘

    getPathname() ‘; var_dump($file->getPathname()); echo ‘

    ‘;
    echo ‘

    getPerms() ‘; var_dump($file->getPerms()); echo ‘

    ‘;
    echo ‘

    getInode() ‘; var_dump($file->getInode()); echo ‘

    ‘;
    echo ‘

    getSize() ‘; var_dump($file->getSize()); echo ‘

    ‘;
    echo ‘

    getOwner() ‘; var_dump($file->getOwner()); echo ‘

    ‘;
    echo ‘

    $file->getGroup() ‘; var_dump($file->getGroup()); echo ‘

    ‘;
    echo ‘

    getATime() ‘; var_dump($file->getATime()); echo ‘

    ‘;
    echo ‘

    getMTime() ‘; var_dump($file->getMTime()); echo ‘

    ‘;
    echo ‘

    getCTime() ‘; var_dump($file->getCTime()); echo ‘

    ‘;
    echo ‘

    getType() ‘; var_dump($file->getType()); echo ‘

    ‘;
    echo ‘

    isWritable() ‘; var_dump($file->isWritable()); echo ‘

    ‘;
    echo ‘

    isReadable() ‘; var_dump($file->isReadable()); echo ‘

    ‘;
    echo ‘

    isExecutable( ‘; var_dump($file->isExecutable()); echo ‘

    ‘;
    echo ‘

    isFile() ‘; var_dump($file->isFile()); echo ‘

    ‘;
    echo ‘

    isDir() ‘; var_dump($file->isDir()); echo ‘

    ‘;
    echo ‘

    isLink() ‘; var_dump($file->isLink()); echo ‘

    ‘;
    echo ‘

    getFileInfo() ‘; var_dump($file->getFileInfo()); echo ‘

    ‘;
    echo ‘

    getPathInfo() ‘; var_dump($file->getPathInfo()); echo ‘

    ‘;
    echo ‘

    openFile() ‘; var_dump($file->openFile()); echo ‘

    ‘;
    echo ‘

    setFileClass() ‘; var_dump($file->setFileClass()); echo ‘

    ‘;
    echo ‘

    setInfoClass() ‘; var_dump($file->setInfoClass()); echo ‘

    ‘;
    }
    }
    ?>

    除去foreach循环外,还足以应用while循环:

    <?php
    /*** create a new iterator object ***/
    $it = new DirectoryIterator('./');
    

    / loop directly over the object /
    while($it->valid())
    {
    echo $it->key().’ — ‘.$it->current().’
    ‘;
    / move to the next iteration /
    $it->next();
    }
    ?>

    假定要过滤全体子目录,能够在valid()方法中过滤:

    <?php
    /*** create a new iterator object ***/
    $it = new DirectoryIterator('./');
    

    / loop directly over the object /
    while($it->valid())
    {
    / check if value is a directory /
    if($it->isDir())
    {
    / echo the key and current value /
    echo $it->key().’ — ‘.$it->current().’
    ‘;
    }
    / move to the next iteration /
    $it->next();
    }
    ?>

    11. ArrayObject类

    以此类可以将Array转化为object。

    <?php
    

    / a simple array /
    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    / create the array object /
    $arrayObj = new ArrayObject($array);

    / iterate over the array /
    for($iterator = $arrayObj->getIterator();
    / check if valid /
    $iterator->valid();
    / move to the next array member /
    $iterator->next())
    {
    / output the key and current array value /
    echo $iterator->key() . ‘ => ‘ . $iterator->current() . ‘
    ‘;
    }
    ?>

    扩充二个成分:

    $arrayObj->append('dingo');
    

    对成分排序:

    $arrayObj->natcasesort();
    

    体现成分的多寡:

    echo $arrayObj->count();
    

    去除2个要素:

    $arrayObj->offsetUnset(5);
    

    某贰个因素是还是不是留存:

     if ($arrayObj->offsetExists(3))
        {
           echo 'Offset Exists<br />';
        }
    

    变更某些地方的成分值:

     $arrayObj->offsetSet(5, "galah");
    

    展现某些地点的成分值:

    echo $arrayObj->offsetGet(4);
    

    **12. ArrayIterator类**

    其一类实际上是对ArrayObject类的补给,为后代提供遍历成效。

    示范如下:

    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    $object = new ArrayIterator($array);
    foreach($object as $key=>$value)
    {
    echo $key.’ => ‘.$value.’
    ‘;
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    ArrayIterator类也支撑offset类措施和count()方法:

    <ul>
    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    $object = new ArrayIterator($array);
    / check for the existence of the offset 2 /
    if($object->offSetExists(2))
    {
    / set the offset of 2 to a new value /
    $object->offSetSet(2, ‘Goanna’);
    }
    / unset the kiwi /
    foreach($object as $key=>$value)
    {
    / check the value of the key /
    if($object->offSetGet($key) === ‘kiwi’)
    {
    / unset the current key /
    $object->offSetUnset($key);
    }
    echo ‘

  • ‘.$key.’ – ‘.$value.’
  • ‘.”\n”;
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    13. RecursiveArrayIterator类和RecursiveIteratorIterator类

    ArrayIterator类和ArrayObject类,只协助遍历一维数组。假若要遍历多维数组,必须先用
    RecursiveIteratorIterator生成1个Iterator,然后再对这几个Iterator使用
    RecursiveIteratorIterator。

    <?php
    $array = array(
        array('name'=>'butch', 'sex'=>'m', 'breed'=>'boxer'),
        array('name'=>'fido', 'sex'=>'m', 'breed'=>'doberman'),
        array('name'=>'girly','sex'=>'f', 'breed'=>'poodle')
    );
    

    foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key=>$value)
    {
    echo $key.’ — ‘.$value.’
    ‘;
    }
    ?>

    14. FilterIterator类

    FilterIterator类能够对成分举行过滤,只要在accept()方法中设置过滤条件就能够了。

    演示如下:

    <?php
    /*** a simple array ***/
    $animals = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ'=>'kiwi', 'kookaburra', 'platypus');
    

    class CullingIterator extends FilterIterator{

    / The filteriterator takes a iterator as param: /
    public function construct( Iterator $it ){
    parent::
    construct( $it );
    }

    / check if key is numeric /
    function accept(){
    return is_numeric($this->key());
    }

    }/ end of class /
    $cull = new CullingIterator(new ArrayIterator($animals));

    foreach($cull as $key=>$value)
    {
    echo $key.’ == ‘.$value.’
    ‘;
    }
    ?>

    下边是另二个回到质数的例子:

    <?php
    

    class PrimeFilter extends FilterIterator{

    / The filteriterator takes a iterator as param: /
    public function construct(Iterator $it){
    parent::
    construct($it);
    }

    / check if current value is prime /
    function accept(){
    if($this->current() % 2 != 1)
    {
    return false;
    }
    $d = 3;
    $x = sqrt($this->current());
    while ($this->current() % $d != 0 && $d < $x) { $d += 2; } return (($this->current() % $d == 0 && $this->current() != $d) 1) == 0 ? true : false;
    }

    }/**
    end of class /

    /
    an array of numbers /
    $numbers = range(212345,212456);

    /
    create a new FilterIterator object ***/
    $primes = new primeFilter(new ArrayIterator($numbers));

    foreach($primes as $value)
    {
    echo $value.’ is prime.
    ‘;
    }
    ?>

    15. SimpleXMLIterator类

    以此类用来遍历xml文件。

    演示如下:

    <?php
    

    / a simple xml tree /
    $xmlstring = <<



    Phascolarctidae
    koala
    Bruce




    macropod
    kangaroo
    Bruce




    diprotodon
    wombat
    Bruce




    macropod
    wallaby
    Bruce




    dromaius
    emu
    Bruce




    Apteryx
    kiwi
    Troy




    kingfisher
    kookaburra
    Bruce




    monotremes
    platypus
    Bruce




    arachnid
    funnel web
    Bruce
    8



    XML;

    / a new simpleXML iterator object /
    try {
    / a new simple xml iterator /
    $it = new SimpleXMLIterator($xmlstring);
    / a new limitIterator object /
    foreach(new RecursiveIteratorIterator($it,1) as $name => $data)
    {
    echo $name.’ — ‘.$data.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    new RecursiveIteratorIterator($it,1)表示展现全体包含父成分在内的子成分。

    来得某三个一定的要素值,能够如此写:

    <?php
    try {
        /*** a new simpleXML iterator object ***/
        $sxi =  new SimpleXMLIterator($xmlstring);
    

    foreach ( $sxi as $node )
    {
    foreach($node as $k=>$v)
    {
    echo $v->species.’
    ‘;
    }
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    相呼应的while循环写法为:

    <?php
    

    try {
    $sxe = simplexml_load_string($xmlstring, ‘SimpleXMLIterator’);

    for ($sxe->rewind(); $sxe->valid(); $sxe->next())
    {
    if($sxe->hasChildren())
    {
    foreach($sxe->getChildren() as $element=>$value)
    {
    echo $value->species.’
    ‘;
    }
    }
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    最便宜的写法,依旧选拔xpath:

    <?php
    try {
        /*** a new simpleXML iterator object ***/
        $sxi =  new SimpleXMLIterator($xmlstring);
    

    / set the xpath /
    $foo = $sxi->xpath(‘animal/category/species’);

    / iterate over the xpath /
    foreach ($foo as $k=>$v)
    {
    echo $v.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    下边包车型客车事例,彰显有namespace的景况:

    <?php
    

    / a simple xml tree /
    $xmlstring = <<

    Phascolarctidae
    Speed Hump
    koala
    Bruce




    macropod
    Boonga
    kangaroo
    Bruce




    diprotodon
    pot holer
    wombat
    Bruce




    macropod
    Target
    wallaby
    Bruce




    dromaius
    Road Runner
    emu
    Bruce




    Apteryx
    Football
    kiwi
    Troy




    kingfisher
    snaker
    kookaburra
    Bruce




    monotremes
    Swamp Rat
    platypus
    Bruce




    arachnid
    Killer
    funnel web
    Bruce
    8



    XML;

    / a new simpleXML iterator object /
    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    $sxi-> registerXPathNamespace(‘spec’, ”);

    / set the xpath /
    $result = $sxi->xpath(‘//spec:name’);

    / get all declared namespaces /
    foreach($sxi->getDocNamespaces(‘animal’) as $ns)
    {
    echo $ns.’
    ‘;
    }

    / iterate over the xpath /
    foreach ($result as $k=>$v)
    {
    echo $v.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    日增一个节点:

    <?php 
     $xmlstring = <<<XML
    <?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
    <document>
      <animal>koala</animal>
      <animal>kangaroo</animal>
      <animal>wombat</animal>
      <animal>wallaby</animal>
      <animal>emu</animal>
      <animal>kiwi</animal>
      <animal>kookaburra</animal>
      <animal>platypus</animal>
      <animal>funnel web</animal>
    </document>
    XML;
    

    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    / add a child /
    $sxi->addChild(‘animal’, ‘Tiger’);

    / a new simpleXML iterator object /
    $new = new SimpleXmlIterator($sxi->saveXML());

    / iterate over the new tree /
    foreach($new as $val)
    {
    echo $val.’
    ‘;
    }
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    充实质量:

    <?php 
    $xmlstring =<<<XML
    <?xml version = "1.0" encoding="UTF-8" standalone="yes"?>
    <document>
      <animal>koala</animal>
      <animal>kangaroo</animal>
      <animal>wombat</animal>
      <animal>wallaby</animal>
      <animal>emu</animal>
      <animal>kiwi</animal>
      <animal>kookaburra</animal>
      <animal>platypus</animal>
      <animal>funnel web</animal>
    </document>
    XML;
    

    try {
    / a new simpleXML iterator object /
    $sxi = new SimpleXMLIterator($xmlstring);

    / add an attribute with a namespace /
    $sxi->addAttribute(‘id:att1’, ‘good things’, ‘urn::test-foo’);

    / add an attribute without a namespace /
    $sxi->addAttribute(‘att2’, ‘no-ns’);

    echo htmlentities($sxi->saveXML());
    }
    catch(Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    16. CachingIterator类

    本条类有三个hasNext()方法,用来判断是还是不是还有下一个要素。

    示范如下:

    <?php
    /*** a simple array ***/
    $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
    

    try {
    / create a new object /
    $object = new CachingIterator(new ArrayIterator($array));
    foreach($object as $value)
    {
    echo $value;
    if($object->hasNext())
    {
    echo ‘,’;
    }
    }
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    17. LimitIterator类

    这些类用来界定再次回到结果集的数据和地方,必须提供offset和limit三个参数,与SQL命令中limit语句看似。

    示范如下:

    <?php
    /*** the offset value ***/
    $offset = 3;
    

    / the limit of records to show /
    $limit = 2;

    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    $it = new LimitIterator(new ArrayIterator($array), $offset, $limit);

    foreach($it as $k=>$v)
    {
    echo $it->getPosition().’
    ‘;
    }
    ?>

    另三个例证是:

    <?php
    

    / a simple array /
    $array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

    $it = new LimitIterator(new ArrayIterator($array));

    try
    {
    $it->seek(5);
    echo $it->current();
    }
    catch(OutOfBoundsException $e)
    {
    echo $e->getMessage() . “
    “;
    }
    ?>

    18. SplFileObject类

    这么些类用来对文件文件进行遍历。

    示范如下:

    <?php
    

    try{
    // iterate directly over the object
    foreach( new SplFileObject("/usr/local/apache/logs/access_log") as $line)
    // and echo each line of the file
    echo $line.’
    ‘;
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    回到文本文件的第贰行,能够那样写:

    <?php
    

    try{
    $file = new SplFileObject(“/usr/local/apache/logs/access_log”);

    $file->seek(3);

    echo $file->current();
    }
    catch (Exception $e)
    {
    echo $e->getMessage();
    }
    ?>

    [参考文献]

    1. Introduction to Standard PHP Library (SPL), By Kevin
      Waterson

    2. Introducing PHP 5’s Standard Library, By Harry
      Fuecks

    3.The Standard PHP Library (SPL), By Ben
    Ramsey

    1. SPL – Standard PHP Library
      Documentation

    (完)

    相关文章

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注

    *
    *
    Website