SPL
在线手册:中文  英文

SPL 函数

Table of Contents


SPL
在线手册:中文  英文

用户评论:

benny at whitewashing dot de (2008-07-22 09:56:04)

I have to correct my implementation from before. The example before only supported correct read-access but failed on setting new values after creation of the ArrayMultiObject. Also i had to correct a bug that occured from my CopyPasteChange into the comment textarea.

This snippet now hopefully implements a fully functional multidimensional array, represented by an ArrayObject:

<?php
class ArrayMultiObject extends ArrayObject
{
    function 
__construct($array$flags 0$iterator_class "ArrayIterator")
    {
        
$objects = array();
        foreach(
$array AS $key => $value) {
            if(
is_array($value)) {
                
$objects[$key] = new ArrayMultiObject($value$flags$iterator_class);
            } else {
                
$objects[$key] = $value;
            }
        }

        
parent::__construct($objects$flags$iterator_class);
    }

    public function 
offsetSet($name$value)
    {
        if(
is_array($value)) {
            
$value = new ArrayMultiObject($value);
        }

        return 
parent::offsetSet($name$value);
    }
}
?>

loaded67 at hotmail dot com (2008-05-19 13:56:54)

For some application I needed to reverse some standard iterators. 

So I mocked up this flexible function.
Enjoy

<?php
function reverse_iterator(Iterator $iterator){
    
$type     get_class($iterator);
    
$array     array_reverse(iterator_to_array($iterator), true);
    return new 
$type($array);
}
?>

chad 0x40 herballure 0x2e com (2007-12-12 06:57:31)

My favorite recursive iteration solution:

<?php
$dir_iter 
= new RecursiveDirectoryIterator($root_dir0);
$all_iter = new RecursiveIteratorIterator($dir_iter);

foreach (
$all_iter as $abs_path => $info) {
  
// your code here
}
?>

You can't just loop on $dir_iter, because it will return the exact same results as the plain DirectoryIterator. It is the RecursiveIteratorIterator that iterates over the children of the RecursiveDirectoryIterator if they're present.

Passing 0 as the flags to the RecursiveDirectoryIterator means that $info will be a RecursiveDirectoryIterator object, and then you can use the getSubPath() and getSubPathname() methods to find the directory (or directory and filename, resp.) relative to $root_dir. By default, $info is a SplFileInfo object instead, which only knows its full pathname, including $root_dir. The RecursiveDirectoryIterator extends SplFileInfo, so all those methods are still available.

prometheus - csaba dot dobai at php-sparcle dot hu (2007-09-13 02:33:37)

This code is an example. By using classes like this, you gives a chance to create classes which extends another class but have most of the ability what a class extends ArrayObject (like multiple inheritance):

<?php

class foo 
{
    public 
$foo 'foo';
// class

class foobar extends foo implements ArrayAccess,IteratorAggregate,Countable
{
    public function 
offsetExists($offset)
    {
        
$array = array(1234);
        return 
array_key_exists($offset$array);
    }
    
    public function 
offsetGet($offset)
    {
        
$array = array(1234);
        return 
$array[$offset];
    }
    
    public function 
offsetSet($offset$value)
    {
        
// Makes "array" to readonly
    
}
    
    public function 
offsetUnset($offset)
    {
        
// Makes "array" to readonly
    
}
    
    function 
count()
    {
        
$array = array(1234);
        return 
count($array);
    } 
// function
    
    
function getArray()
    {
        return array(
1234);
    } 
// function
    
    
function getIterator()
    {
        return new 
ArrayIterator(array(1234));
    } 
// function
    
    
function __toString()
    {
        return 
'String test';
    } 
// function
// class

$foobar = new foobar();
print 
$foobar[0].'<br/>';
print 
$foobar->foo.'<br/>';
print 
count($foobar).'<br/>';

foreach (
$foobar as $k=>$v)
{
    print 
$k.'=>'.$v.'<br/>';
// foreach

var_dump($foobar->getArray());

print 
$foobar;

/* Generated output:
1
foo
4
0=>1
1=>2
2=>3
3=>4
array
  0 => int 1
  1 => int 2
  2 => int 3
  3 => int 4
String test
*/
?>

For proper use you must be define all these methods except getArray()

Browse SPL's sources to be a very helpful think.

ps.: sry for my english

semperluc (at) yahoo._forgot_the_rest (2007-02-01 13:43:54)

<?php 
/*
How to store SPL Iterator results (rather than just echo-and-forget):

The library of Iterators  are object based, so you need to trick the little rascals into an array.  
Here's how (two ways) ...

1. Explicit typecasts: $a[] = (array)$Obj->objMethod();

2. Array definition: $a[] = array( key => $Obj->objMethod() );

Examples: DirectoryIterator()
*/

// 1. explicity typecast object as array
foreach ( new DirectoryIterator('./') as $Item )
{
  
$fname = (array)$Item->getFilename();
  
$dir_listing[] = $fname[0];
}

//
echo "<pre>";
print_r($dir_listing); unset($dir_listing);
echo
"</pre><hr />";
//

// or

// 2. define array as key => object->method
foreach ( new DirectoryIterator('./') as $Item )
{
  
$dir_listing[] = array (
    
"fname" => $Item->getFilename(),        
    
"path" => $Item->getPathname(),
    
"size" => $Item->getSize(),                    
    
"mtime" => $Item->getMTime() 
  );
}

//
echo "<pre>";
print_r($dir_listing); unset($dir_listing);
echo
"</pre>";
//
?>

kevin at oceania dot net (2006-03-07 00:21:45)

The most comprehensive of all tutorials regarding SPL has been written with some help from Marcus and can be found here.
http://www.phpro.org/tutorials/Introduction-to-SPL.html
Enjoy

ville</.>witt</a>gmail</.>com (2006-01-12 12:37:26)

These to funtions has excatly the same output, the only diff. is in which directory iterator they use. I hope someone out there can use it:
<?php
function listfilesin1 ($dir "."$depth=0) {
    echo 
"Dir: ".$dir."<br/>";
    foreach(new 
DirectoryIterator($dir) as $file) {
        if (!
$file->isDot()) {
            if (
$file->isDir()) {
                
$newdir $file->getPathname();
                
listfilesin1($newdir$depth+1);
            } else {
                echo 
"($depth)".$file->getPathname() . "<br/>";
            }
        }
    }
}
function 
listfilesin2 ($dir "."$depth=0) {
    echo 
"Dir: ".$dir."<br/>";
    foreach(new 
RecursiveDirectoryIterator($dir) as $file) {
        if (
$file->hasChildren(false)) {
            
$newdir $file->key();
            
listfilesin2($newdir$depth+1);
        } else {
            echo 
"($depth)".$file->key() . "<br/>";
        }
    }
}
listfilesin();
?>

jce at vt dot ilw dot agrl dot ethz dot ch (2005-11-10 11:51:25)

You may access the ArrayObject as an array by using explicit typecasts:
class myArrayObject extends ArrayObject
{
function getArray()
{
return (array) $this;
}
}

adove at booyahnetworks dot com (2005-10-10 10:45:37)

Something to note that, at least to me, seems pretty important and is not entirely clear in the documentation is the fact that the ArrayObject class supports get/set on uni-dimensional keys and get ONLY on *passed* multi-dimensional keys/paths (see source below). If you, like me, need to support array accesss overloading for multi-dimensional data, you will need to derive from ArrayObject and overide the ArrayAccess interface methods to "walk" passed data and convert embedded arrays to objects of some kind...
Reference Bug 34816 @ http://bugs.php.net/bug.php?id=34816.
Illustration of the issue:
$a = array(
"test" => array(
"one" => "dunno",
"two" => array(
"peekabo" => "do you see me?",
"anyone" => array("there")
)
)
);
$oArray = new ArrayObject($a);
var_dump($oArray);
$oArray["three"] = "No problems here.";
echo "\n\\test\\one == " . $oArray["test"]["one"] . "\n\n";
// NEITHER of the two below will work!
$oArray["test"]["one"] = "Yes I do!";
$oArray["test"]["yes"] = array(
"hello" => "Goodbye!"
);
var_dump($oArray);
---
Note from the extension author:
Actually there is RecursiveArrayObject and RecursiveArrayIterator to deal with recursive structures. However this does not always solve all multidimensional issues as expected.

helly at php dot net (2005-09-25 02:41:36)

There is a RecursiveFilterIterator that makes the above code much easier. And then ther is ParentIterator thta is already a filtering recursive iterator that only accepts elements that have children, with a RecursiveDirectoryIterator as inner iterator you would obviously get only the directories. Further more it ensures that it creates the correct children. All in all you simply need to do this:
$it = new RecursiveDirectoryIterator($path);
$it = new ParentIterator($it);
$it = new RecursiveIteratorIteator($it);
foreach($it as $dir => $o) { ... }

ericjr [!_ at _!] junioronline dot us (2005-07-12 04:57:59)

In addition to "mastabog at hotmail dot com"`s note about the recursive directory iterator, his method skips symlinked directories, because getChildren() doesn't return true if the directory is symlinked.

To fix this, the script should always instanciate an innerInterator when dealing with symlinked directories like so:

<?
class DirectoriesOnlyIterator extends FilterIterator implements RecursiveIterator
{
   public function __construct ($path)
   {
       parent::__construct(new RecursiveDirectoryIterator($path));
   }

   public function accept()
   {
       return $this->getInnerIterator()->hasChildren();
   }

   public function hasChildren ()
   {
       return $this->hasChildren() || $this->isLink();
   }
   
   public function getChildren ()
   {
       return new self($this->getInnerIterator()->getPathname());
   }
}

just_somedood at yahoo dot com (2005-06-27 12:11:04)

Just a follow up on dave at tunasoft's post.  To give his example of ArrayAccess use of foreach, it's easiest to implement IteratorAggregate and use the ArrayIterator object as the iterator, as below:

<?php 

class Collection implements ArrayAccess,IteratorAggregate
{
    public 
$objectArray = Array();
    
//**these are the required iterator functions    
    
function offsetExists($offset)
    {          
        if(isset(
$this->objectArray[$offset]))  return TRUE;
        else return 
FALSE;          
    }    
    
    function & 
offsetGet($offset)
    {   
        if (
$this->offsetExists($offset))  return $this->objectArray[$offset];
        else return (
false);
    }
    
    function 
offsetSet($offset$value)
    {          
        if (
$offset)  $this->objectArray[$offset] = $value;
        else  
$this->objectArray[] = $value;
    }
    
    function 
offsetUnset($offset)
    {
        unset (
$this->objectArray[$offset]);
    }
    
    function & 
getIterator()
    {
        return new 
ArrayIterator($this->objectArray);
    }
    
//**end required iterator functions

    
public function doSomething()
    {
        echo 
"I'm doing something";
    }
}

?>

I LOVE the new SPL stuff in PHP.  The above allows you to have methods inside of your array, and when treated as an array the data components are returned, such as:

<?php
class Contact
{
    protected 
$name NULL;

    public function 
set_name($name)
    {
        
$this->name $name;
    }
    
    public function 
get_name()
    {
        return (
$this->name);
    }
}

$bob = new Collection();
$bob->doSomething();
$bob[] = new Contact();
$bob[5] = new Contact();
$bob[0]->set_name("Superman");
$bob[5]->set_name("a name of a guy");

foreach (
$bob as $aContact)
{
     echo 
$aContact->get_name() . "\r\n";
}
?>

Would work just fine.  This make code so much simpler and easy to follow, it's great.  This is exactly the direction I had hoped PHP5 was going!

zaufi at sendmail dot ru (2005-04-17 07:24:54)

I'v done with my PluginsManager... Sample code to use plugins may looks lije this:
<?php
require_once('lib/plugins-manager.inc.php');

// Load and use conctere plugin module
$p = new Plugin('test.class.php');
$test $p->class_factory('test'12);
$test->foo();

// ... oneliner ;)
$p $pm['test.class.php']->class_factory('test'12)->foo();

// Scan for plugable modules, construct an instance and call foo()
$pm = new PluginsManager('.');
foreach (
$pm as $p)
{
    
$p->class_factory('test'12)->foo();
}

?>

You may download php files at my tw.o page: http://tikiwiki.org/tiki-index.php?page=UserPagezaufi (see page attachments below)

<nospam>mike[ at ]emesdee.net</nospam> (2004-11-22 12:47:44)

Excelent article here by Harry Fuecks...
http://www.sitepoint.com/print/php5-standard-library
and some auto generated documentation that could be of some use here...
http://www.php.net/~helly/php/ext/spl/index.html

dave at tunasoft dot com (2004-08-10 06:28:25)

There are some interfaces used here that are not documented.  It took a bit to figure this one out, but you can create your own ArrayObject type class (that is, one who's objects can be access using the array [$index] syntax).

Your class must just implement ArrayAccess.  Which has four abstract methods you must define.  For example:

<?php
    
class Collection Implements ArrayAccess{
    
        protected 
$array;
        
        function 
offsetExists($offset){
            
            if(isset(
$this->array[$offset])){
                return 
TRUE;
            }
            else{
                return 
FALSE;
            }
            
        }
        
        function 
offsetGet($offset){
            
            return 
$this->array[$offset];
            
        }
        
        function 
offsetSet($offset$value){
            
            if(
$offset){
                
$this->array[$offset] = $value;
            }
            else{
                
$this->array[] = $value;
            }
        
        }
        
        function 
offsetUnset($offset){
        
        }
    
    
    }
?>

You'll have to jump through a couple more hoops to get foreach and print_r and the likes to behave properly.  But with just this, you can :

<?php
      $col 
= new Collction();
      
$col[] = new ObjectX();
      
$col[] = new ObjectX(123);

      echo 
$col[0]->name;
      
// etc.
?>

phil &ampersat; flatnet.net (2004-04-17 15:11:37)

Here's a sample implementation of the RecursiveDirectoryIterator class. It prints a simple treeview of a given directory:
<?php 
function recurse($it) { 
   echo 
'<ul>'
   for( ; 
$it->valid(); $it->next()) { 
       if(
$it->isDir() && !$it->isDot()) { 
           
printf('<li class="dir">%s</li>'$it->current()); 
           if(
$it->hasChildren()) { 
               
$bleh $it->getChildren(); 
               echo 
'<ul>' recurse($bleh) . '</ul>'
           } 
       } elseif(
$it->isFile()) { 
           echo 
'<li class="file">'$it->current() . ' (' $it->getSize(). ' Bytes)</li>'
       } 
   } 
   echo 
'</ul>'


recurse(new RecursiveDirectoryIterator('D:/')); 
?>

易百教程