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);
}
}
?>
Standard PHP Library (SPL) Functions
소개
SPL is a collection of interfaces and classes that are meant to solve standard problems.
Tip
A more detailed documentation of SPL can be found » here.
설치
This extension is available and compiled by default in PHP 5.
예약 상수
이 확장은 다음의 상수들을 정의합니다. 이 확장을 PHP에 내장했거나, 실행시에 동적으로 읽어들일 경우에만 사용할 수 있습니다.
Warning
SPL uses class constants since PHP 5.1. Prior releases use global constants in the form RIT_LEAVES_ONLY.
Table of Contents
- ArrayIterator::current — Return current array entry
- ArrayIterator::key — Return current array key
- ArrayIterator::next — Move to next entry
- ArrayIterator::rewind — Rewind array back to the start
- ArrayIterator::seek — Seek to position
- ArrayIterator::valid — Check whether array contains more entries
- ArrayObject::append — Appends the value
- ArrayObject::__construct — Construct a new array object
- ArrayObject::count — Return the number of elements in the Iterator
- ArrayObject::getIterator — Create a new iterator from an ArrayObject instance
- ArrayObject::offsetExists — Returns whether the requested $index exists
- ArrayObject::offsetGet — Returns the value at the specified $index
- ArrayObject::offsetSet — Sets the value at the specified $index to $newval
- ArrayObject::offsetUnset — Unsets the value at the specified $index
- CachingIterator::hasNext — Check whether the inner iterator has a valid next element
- CachingIterator::next — Move the iterator forward
- CachingIterator::rewind — Rewind the iterator
- CachingIterator::__toString — Return the string representation of the current element
- CachingIterator::valid — Check whether the current element is valid
- CachingRecursiveIterator::getChildren — Return the inner iterator's children as a CachingRecursiveIterator
- CachingRecursiveIterator::hasChildren — Check whether the current element of the inner iterator has children
- DirectoryIterator::__construct — Constructs a new dir iterator from a path
- DirectoryIterator::current — Return this (needed for Iterator interface)
- DirectoryIterator::getATime — Get last access time of file
- DirectoryIterator::getCTime — Get inode modification time of file
- DirectoryIterator::getFilename — Return filename of current dir entry
- DirectoryIterator::getGroup — Get file group
- DirectoryIterator::getInode — Get file inode
- DirectoryIterator::getMTime — Get last modification time of file
- DirectoryIterator::getOwner — Get file owner
- DirectoryIterator::getPath — Return directory path
- DirectoryIterator::getPathname — Return path and filename of current dir entry
- DirectoryIterator::getPerms — Get file permissions
- DirectoryIterator::getSize — Get file size
- DirectoryIterator::getType — Get file type
- DirectoryIterator::isDir — Returns true if file is directory
- DirectoryIterator::isDot — Returns true if current entry is '.' or '..'
- DirectoryIterator::isExecutable — Returns true if file is executable
- DirectoryIterator::isFile — Returns true if file is a regular file
- DirectoryIterator::isLink — Returns true if file is symbolic link
- DirectoryIterator::isReadable — Returns true if file can be read
- DirectoryIterator::isWritable — Returns true if file can be written
- DirectoryIterator::key — Return current dir entry
- DirectoryIterator::next — Move to next entry
- DirectoryIterator::rewind — Rewind dir back to the start
- DirectoryIterator::valid — Check whether dir contains more entries
- FilterIterator::current — Get the current element value
- FilterIterator::getInnerIterator — Get the inner iterator
- FilterIterator::key — Get the current key
- FilterIterator::next — Move the iterator forward
- FilterIterator::rewind — Rewind the iterator
- FilterIterator::valid — Check whether the current element is valid
- LimitIterator::getPosition — Return the current position
- LimitIterator::next — Move the iterator forward
- LimitIterator::rewind — Rewind the iterator to the specified starting offset
- LimitIterator::seek — Seek to the given position
- LimitIterator::valid — Check whether the current element is valid
- ParentIterator::getChildren — Return the inner iterator's children contained in a ParentIterator
- ParentIterator::hasChildren — Check whether the inner iterator's current element has children
- ParentIterator::next — Move the iterator forward
- ParentIterator::rewind — Rewind the iterator
- RecursiveDirectoryIterator::getChildren — Returns an iterator for the current entry if it is a directory
- RecursiveDirectoryIterator::hasChildren — Returns whether current entry is a directory and not '.' or '..'
- RecursiveDirectoryIterator::key — Return path and filename of current dir entry
- RecursiveDirectoryIterator::next — Move to next entry
- RecursiveDirectoryIterator::rewind — Rewind dir back to the start
- RecursiveIteratorIterator::current — Access the current element value
- RecursiveIteratorIterator::getDepth — Get the current depth of the recursive iteration
- RecursiveIteratorIterator::getSubIterator — The current active sub iterator
- RecursiveIteratorIterator::key — Access the current key
- RecursiveIteratorIterator::next — Move forward to the next element
- RecursiveIteratorIterator::rewind — Rewind the iterator to the first element of the top level inner iterator
- RecursiveIteratorIterator::valid — Check whether the current position is valid
- SimpleXMLIterator::current — Return current SimpleXML entry
- SimpleXMLIterator::getChildren — Returns an iterator for the current entry if it is a SimpleXML object
- SimpleXMLIterator::hasChildren — Returns whether current entry is a SimpleXML object
- SimpleXMLIterator::key — Return current SimpleXML key
- SimpleXMLIterator::next — Move to next entry
- SimpleXMLIterator::rewind — Rewind SimpleXML back to the start
- SimpleXMLIterator::valid — Check whether SimpleXML contains more entries
- class_implements — Return the interfaces which are implemented by the given class
- class_parents — Return the parent classes of the given class
- iterator_count — Count the elements in an iterator
- iterator_to_array — Copy the iterator into an array
- spl_autoload_call — Try all registered __autoload() function to load the requested class
- spl_autoload_extensions — Register and return default file extensions for spl_autoload
- spl_autoload_functions — Return all registered __autoload() functions
- spl_autoload_register — Register given function as __autoload() implementation
- spl_autoload_unregister — Unregister given function as __autoload() implementation
- spl_autoload — Default implementation for __autoload()
- spl_classes — Return available SPL classes
- spl_object_hash — Return hash id for given object
spl
benny at whitewashing dot de
22-Jul-2008 09:56
22-Jul-2008 09:56
loaded67 at hotmail dot com
19-May-2008 01:56
19-May-2008 01:56
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
12-Dec-2007 06:57
12-Dec-2007 06:57
My favorite recursive iteration solution:
<?php
$dir_iter = new RecursiveDirectoryIterator($root_dir, 0);
$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
13-Sep-2007 02:33
13-Sep-2007 02:33
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(1, 2, 3, 4);
return array_key_exists($offset, $array);
}
public function offsetGet($offset)
{
$array = array(1, 2, 3, 4);
return $array[$offset];
}
public function offsetSet($offset, $value)
{
// Makes "array" to readonly
}
public function offsetUnset($offset)
{
// Makes "array" to readonly
}
function count()
{
$array = array(1, 2, 3, 4);
return count($array);
} // function
function getArray()
{
return array(1, 2, 3, 4);
} // function
function getIterator()
{
return new ArrayIterator(array(1, 2, 3, 4));
} // 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
01-Feb-2007 01:43
01-Feb-2007 01:43
<?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
07-Mar-2006 12:21
07-Mar-2006 12:21
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
12-Jan-2006 12:37
12-Jan-2006 12:37
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
10-Nov-2005 11:51
10-Nov-2005 11:51
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
10-Oct-2005 10:45
10-Oct-2005 10:45
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
25-Sep-2005 02:41
25-Sep-2005 02:41
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
12-Jul-2005 04:57
12-Jul-2005 04:57
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
27-Jun-2005 12:11
27-Jun-2005 12:11
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
17-Apr-2005 07:24
17-Apr-2005 07:24
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', 1, 2);
$test->foo();
// ... oneliner ;)
$p = $pm['test.class.php']->class_factory('test', 1, 2)->foo();
// Scan for plugable modules, construct an instance and call foo()
$pm = new PluginsManager('.');
foreach ($pm as $p)
{
$p->class_factory('test', 1, 2)->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>
22-Nov-2004 12:47
22-Nov-2004 12:47
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
mastabog at hotmail dot com
17-Aug-2004 02:41
17-Aug-2004 02:41
Marcus Boerger has done a wonderful job developing the SPL. He also provided many examples using the SPL that can be found in the php5 sources. Just unpack the sources and in the ext/spl/examples directory you have some very nice ones. Thank you Marcus for all your efforts!
Now, a contribution of mine (i think it will be implemented later anyway). The RecursiveIteratorIterator could use a depth limit option. Very useful in many situations (e.g. show just the 1st subdirectory of a list of dirs). I'm sure this can be done in other ways. Here's my 2 cents:
<?php
/**
* Limit Depth RecursiveIteratorIterator class
*
*/
class LimitRecursiveIteratorIterator extends RecursiveIteratorIterator
{
protected $depth_limit;
/**
* No depth limit by default
*
**/
public function __construct (Iterator $it, $mode = RIT_SELF_FIRST, $depth_limit = -1)
{
parent::__construct($it, $mode);
$this->depth_limit = $depth_limit;
}
/**
* After the call to next() if depth is bigger than limit then
* just skip all subIterators for that depth until depth end.
*
**/
public function next ()
{
parent::next();
if ($this->getDepth() == $this->depth_limit)
{
while ($this->getSubIterator()->valid())
$this->getSubIterator()->next();
parent::next();
}
}
}
?>
Then you can try this:
<?php
/**
* Directories only filter iterator class
*
*/
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->getInnerIterator()->hasChildren();
}
public function getChildren ()
{
return new self($this->getInnerIterator()->getPathname());
}
}
$it = new LimitRecursiveIteratorIterator(new DirectoriesOnlyIterator('c:'), RIT_SELF_FIRST, 2);
// list all dirs and 1st subdir of the c: drive (might take a while depending on how many you have)
foreach ($it as $key => $value)
{
echo str_repeat(' ', $it->getDepth()) . "$value\n";
}
?>
This is considerably faster than using just the RecursiveIteratorIterator and ignoring yourself in the foreach loop the values for depth > limit (i.e. if($it->getDepth() > $limit) continue;). that is because the class will still parse everything up to the last depth level of every head node.
You can then play and display nice trees (might need a while() loop or the CachingRecursiveIterator to detect end nodes/leafs). There is already an example provided by Marcus in the ext/spl/examples dir i mentioned above.
Happy SPL-ing :),
Bogdan
P.S. I think some of the classes should call rewind() at instantiation time ... If you try to put a Caching* object in a foreach loop you will lose the first/last element. Instead, you should call rewind() and then go with a while($cit->valid()) loop and using current() and key() inside it.
dave at tunasoft dot com
10-Aug-2004 06:28
10-Aug-2004 06:28
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 &ersat; flatnet.net
17-Apr-2004 03:11
17-Apr-2004 03:11
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:/'));
?>
