summaryrefslogtreecommitdiff
path: root/ext/spl
diff options
context:
space:
mode:
authorMark A. Hershberger <mah@debian.(none)>2009-03-25 00:36:21 -0400
committerMark A. Hershberger <mah@debian.(none)>2009-03-25 00:36:21 -0400
commitd29a4fd2dd3b5d4cf6e80b602544d7b71d794e76 (patch)
treeb38e2e5c6974b9a15f103e5cf884cba9fff90ef4 /ext/spl
parenta88a88d0986a4a32288c102cdbfebd78d7e91d99 (diff)
downloadphp-upstream/5.2.0.tar.gz
Imported Upstream version 5.2.0upstream/5.2.0
Diffstat (limited to 'ext/spl')
-rwxr-xr-xext/spl/config.m47
-rwxr-xr-xext/spl/doxygen.cfg4
-rwxr-xr-xext/spl/examples/dualiterator.inc212
-rwxr-xr-xext/spl/examples/recursivedualiterator.inc72
-rwxr-xr-xext/spl/examples/tests/dualiterator_001.phpt47
-rwxr-xr-xext/spl/internal/filteriterator.inc10
-rwxr-xr-xext/spl/internal/recursiveregexiterator.inc61
-rwxr-xr-xext/spl/internal/regexiterator.inc163
-rwxr-xr-xext/spl/internal/splfileobject.inc40
-rwxr-xr-xext/spl/php_spl.c83
-rwxr-xr-xext/spl/spl.php264
-rwxr-xr-xext/spl/spl_array.c303
-rwxr-xr-xext/spl/spl_array.h3
-rwxr-xr-xext/spl/spl_directory.c360
-rwxr-xr-xext/spl/spl_directory.h7
-rwxr-xr-xext/spl/spl_exceptions.c4
-rwxr-xr-xext/spl/spl_functions.c18
-rwxr-xr-xext/spl/spl_functions.h8
-rwxr-xr-xext/spl/spl_iterators.c978
-rwxr-xr-xext/spl/spl_iterators.h51
-rwxr-xr-xext/spl/spl_observer.c4
-rwxr-xr-xext/spl/tests/array_013.phpt2
-rwxr-xr-xext/spl/tests/array_019.phpt4
-rwxr-xr-xext/spl/tests/array_021.phpt2
-rwxr-xr-xext/spl/tests/array_022.phpt26
-rwxr-xr-xext/spl/tests/bug36941.phpt2
-rwxr-xr-xext/spl/tests/bug37457.phpt82
-rwxr-xr-xext/spl/tests/fileobject_003.phpt89
-rwxr-xr-xext/spl/tests/iterator_027.phpt85
-rwxr-xr-xext/spl/tests/iterator_029.phpt40
-rw-r--r--ext/spl/tests/iterator_035.phpt2
-rwxr-xr-xext/spl/tests/iterator_036.phpt24
-rwxr-xr-xext/spl/tests/iterator_037.phpt133
-rwxr-xr-xext/spl/tests/iterator_038.phpt21
-rwxr-xr-xext/spl/tests/iterator_039.phpt123
-rwxr-xr-xext/spl/tests/iterator_040.phpt49
-rwxr-xr-xext/spl/tests/iterator_041.phpt119
-rwxr-xr-xext/spl/tests/iterator_041a.phpt109
-rwxr-xr-xext/spl/tests/iterator_041b.phpt107
-rwxr-xr-xext/spl/tests/iterator_042.phpt104
-rwxr-xr-xext/spl/tests/iterator_043.phpt20
-rwxr-xr-xext/spl/tests/iterator_044.phpt169
-rwxr-xr-xext/spl/tests/iterator_045.phpt171
-rwxr-xr-xext/spl/tests/iterator_046.phpt53
-rwxr-xr-xext/spl/tests/iterator_047.phpt119
-rwxr-xr-xext/spl/tests/iterator_048.phpt38
-rwxr-xr-xext/spl/tests/iterator_049.phpt24
-rwxr-xr-xext/spl/tests/iterator_049b.phptbin0 -> 616 bytes
-rwxr-xr-xext/spl/tests/iterator_050.phpt93
-rwxr-xr-xext/spl/tests/iterator_051.phpt95
-rwxr-xr-xext/spl/tests/iterator_052.phpt314
-rwxr-xr-xext/spl/tests/iterator_053.phpt314
-rwxr-xr-xext/spl/tests/iterator_054.phpt84
-rwxr-xr-xext/spl/tests/iterator_055.phpt61
-rwxr-xr-xext/spl/tests/spl_004.phpt86
-rwxr-xr-xext/spl/tests/spl_005.phpt23
56 files changed, 5005 insertions, 481 deletions
diff --git a/ext/spl/config.m4 b/ext/spl/config.m4
index 470b89d8e..30f4f7806 100755
--- a/ext/spl/config.m4
+++ b/ext/spl/config.m4
@@ -1,13 +1,10 @@
-dnl $Id: config.m4,v 1.13.2.4 2006/01/06 14:03:37 sniper Exp $
+dnl $Id: config.m4,v 1.13.2.4.2.1 2006/08/23 09:47:21 tony2001 Exp $
dnl config.m4 for extension SPL
PHP_ARG_ENABLE(spl, enable SPL suppport,
[ --disable-spl Disable Standard PHP Library], yes)
if test "$PHP_SPL" != "no"; then
- if test "$ext_shared" = "yes"; then
- AC_MSG_ERROR(Cannot build SPL as a shared module)
- fi
AC_MSG_CHECKING(whether zend_object_value is packed)
old_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$INCLUDES -I$abs_srcdir $CPPFLAGS"
@@ -29,5 +26,5 @@ int main(int argc, char **argv) {
CPPFLAGS=$old_CPPFLAGS
AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed])
AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support])
- PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c, $ext_shared)
+ PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_sxe.c spl_exceptions.c spl_observer.c, no)
fi
diff --git a/ext/spl/doxygen.cfg b/ext/spl/doxygen.cfg
index d58017a6a..4b7178723 100755
--- a/ext/spl/doxygen.cfg
+++ b/ext/spl/doxygen.cfg
@@ -194,10 +194,10 @@ PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
-HAVE_DOT = NO
+HAVE_DOT = YES
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
-UML_LOOK = NO
+UML_LOOK = YES
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
diff --git a/ext/spl/examples/dualiterator.inc b/ext/spl/examples/dualiterator.inc
new file mode 100755
index 000000000..544034856
--- /dev/null
+++ b/ext/spl/examples/dualiterator.inc
@@ -0,0 +1,212 @@
+<?php
+
+/** @file dualiterator.inc
+ * @ingroup Examples
+ * @brief class DualIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Synchronous iteration over two iterators
+ * @author Marcus Boerger
+ * @version 1.1
+ */
+class DualIterator implements Iterator
+{
+ const CURRENT_LHS = 0x01;
+ const CURRENT_RHS = 0x02;
+ const CURRENT_ARRAY = 0x03;
+ const CURRENT_0 = 0x00;
+
+ const KEY_LHS = 0x10;
+ const KEY_RHS = 0x20;
+ const KEY_ARRAY = 0x30;
+ const KEY_0 = 0x00;
+
+ const DEFAULT_FLAGS = 0x33;
+
+ private $lhs;
+ private $rhs;
+ private $flags;
+
+ /** construct iterator from two iterators
+ *
+ * @param lhs Left Hand Side Iterator
+ * @param rhs Right Hand Side Iterator
+ * @param flags iteration flags
+ */
+ function __construct(Iterator $lhs, Iterator $rhs,
+ $flags = 0x33 /*DualIterator::DEFAULT_FLAGS*/)
+ {
+ $this->lhs = $lhs;
+ $this->rhs = $rhs;
+ $this->flags = $flags;
+ }
+
+ /** @return Left Hand Side Iterator
+ */
+ function getLHS()
+ {
+ return $this->lhs;
+ }
+
+ /** @return Right Hand Side Iterator
+ */
+ function getRHS()
+ {
+ return $this->rhs;
+ }
+
+ /** @param flags new flags
+ */
+ function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /** @return current flags
+ */
+ function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /** rewind both inner iterators
+ */
+ function rewind()
+ {
+ $this->lhs->rewind();
+ $this->rhs->rewind();
+ }
+
+ /** @return whether both inner iterators are valid
+ */
+ function valid()
+ {
+ return $this->lhs->valid() && $this->rhs->valid();
+ }
+
+ /** @return current value depending on CURRENT_* flags
+ */
+ function current()
+ {
+ switch($this->flags & 0x0F)
+ {
+ default:
+ case self::CURRENT_ARRAY:
+ return array($this->lhs->current(), $this->rhs->current());
+ case self::CURRENT_LHS:
+ return $this->lhs->current();
+ case self::CURRENT_RHS:
+ return $this->rhs->current();
+ case self::CURRENT_0:
+ return NULL;
+ }
+ }
+
+ /** @return current value depending on KEY_* flags
+ */
+ function key()
+ {
+ switch($this->flags & 0xF0)
+ {
+ default:
+ case self::CURRENT_ARRAY:
+ return array($this->lhs->key(), $this->rhs->key());
+ case self::CURRENT_LHS:
+ return $this->lhs->key();
+ case self::CURRENT_RHS:
+ return $this->rhs->key();
+ case self::CURRENT_0:
+ return NULL;
+ }
+ }
+
+ /** move both inner iterators forward
+ */
+ function next()
+ {
+ $this->lhs->next();
+ $this->rhs->next();
+ }
+
+ /** @return whether both inner iterators are valid and have identical
+ * current and key values or both are non valid.
+ */
+ function areIdentical()
+ {
+ return $this->valid()
+ ? $this->lhs->current() === $this->rhs->current()
+ && $this->lhs->key() === $this->rhs->key()
+ : $this->lhs->valid() == $this->rhs->valid();
+ }
+
+ /** @return whether both inner iterators are valid and have equal current
+ * and key values or both are non valid.
+ */
+ function areEqual()
+ {
+ return $this->valid()
+ ? $this->lhs->current() == $this->rhs->current()
+ && $this->lhs->key() == $this->rhs->key()
+ : $this->lhs->valid() == $this->rhs->valid();
+ }
+
+ /** Compare two iterators
+ *
+ * @param lhs Left Hand Side Iterator
+ * @param rhs Right Hand Side Iterator
+ * @param identical whether to use areEqual() or areIdentical()
+ * @return whether both iterators are equal/identical
+ *
+ * @note If one implements RecursiveIterator the other must do as well.
+ * And if both do then a recursive comparison is being used.
+ */
+ static function compareIterators(Iterator $lhs, Iterator $rhs,
+ $identical = false)
+ {
+ if ($lhs instanceof RecursiveIterator)
+ {
+ if ($rhs instanceof RecursiveIterator)
+ {
+ $it = new RecursiveDualIterator($lhs, $rhs,
+ self::CURRENT_0 | self::KEY_0);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ $it = new DualIterator($lhs, $rhs, self::CURRENT_0 | self::KEY_0);
+ }
+
+ if ($identical)
+ {
+ foreach(new RecursiveIteratorIterator($it) as $n)
+ {
+ if (!$it->areIdentical())
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ foreach($it as $n)
+ {
+ if (!$it->areEqual())
+ {
+ return false;
+ }
+ }
+ }
+ return $identical ? $it->areIdentical() : $it->areEqual();
+ }
+}
+
+?>
diff --git a/ext/spl/examples/recursivedualiterator.inc b/ext/spl/examples/recursivedualiterator.inc
new file mode 100755
index 000000000..702e0cd74
--- /dev/null
+++ b/ext/spl/examples/recursivedualiterator.inc
@@ -0,0 +1,72 @@
+<?php
+
+/** @file recursivedualiterator.inc
+ * @ingroup Examples
+ * @brief class RecursiveDualIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/** @ingroup Examples
+ * @brief Synchronous iteration over two recursive iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ */
+class RecursiveDualIterator extends DualIterator implements RecursiveIterator
+{
+ private $ref;
+
+ /** construct iterator from two iterators
+ *
+ * @param lhs Left Hand Side Iterator
+ * @param rhs Right Hand Side Iterator
+ * @param flags iteration flags
+ */
+ function __construct(RecursiveIterator $lhs, RecursiveIterator $rhs,
+ $flags = 0x33 /*DualIterator::DEFAULT_FLAGS*/)
+ {
+ parent::__construct($lhs, $rhs, $flags);
+ }
+
+ /** @return whether both LHS and RHS have children
+ */
+ function hasChildren()
+ {
+ return $this->getLHS()->hasChildren() && $this->getRHS()->hasChildren();
+ }
+
+ /** @return new RecursiveDualIterator (late binding) for the two inner
+ * iterators current children.
+ */
+ function getChildren()
+ {
+ if (empty($this->ref))
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ return $this->ref->newInstance(
+ $this->getLHS()->getChildren(), $this->getRHS()->getChildren(), $this->getFlags());
+ }
+
+ /** @return whether both inner iterators are valid, have same hasChildren()
+ * state and identical current and key values or both are non valid.
+ */
+ function areIdentical()
+ {
+ return $this->getLHS()->hasChildren() === $this->getRHS()->hasChildren()
+ && parent::areIdentical();
+ }
+
+ /** @return whether both inner iterators are valid, have same hasChildren()
+ * state and equal current and key values or both are invalid.
+ */
+ function areEqual()
+ {
+ return $this->getLHS()->hasChildren() === $this->getRHS()->hasChildren()
+ && parent::areEqual();
+ }
+}
+
+?>
diff --git a/ext/spl/examples/tests/dualiterator_001.phpt b/ext/spl/examples/tests/dualiterator_001.phpt
new file mode 100755
index 000000000..5577c4dc1
--- /dev/null
+++ b/ext/spl/examples/tests/dualiterator_001.phpt
@@ -0,0 +1,47 @@
+--TEST--
+SPL: DualIterator
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function spl_examples_autoload($classname)
+{
+ include(dirname(__FILE__) . '/../' . strtolower($classname) . '.inc');
+}
+
+spl_autoload_register('spl_examples_autoload');
+
+function test($a, $b, $identical = false)
+{
+ var_dump(DualIterator::compareIterators(
+ new RecursiveArrayIterator($a),
+ new RecursiveArrayIterator($b),
+ $identical));
+}
+
+test(array(1,2,3), array(1,2,3));
+test(array(1,2,3), array(1,2));
+test(array(1,array(21,22),3), array(1,array(21,22),3));
+test(array(1,array(21,22),3), array(1,array(21,22,23),3));
+test(array(1,array(21,22),3), array(1,array(21,22,3)));
+test(array(1,array(21,22),3), array(1,array(21),array(22),3));
+test(array(1,2,3), array(1,"2",3), false);
+test(array(1,2,3), array(1,"2",3), true);
+test(array(1,array(21,22),3), array(1,array(21,"22"),3), false);
+test(array(1,array(21,22),3), array(1,array(21,"22"),3), true);
+
+?>
+===DONE===
+--EXPECT--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+===DONE===
diff --git a/ext/spl/internal/filteriterator.inc b/ext/spl/internal/filteriterator.inc
index ddf161355..c0b5681d2 100755
--- a/ext/spl/internal/filteriterator.inc
+++ b/ext/spl/internal/filteriterator.inc
@@ -4,13 +4,13 @@
* @ingroup SPL
* @brief class FilterIterator
* @author Marcus Boerger
- * @date 2003 - 2005
+ * @date 2003 - 2006
*
* SPL - Standard PHP Library
*/
/**
- * @brief Regular expression filter for string iterators
+ * @brief Abstract filter for iterators
* @author Marcus Boerger
* @version 1.1
* @since PHP 5.0
@@ -28,11 +28,9 @@ abstract class FilterIterator implements OuterIterator
private $it;
/**
- * Constructs a filter around an iterator whose elemnts are strings.
- * If the given iterator is of type spl_sequence then its rewind()
- * method is called.
+ * Constructs a filter around another iterator.
*
- * @param it Object that implements at least spl_forward
+ * @param it Iterator to filter
*/
function __construct(Iterator $it) {
$this->it = $it;
diff --git a/ext/spl/internal/recursiveregexiterator.inc b/ext/spl/internal/recursiveregexiterator.inc
new file mode 100755
index 000000000..df47d6197
--- /dev/null
+++ b/ext/spl/internal/recursiveregexiterator.inc
@@ -0,0 +1,61 @@
+<?php
+
+/** @file recursiveregexiterator.inc
+ * @ingroup SPL
+ * @brief class RegexIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Recursive regular expression filter for iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ *
+ * This filter iterator assumes that the inner iterator
+ */
+class RecursiveRegexIterator extends RegexIterator implements RecursiveIterator
+{
+ /**
+ * Constructs a regular expression filter around an iterator whose
+ * elemnts or keys are strings.
+ *
+ * @param it inner iterator
+ * @param regex the regular expression to match
+ * @param mode operation mode (one of self::MATCH, self::GET_MATCH,
+ * self::ALL_MATCHES, self::SPLIT)
+ * @param flags special flags (self::USE_KEY)
+ * @param preg_flags global PREG_* flags, see preg_match(),
+ * preg_match_all(), preg_split()
+ */
+ function __construct(RecursiveIterator $it, $regex, $mode = 0, $flags = 0, $preg_flags = 0) {
+ parent::__construct($it, $regex, $mode, $flags, $preg_flags);
+ }
+
+ /** @return whether the current element has children
+ */
+ function hasChildren()
+ {
+ return $this->getInnerIterator()->hasChildren();
+ }
+
+ /** @return an iterator for the current elements children
+ *
+ * @note the returned iterator will be of the same class as $this
+ */
+ function getChildren()
+ {
+ if (empty($this->ref))
+ {
+ $this->ref = new ReflectionClass($this);
+ }
+ return $this->ref->newInstance($this->getInnerIterator()->getChildren());
+ }
+
+ private $ref;
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/regexiterator.inc b/ext/spl/internal/regexiterator.inc
new file mode 100755
index 000000000..05eb4b1d9
--- /dev/null
+++ b/ext/spl/internal/regexiterator.inc
@@ -0,0 +1,163 @@
+<?php
+
+/** @file regexiterator.inc
+ * @ingroup SPL
+ * @brief class RegexIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2006
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Regular expression filter for iterators
+ * @author Marcus Boerger
+ * @version 1.0
+ * @since PHP 5.1
+ *
+ * This filter iterator assumes that the inner iterator
+ */
+class RegexIterator implements FilterIterator
+{
+ const USE_KEY = 0x00000001; /**< If present in $flags the the key is
+ used rather then the current value. */
+
+ const MATCH = 0; /**< Mode: Executed a plain match only */
+ const GET_MATCH = 1; /**< Mode: Return the first matche (if any) */
+ const ALL_MATCHES = 2; /**< Mode: Return all matches (if any) */
+ const SPLIT = 3; /**< Mode: Return the split values (if any) */
+ const REPLACE = 4; /**< Mode: Replace the input key or current */
+
+ private $regex; /**< the regular expression to match against */
+ private $mode; /**< operation mode (one of self::MATCH,
+ self::GET_MATCH, self::ALL_MATCHES, self::SPLIT) */
+ private $flags; /**< special flags (self::USE_KEY) */
+ private $preg_flags;/**< PREG_* flags, see preg_match(), preg_match_all(),
+ preg_split() */
+ private $key; /**< the value used for key() */
+ private $current; /**< the value used for current() */
+
+ /**
+ * Constructs a regular expression filter around an iterator whose
+ * elemnts or keys are strings.
+ *
+ * @param it inner iterator
+ * @param regex the regular expression to match
+ * @param mode operation mode (one of self::MATCH, self::GET_MATCH,
+ * self::ALL_MATCHES, self::SPLIT)
+ * @param flags special flags (self::USE_KEY)
+ * @param preg_flags global PREG_* flags, see preg_match(),
+ * preg_match_all(), preg_split()
+ */
+ function __construct(Iterator $it, $regex, $mode = 0, $flags = 0, $preg_flags = 0) {
+ parent::__construct($it);
+ $this->regex = $regex;
+ $this->flags = $flags;
+ $this->mode = $mode;
+ $this->preg_flags = $preg_flags;
+ }
+
+ /**
+ * Match current or key against regular expression using mode, flags and
+ * preg_flags.
+ *
+ * @return whether this is a match
+ *
+ * @warning never call this twice for the same state
+ */
+ function accept()
+ {
+ $matches = array();
+ $this->key = parent::key();
+ $this->current = parent::current();
+ /* note that we use $this->current, rather than calling parent::current() */
+ $subject = ($this->flags & self::USE_KEY) ? $this->key : $this->current;
+ switch($this->mode)
+ {
+ case self::MATCH:
+ return preg_match($this->regex, $subject, $matches, $this->preg_flags);
+
+ case self::GET_MATCH:
+ $this->current = array();
+ return preg_match($this->regex, $subject, $this->current, $this->preg_flags) > 0;
+
+ case self::ALL_MATCHES:
+ $this->current = array();
+ return preg_match_all($this->regex, $subject, $this->current, $this->preg_flags) > 0;
+
+ case self::SPLIT:
+ $this->current = array();
+ preg_split($this->regex, $subject, $this->current, $this->preg_flags) > 1;
+
+ case self::REPLACE:
+ $this->current = array();
+ $result = preg_replace($this->regex, $this->replacement, $subject);
+ if ($this->flags & self::USE_KEY)
+ {
+ $this->key = $result;
+ }
+ else
+ {
+ $this->current = $result;
+ }
+ }
+ }
+
+ /** @return the key after accept has been called
+ */
+ function key()
+ {
+ return $this->key;
+ }
+
+ /** @return the current value after accept has been called
+ */
+ function current()
+ {
+ return $this->current;
+ }
+
+ /** @return current operation mode
+ */
+ function getMode()
+ {
+ return $this->mode;
+ }
+
+ /** @param mode new operaion mode
+ */
+ function setMode($mode)
+ {
+ $this->mode = $mode;
+ }
+
+ /** @return current operation flags
+ */
+ function getFlags()
+ {
+ return $this->flags;
+ }
+
+ /** @param flags new operaion flags
+ */
+ function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
+ /** @return current PREG flags
+ */
+ function getPregFlags()
+ {
+ return $this->preg_flags;
+ }
+
+ /** @param preg_flags new PREG flags
+ */
+ function setPregFlags($preg_flags)
+ {
+ $this->preg_flags = $preg_flags;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/ext/spl/internal/splfileobject.inc b/ext/spl/internal/splfileobject.inc
index bb1a23929..5f746ea2d 100755
--- a/ext/spl/internal/splfileobject.inc
+++ b/ext/spl/internal/splfileobject.inc
@@ -4,7 +4,7 @@
* @ingroup SPL
* @brief class FileObject
* @author Marcus Boerger
- * @date 2003 - 2005
+ * @date 2003 - 2006
*
* SPL - Standard PHP Library
*/
@@ -12,10 +12,10 @@
/** @ingroup SPL
* @brief Object representation for any stream
* @author Marcus Boerger
- * @version 1.0
+ * @version 1.1
* @since PHP 5.1
*/
-class SplFileObject implements RecursiveIterator, SeekableIterator
+class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator
{
/** Flag: wheter to suppress new lines */
const DROP_NEW_LINE = 0x00000001;
@@ -26,6 +26,8 @@ class SplFileObject implements RecursiveIterator, SeekableIterator
private $lnum = 0;
private $max_len = 0;
private $flags = 0;
+ private $delimiter= ',';
+ private $enclosure= '"';
/**
* Constructs a new file object
@@ -80,14 +82,44 @@ class SplFileObject implements RecursiveIterator, SeekableIterator
* @param enclosure end of
* @return array containing read data
*/
- function fgetcsv($delimiter = ';', $enclosure = '')
+ function fgetcsv($delimiter = NULL, $enclosure = NULL)
{
$this->freeLine();
$this->lnum++;
+ switch(fun_num_args())
+ {
+ case 0:
+ $delimiter = $this->delimiter;
+ case 1:
+ $enclosure = $this->enclosure;
+ default:
+ case 2:
+ break;
+ }
return fgetcsv($this->fp, $this->max_len, $delimiter, $enclosure);
}
/**
+ * Set the delimiter and enclosure character used in fgetcsv
+ *
+ * @param delimiter new delimiter, defaults to ','
+ * @param enclosure new enclosure, defaults to '"'
+ */
+ function setCsvControl($delimiter = ';', $enclosure = '"')
+ {
+ $this->delimiter = $delimiter;
+ $this->enclosure = $enclosure;
+ }
+
+ /**
+ * @return array(delimiter, enclosure) as used in fgetcsv
+ */
+ function getCsvControl($delimiter = ',', $enclosure = '"')
+ {
+ return array($this->delimiter, $this->enclosure);
+ }
+
+ /**
* @param operation lock operation (LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB)
* @retval $wouldblock whether the operation would block
*/
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 2ac1cef67..7991e4c76 100755
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: php_spl.c,v 1.52.2.28 2006/03/23 19:55:16 helly Exp $ */
+/* $Id: php_spl.c,v 1.52.2.28.2.6 2006/08/07 09:49:53 tony2001 Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -36,6 +36,7 @@
#include "spl_observer.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
+#include "ext/standard/md5.h"
#ifdef COMPILE_DL_SPL
ZEND_GET_MODULE(spl)
@@ -50,9 +51,9 @@ zend_function_entry spl_functions_none[] = {
};
/* }}} */
-/* {{{ spl_init_globals
+/* {{{ PHP_GINIT_FUNCTION
*/
-static void spl_init_globals(zend_spl_globals *spl_globals)
+static PHP_GINIT_FUNCTION(spl)
{
spl_globals->autoload_extensions = NULL;
spl_globals->autoload_functions = NULL;
@@ -180,6 +181,8 @@ PHP_FUNCTION(class_implements)
SPL_ADD_CLASS(RecursiveFilterIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RecursiveIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RecursiveIteratorIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RecursiveRegexIterator, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(RegexIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(RuntimeException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SeekableIterator, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(SimpleXMLIterator, z_list, sub, allow, ce_flags); \
@@ -210,10 +213,25 @@ int spl_autoload(const char *class_name, const char * lc_name, int class_name_le
zend_file_handle file_handle;
zend_op_array *new_op_array;
zval *result = NULL;
+ zval err_mode;
+ int ret;
class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);
- if (zend_stream_open(class_file, &file_handle TSRMLS_CC) == SUCCESS) {
+ ZVAL_LONG(&err_mode, EG(error_reporting));
+ if (Z_LVAL(err_mode)) {
+ php_alter_ini_entry("error_reporting", sizeof("error_reporting"), "0", 1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
+ }
+
+ ret = zend_stream_open(class_file, &file_handle TSRMLS_CC);
+
+ if (!EG(error_reporting) && Z_LVAL(err_mode) != EG(error_reporting)) {
+ convert_to_string(&err_mode);
+ zend_alter_ini_entry("error_reporting", sizeof("error_reporting"), Z_STRVAL(err_mode), Z_STRLEN(err_mode), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
+ zendi_zval_dtor(err_mode);
+ }
+
+ if (ret == SUCCESS) {
if (!file_handle.opened_path) {
file_handle.opened_path = estrndup(class_file, class_file_len);
}
@@ -227,7 +245,7 @@ int spl_autoload(const char *class_name, const char * lc_name, int class_name_le
if (new_op_array) {
EG(return_value_ptr_ptr) = &result;
EG(active_op_array) = new_op_array;
-
+
zend_execute(new_op_array TSRMLS_CC);
destroy_op_array(new_op_array TSRMLS_CC);
@@ -257,15 +275,11 @@ PHP_FUNCTION(spl_autoload)
zend_op **original_opline_ptr = EG(opline_ptr);
zend_op_array *original_active_op_array = EG(active_op_array);
zend_function_state *original_function_state_ptr = EG(function_state_ptr);
- zval err_mode;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &class_name, &class_name_len, &file_exts, &file_exts_len) == FAILURE) {
RETURN_FALSE;
}
- ZVAL_LONG(&err_mode, EG(error_reporting));
- php_alter_ini_entry("error_reporting", sizeof("error_reporting"), "0", 1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
-
copy = pos1 = estrdup(ZEND_NUM_ARGS() > 1 ? file_exts : SPL_G(autoload_extensions));
lc_name = zend_str_tolower_dup(class_name, class_name_len);
while(pos1 && *pos1 && !EG(exception)) {
@@ -286,12 +300,6 @@ PHP_FUNCTION(spl_autoload)
efree(copy);
}
- if (!EG(error_reporting) && Z_LVAL(err_mode) != EG(error_reporting)) {
- convert_to_string(&err_mode);
- zend_alter_ini_entry("error_reporting", sizeof("error_reporting"), Z_STRVAL(err_mode), Z_STRLEN(err_mode), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
- zendi_zval_dtor(err_mode);
- }
-
EG(return_value_ptr_ptr) = original_return_value;
EG(opline_ptr) = original_opline_ptr;
EG(active_op_array) = original_active_op_array;
@@ -564,6 +572,32 @@ PHP_FUNCTION(spl_autoload_functions)
add_next_index_string(return_value, EG(autoload_func)->common.function_name, 1);
} /* }}} */
+/* {{{ proto string spl_object_hash(object obj)
+ Return hash id for given object */
+PHP_FUNCTION(spl_object_hash)
+{
+ zval *obj;
+ int len;
+ char *hash;
+ char md5str[33];
+ PHP_MD5_CTX context;
+ unsigned char digest[16];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+ return;
+ }
+
+ len = spprintf(&hash, 0, "%p:%d", Z_OBJ_HT_P(obj), Z_OBJ_HANDLE_P(obj));
+
+ md5str[0] = '\0';
+ PHP_MD5Init(&context);
+ PHP_MD5Update(&context, (unsigned char*)hash, len);
+ PHP_MD5Final(digest, &context);
+ make_digest(md5str, digest);
+ RETVAL_STRING(md5str, 1);
+ efree(hash);
+}
+
int spl_build_class_list_string(zval **entry, char **list TSRMLS_DC) /* {{{ */
{
char *res;
@@ -608,7 +642,14 @@ PHP_MINFO_FUNCTION(spl)
static
ZEND_BEGIN_ARG_INFO(arginfo_iterator, 0)
- ZEND_ARG_INFO(0, iterator)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_apply, 0, 0, 2)
+ ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0)
+ ZEND_ARG_INFO(0, function)
+ ZEND_ARG_ARRAY_INFO(0, args, 1)
ZEND_END_ARG_INFO();
/* {{{ spl_functions
@@ -623,9 +664,11 @@ zend_function_entry spl_functions[] = {
PHP_FE(spl_autoload_call, NULL)
PHP_FE(class_parents, NULL)
PHP_FE(class_implements, NULL)
+ PHP_FE(spl_object_hash, NULL)
#ifdef SPL_ITERATORS_H
PHP_FE(iterator_to_array, arginfo_iterator)
PHP_FE(iterator_count, arginfo_iterator)
+ PHP_FE(iterator_apply, arginfo_iterator_apply)
#endif /* SPL_ITERATORS_H */
{NULL, NULL, NULL}
};
@@ -635,8 +678,6 @@ zend_function_entry spl_functions[] = {
*/
PHP_MINIT_FUNCTION(spl)
{
- ZEND_INIT_MODULE_GLOBALS(spl, spl_init_globals, NULL);
-
PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU);
@@ -694,7 +735,11 @@ zend_module_entry spl_module_entry = {
PHP_RSHUTDOWN(spl),
PHP_MINFO(spl),
"0.2",
- STANDARD_MODULE_PROPERTIES
+ PHP_MODULE_GLOBALS(spl),
+ PHP_GINIT(spl),
+ NULL,
+ NULL,
+ STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
diff --git a/ext/spl/spl.php b/ext/spl/spl.php
index f704e044b..2987024f2 100755
--- a/ext/spl/spl.php
+++ b/ext/spl/spl.php
@@ -6,7 +6,7 @@
*
* SPL - Standard PHP Library
*
- * (c) Marcus Boerger, 2003 - 2005
+ * (c) Marcus Boerger, 2003 - 2006
*/
/** @mainpage SPL - Standard PHP Library
@@ -46,6 +46,8 @@
* - class EmptyIterator implements Iterator
* - class InfiniteIterator extends IteratorIterator
* - class AppendIterator implements OuterIterator
+ * - class RegexIterator extends FilterIterator
+ * - class RecursiveRegexIterator extends RegexIterator implements RecursiveIterator
*
* 2) Directories and Files
*
@@ -66,8 +68,8 @@
*
* SPL offers advanced Array overloading:
*
- * - class ArrayObject implements IteratorAggregate
- * - class ArrayIterator implements Iterator
+ * - class ArrayObject implements IteratorAggregate, ArrayAccess, Countable
+ * - class ArrayIterator implements Iterator, ArrayAccess, Countable, SeekableIterator
* - class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator
*
* As the above suggest an ArrayObject creates an ArrayIterator when it comes to
@@ -110,6 +112,7 @@
* c-code.
*
* 9) Some articles about SPL:
+ * - <a href="http://www.phpro.org/tutorials/Introduction-to-SPL.html">Introduction to Standard PHP Library (SPL)</a>
* - <a href="http://www.sitepoint.com/article/php5-standard-library/1">Introducing PHP 5's Standard Library</a>
* - <a href="http://www.ramikayyali.com/archives/2005/02/25/iterators">Iterators in PHP5</a>
* - <a href="http://www.phpriot.com/d/articles/php/oop/oop-with-spl-php-5-1/index.html">Advanced OOP with SPL in PHP 5</a>
@@ -128,7 +131,7 @@
* You can download this documentation as a chm file
* <a href="http://php.net/~helly/php/ext/spl/spl.chm">here</a>.
*
- * (c) Marcus Boerger, 2003 - 2005
+ * (c) Marcus Boerger, 2003 - 2006
*/
/** @defgroup ZendEngine Zend engine classes
@@ -157,7 +160,7 @@
* @param class_name name of class to load
* @param file_extensions file extensions (use defaults if NULL)
*/
-function spl_autoload(string $class_name, string $file_extensions = NULL);
+function spl_autoload(string $class_name, string $file_extensions = NULL) {/**/};
/** @ingroup SPL
* @brief Manual invocation of all registerd autoload functions
@@ -165,7 +168,7 @@ function spl_autoload(string $class_name, string $file_extensions = NULL);
*
* @param class_name name of class to load
*/
-function spl_autoload_call(string $class_name);
+function spl_autoload_call(string $class_name) {/**/};
/** @ingroup SPL
* @brief Register and return default file extensions for spl_autoload
@@ -176,7 +179,7 @@ function spl_autoload_call(string $class_name);
* @return comma separated list of file extensions to use in default autoload
* function.
*/
-function spl_autoload_extensions($file_extensions);
+function spl_autoload_extensions($file_extensions) {/**/};
/** @ingroup SPL
* @brief Return all registered autoload functionns
@@ -184,7 +187,7 @@ function spl_autoload_extensions($file_extensions);
*
* @return array of all registered autoload functions or false
*/
-function spl_autoload_functions();
+function spl_autoload_functions() {/**/};
/** @ingroup SPL
* @brief Register given function as autoload implementation
@@ -194,7 +197,7 @@ function spl_autoload_functions();
* function name to register as autoload function.
* @param throw whether to throw or issue an error on failure.
*/
-function spl_autoload_register(string $autoload_function = "spl_autoload", $throw = true);
+function spl_autoload_register(string $autoload_function = "spl_autoload", $throw = true) {/**/};
/** @ingroup SPL
* @brief Unregister given function as autoload implementation
@@ -203,7 +206,7 @@ function spl_autoload_register(string $autoload_function = "spl_autoload", $thro
* @param autoload_function name of function or array of object/class and
* function name to unregister as autoload function.
*/
-function spl_autoload_unregister(string $autoload_function = "spl_autoload");
+function spl_autoload_unregister(string $autoload_function = "spl_autoload") {/**/};
/** @ingroup SPL
* @brief Return an array of classes and interfaces in SPL
@@ -211,7 +214,7 @@ function spl_autoload_unregister(string $autoload_function = "spl_autoload");
* @return array containing the names of all clsses and interfaces defined in
* extension SPL
*/
-function spl_classes();
+function spl_classes() {/**/};
/** @ingroup SPL
* @brief Count the elements in an iterator
@@ -219,7 +222,7 @@ function spl_classes();
*
* @return number of elements in an iterator
*/
-function iterator_count(Traversable $it);
+function iterator_count(Traversable $it) {/**/};
/** @ingroup SPL
* @brief Copy iterator elements into an array
@@ -228,7 +231,7 @@ function iterator_count(Traversable $it);
* @param it iterator to copy
* @return array with elements copied from the iterator
*/
-function iterator_to_array(Traversable $it);
+function iterator_to_array(Traversable $it) {/**/};
/** @ingroup ZendEngine
* @brief Basic Exception class.
@@ -611,7 +614,7 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable
* @param $flags see setFlags().
* @param $iterator_class class used in getIterator()
*/
- function __construct($array, $flags = 0, $iterator_class = "ArrayIterator");
+ function __construct($array, $flags = 0, $iterator_class = "ArrayIterator") {/**/}
/** Set behavior flags.
*
@@ -620,72 +623,94 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable
* when accessed as list (var_dump, foreach, etc.)
* 1 set: array indices can be accessed as properties in read/write
*/
- function setFlags($flags);
+ function setFlags($flags) {/**/}
- /**
- * @ return current flags
+ /** @return current flags
*/
- function getFlags();
+ function getFlags() {/**/}
- /**
- * @param $array new array or object
+ /** Sort the entries by values.
+ */
+ function asort() {/**/}
+
+ /** Sort the entries by key.
*/
- function exchangeArray($array);
+ function ksort() {/**/}
+
+ /** Sort the entries by values using user defined function.
+ */
+ function uasort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by key using user defined function.
+ */
+ function uksort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by values using "natural order" algorithm.
+ */
+ function natsort() {/**/}
+
+ /** Sort the entries by values using case insensitive "natural order" algorithm.
+ */
+ function natcasesort() {/**/}
+
+ /** @param $array new array or object
+ */
+ function exchangeArray($array) {/**/}
/** @return the iterator which is an ArrayIterator object connected to
* this object.
*/
- function getIterator();
+ function getIterator() {/**/}
/** @param $index offset to inspect
* @return whetehr offset $index esists
*/
- function offsetExists($index);
+ function offsetExists($index) {/**/}
/** @param $index offset to return value for
* @return value at offset $index
*/
- function offsetGet($index);
+ function offsetGet($index) {/**/}
/** @param $index index to set
* @param $newval new value to store at offset $index
*/
- function offsetSet($index, $newval);
+ function offsetSet($index, $newval) {/**/}
/** @param $index offset to unset
*/
- function offsetUnset($index);
+ function offsetUnset($index) {/**/}
/** @param $value is appended as last element
* @warning this method cannot be called when the ArrayObject refers to
* an object.
*/
- function append($value);
+ function append($value) {/**/}
/** @return a \b copy of the array
* @note when the ArrayObject refers to an object then this method
* returns an array of the public properties.
*/
- function getArrayCopy();
+ function getArrayCopy() {/**/}
/** @return the number of elements in the array or the number of public
* properties in the object.
*/
- function count();
+ function count() {/**/}
/* @param $iterator_class new class used in getIterator()
*/
- function setIteratorClass($itertor_class);
+ function setIteratorClass($itertor_class) {/**/}
/* @return class used in getIterator()
*/
- function getIteratorClass();
+ function getIteratorClass() {/**/}
}
/** @ingroup SPL
* @brief An Array iterator
* @since PHP 5.0
- * @version 1.1
+ * @version 1.2
*
* This iterator allows to unset and modify values and keys while iterating
* over Arrays and Objects.
@@ -709,7 +734,7 @@ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable
* @param $array the array to use.
* @param $flags see setFlags().
*/
- function __construct($array, $flags = 0);
+ function __construct($array, $flags = 0) {/**/}
/** Set behavior flags.
*
@@ -718,53 +743,92 @@ class ArrayIterator implements SeekableIterator, ArrayAccess, Countable
* when accessed as list (var_dump, foreach, etc.)
* 1 set: array indices can be accessed as properties in read/write
*/
- function setFlags($flags);
+ function setFlags($flags) {/**/}
/**
- * @ return current flags
+ * @return current flags
*/
- function getFlags();
+ function getFlags() {/**/}
+ /** Sort the entries by values.
+ */
+ function asort() {/**/}
+
+ /** Sort the entries by key.
+ */
+ function ksort() {/**/}
+
+ /** Sort the entries by values using user defined function.
+ */
+ function uasort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by key using user defined function.
+ */
+ function uksort(mixed cmp_function) {/**/}
+
+ /** Sort the entries by values using "natural order" algorithm.
+ */
+ function natsort() {/**/}
+
+ /** Sort the entries by values using case insensitive "natural order" algorithm.
+ */
+ function natcasesort() {/**/}
+
/** @param $index offset to inspect
* @return whetehr offset $index esists
*/
- function offsetExists($index);
+ function offsetExists($index) {/**/}
/** @param $index offset to return value for
* @return value at offset $index
*/
- function offsetGet($index);
+ function offsetGet($index) {/**/}
/** @param $index index to set
* @param $newval new value to store at offset $index
*/
- function offsetSet($index, $newval);
+ function offsetSet($index, $newval) {/**/}
/** @param $index offset to unset
*/
- function offsetUnset($index);
+ function offsetUnset($index) {/**/}
/** @param $value is appended as last element
* @warning this method cannot be called when the ArrayIterator refers to
* an object.
*/
- function append($value);
+ function append($value) {/**/}
/** @return a \b copy of the array
* @note when the ArrayIterator refers to an object then this method
* returns an array of the public properties.
*/
- function getArrayCopy();
+ function getArrayCopy() {/**/}
/** @param $position offset to seek to
* @throw OutOfBoundsException if $position is invalid
*/
- function seek($position);
+ function seek($position) {/**/}
/** @return the number of elements in the array or the number of public
* properties in the object.
*/
- function count();
+ function count() {/**/}
+
+ /** @copydoc Iterator::rewind */
+ function rewind() {/**/}
+
+ /** @copydoc Iterator::valid */
+ function valid() {/**/}
+
+ /** @copydoc Iterator::current */
+ function current() {/**/}
+
+ /** @copydoc Iterator::key */
+ function key() {/**/}
+
+ /** @copydoc Iterator::next */
+ function next() {/**/}
}
/** @ingroup SPL
@@ -777,95 +841,95 @@ class SplFileInfo
*
* @param $file_name path or file name
*/
- function __construct($file_name);
+ function __construct($file_name) {/**/}
/** @return the path part only.
*/
- function getPath();
+ function getPath() {/**/}
/** @return the filename only.
*/
- function getFilename();
+ function getFilename() {/**/}
/** @return SplFileInfo created for the file
* @param class_name name of class to instantiate
* @see SplFileInfo::setInfoClass()
*/
- function getFileInfo(string class_name = NULL);
+ function getFileInfo(string class_name = NULL) {/**/}
/** @return The current entries path and file name.
*/
- function getPathname();
+ function getPathname() {/**/}
/** @return SplFileInfo created for the path
* @param class_name name of class to instantiate
* @see SplFileInfo::setInfoClass()
*/
- function getPathInfo(string class_name = NULL);
+ function getPathInfo(string class_name = NULL) {/**/}
/** @return The current entry's permissions.
*/
- function getPerms();
+ function getPerms() {/**/}
/** @return The current entry's inode.
*/
- function getInode();
+ function getInode() {/**/}
/** @return The current entry's size in bytes .
*/
- function getSize();
+ function getSize() {/**/}
/** @return The current entry's owner name.
*/
- function getOwner();
+ function getOwner() {/**/}
/** @return The current entry's group name.
*/
- function getGroup();
+ function getGroup() {/**/}
/** @return The current entry's last access time.
*/
- function getATime();
+ function getATime() {/**/}
/** @return The current entry's last modification time.
*/
- function getMTime();
+ function getMTime() {/**/}
/** @return The current entry's last change time.
*/
- function getCTime();
+ function getCTime() {/**/}
/** @return The current entry's size in bytes .
*/
- function getType();
+ function getType() {/**/}
/** @return Whether the current entry is writeable.
*/
- function isWritable();
+ function isWritable() {/**/}
/** @return Whether the current entry is readable.
*/
- function isReadable();
+ function isReadable() {/**/}
/** @return Whether the current entry is executable.
*/
- function isExecutable();
+ function isExecutable() {/**/}
/** @return Whether the current entry is .
*/
- function isFile();
+ function isFile() {/**/}
/** @return Whether the current entry is a directory.
*/
- function isDir();
+ function isDir() {/**/}
/** @return whether the current entry is a link.
*/
- function isLink();
+ function isLink() {/**/}
/** @return getPathname()
*/
- function __toString();
+ function __toString() {/**/}
/** Open the current file as a SplFileObject instance
*
@@ -880,17 +944,17 @@ class SplFileInfo
* @see SplFileInfo::setFileClass()
* @see file()
*/
- function openFile($mode = 'r', $use_include_path = false, $context = NULL);
+ function openFile($mode = 'r', $use_include_path = false, $context = NULL) {/**/}
/** @param class_name name of class used with openFile(). Must be derived
* from SPLFileObject.
*/
- function setFileClass(string class_name = "SplFileObject");
+ function setFileClass(string class_name = "SplFileObject") {/**/}
/** @param class_name name of class used with getFileInfo(), getPathInfo().
- * Must be derived from SplFileInfo.
+ * Must be derived from SplFileInfo.
*/
- function setInfoClass(string class_name = "SplFileInfo");
+ function setInfoClass(string class_name = "SplFileInfo") {/**/}
}
/** @ingroup SPL
@@ -904,27 +968,36 @@ class DirectoryIterator extends SplFileInfo implements Iterator
*
* @param $path directory to iterate.
*/
- function __construct($path);
+ function __construct($path) {/**/}
+ /** @copydoc Iterator::rewind */
+ function rewind() {/**/}
+
+ /** @copydoc Iterator::valid */
+ function valid() {/**/}
+
/** @return index of entry
*/
- function key();
+ function key() {/**/}
/** @return $this
*/
- function current();
+ function current() {/**/}
+
+ /** @copydoc Iterator::next */
+ function next() {/**/}
/** @return Whether the current entry is either '.' or '..'.
*/
- function isDot();
+ function isDot() {/**/}
/** @return whether the current entry is a link.
*/
- function isLink();
+ function isLink() {/**/}
/** @return getFilename()
*/
- function __toString();
+ function __toString() {/**/}
}
/** @ingroup SPL
@@ -946,31 +1019,31 @@ class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveI
* - KEY_AS_FILENAME
* - NEW_CURRENT_AND_KEY
*/
- function __construct($path, $flags = 0);
+ function __construct($path, $flags = 0) {/**/}
/** @return getPathname() or getFilename() depending on flags
*/
- function key();
+ function key() {/**/}
/** @return getFilename() or getFileInfo() depending on flags
*/
- function current();
+ function current() {/**/}
/** @return whether the current is a directory (not '.' or '..').
*/
- function hasChildren();
+ function hasChildren() {/**/}
/** @return a RecursiveDirectoryIterator for the current entry.
*/
- function getChildren();
+ function getChildren() {/**/}
/** @return sub path only (without main path)
*/
- function getSubPath();
+ function getSubPath() {/**/}
/** @return the current sub path
*/
- function getSubPathname();
+ function getSubPathname() {/**/}
}
/** @ingroup SPL
@@ -984,15 +1057,34 @@ class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveI
* has subelements, hasChildren() returns true. This will trigger a call to
* getChildren() which returns the iterator for that sub element.
*/
-class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator
+class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator, Countable
{
/** @return whether the current node has sub nodes.
*/
- function hasChildren();
+ function hasChildren() {/**/}
/** @return a SimpleXMLIterator for the current node.
*/
- function getChildren();
+ function getChildren() {/**/}
+
+ /** @return number of elements/attributes seen with foreach()
+ */
+ function count() {/**/}
+
+ /** @copydoc Iterator::rewind */
+ function rewind() {/**/}
+
+ /** @copydoc Iterator::valid */
+ function valid() {/**/}
+
+ /** @copydoc Iterator::current */
+ function current() {/**/}
+
+ /** @copydoc Iterator::key */
+ function key() {/**/}
+
+ /** @copydoc Iterator::next */
+ function next() {/**/}
}
/** @ingroup SPL
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 34804315a..d025f3ffd 100755
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_array.c,v 1.71.2.17 2006/04/07 22:53:23 tony2001 Exp $ */
+/* $Id: spl_array.c,v 1.71.2.17.2.4 2006/10/20 02:11:19 pollita Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -46,10 +46,15 @@ PHPAPI zend_class_entry *spl_ce_Countable;
#define SPL_ARRAY_STD_PROP_LIST 0x00000001
#define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
+#define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
+#define SPL_ARRAY_OVERLOADED_VALID 0x00020000
+#define SPL_ARRAY_OVERLOADED_KEY 0x00040000
+#define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
+#define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
#define SPL_ARRAY_IS_REF 0x01000000
#define SPL_ARRAY_IS_SELF 0x02000000
#define SPL_ARRAY_USE_OTHER 0x04000000
-#define SPL_ARRAY_INT_MASK 0xFF000000
+#define SPL_ARRAY_INT_MASK 0xFFFF0000
#define SPL_ARRAY_CLONE_MASK 0x03000007
typedef struct _spl_array_object {
@@ -114,7 +119,7 @@ static void spl_array_object_free_storage(void *object TSRMLS_DC)
}
/* }}} */
-zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC);
+zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
/* {{{ spl_array_object_new */
static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
@@ -166,6 +171,7 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s
while (parent) {
if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
retval.handlers = &spl_handler_ArrayIterator;
+ class_type->get_iterator = spl_array_get_iterator;
break;
} else if (parent == spl_ce_ArrayObject) {
retval.handlers = &spl_handler_ArrayObject;
@@ -195,7 +201,25 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s
intern->fptr_offset_del = NULL;
}
}
- intern->ce_get_iterator = spl_ce_ArrayIterator;
+ /* Cache iterator functions if ArrayIterator or derived. Check current's */
+ /* cache since only current is always required */
+ if (retval.handlers == &spl_handler_ArrayIterator) {
+ if (!class_type->iterator_funcs.zf_current) {
+ zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
+ zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
+ zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
+ zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
+ zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
+ }
+ if (inherited) {
+ if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
+ if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
+ if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
+ if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
+ if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
+ }
+ }
+
zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
return retval;
}
@@ -275,6 +299,8 @@ static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object,
static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
{
+ zval **ret;
+
if (check_inherited) {
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
if (intern->fptr_offset_get) {
@@ -291,7 +317,30 @@ static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval
return EG(uninitialized_zval_ptr);
}
}
- return *spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
+ ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
+
+ /* When in a write context,
+ * ZE has to be fooled into thinking this is in a reference set
+ * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
+ if ((type == BP_VAR_W || type == BP_VAR_RW) && !(*ret)->is_ref) {
+ if ((*ret)->refcount > 1) {
+ zval *newval;
+
+ /* Separate */
+ MAKE_STD_ZVAL(newval);
+ *newval = **ret;
+ zval_copy_ctor(newval);
+ newval->refcount = 1;
+
+ /* Replace */
+ (*ret)->refcount--;
+ *ret = newval;
+ }
+
+ (*ret)->is_ref = 1;
+ }
+
+ return *ret;
} /* }}} */
static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
@@ -461,8 +510,8 @@ SPL_METHOD(Array, offsetExists)
RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 1 TSRMLS_CC));
} /* }}} */
-/* {{{ proto bool ArrayObject::offsetGet(mixed $index)
- proto bool ArrayIterator::offsetGet(mixed $index)
+/* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
+ proto mixed ArrayIterator::offsetGet(mixed $index)
Returns the value at the specified $index. */
SPL_METHOD(Array, offsetGet)
{
@@ -498,7 +547,7 @@ void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{
}
if (Z_TYPE_P(intern->array) == IS_OBJECT) {
- php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
return;
}
@@ -659,7 +708,7 @@ static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
/* define an overloaded iterator structure */
typedef struct {
- zend_object_iterator intern;
+ zend_user_iterator intern;
spl_array_object *object;
} spl_array_it;
@@ -667,7 +716,8 @@ static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
{
spl_array_it *iterator = (spl_array_it *)iter;
- zval_ptr_dtor((zval**)&iterator->intern.data);
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ zval_ptr_dtor((zval**)&iterator->intern.it.data);
efree(iterator);
}
@@ -679,16 +729,20 @@ static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
spl_array_object *object = iterator->object;
HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
- if (!aht) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
- return FAILURE;
- }
-
- if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
- return FAILURE;
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
+ return zend_user_it_valid(iter TSRMLS_CC);
} else {
- return zend_hash_has_more_elements_ex(aht, &object->pos);
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
+ return FAILURE;
+ }
+
+ if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
+ return FAILURE;
+ } else {
+ return zend_hash_has_more_elements_ex(aht, &object->pos);
+ }
}
}
/* }}} */
@@ -698,9 +752,13 @@ static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***da
spl_array_it *iterator = (spl_array_it *)iter;
spl_array_object *object = iterator->object;
HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
-
- if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
- *data = NULL;
+
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
+ zend_user_it_get_current_data(iter, data TSRMLS_CC);
+ } else {
+ if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
+ *data = NULL;
+ }
}
}
/* }}} */
@@ -711,17 +769,21 @@ static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_k
spl_array_object *object = iterator->object;
HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
- if (!aht) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
- return HASH_KEY_NON_EXISTANT;
- }
-
- if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
- return HASH_KEY_NON_EXISTANT;
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
+ return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
+ } else {
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
+ return HASH_KEY_NON_EXISTANT;
+ }
+
+ if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
+ return HASH_KEY_NON_EXISTANT;
+ }
+
+ return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
}
-
- return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
}
/* }}} */
@@ -731,15 +793,20 @@ static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {
spl_array_object *object = iterator->object;
HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
- if (!aht) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
- return;
- }
-
- if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
+ zend_user_it_move_forward(iter TSRMLS_CC);
} else {
- spl_array_next(object TSRMLS_CC);
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ if (!aht) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
+ return;
+ }
+
+ if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
+ } else {
+ spl_array_next(object TSRMLS_CC);
+ }
}
}
/* }}} */
@@ -763,7 +830,12 @@ static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
spl_array_it *iterator = (spl_array_it *)iter;
spl_array_object *object = iterator->object;
- spl_array_rewind(object TSRMLS_CC);
+ if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
+ zend_user_it_rewind(iter TSRMLS_CC);
+ } else {
+ zend_user_it_invalidate_current(iter TSRMLS_CC);
+ spl_array_rewind(object TSRMLS_CC);
+ }
}
/* }}} */
@@ -777,14 +849,22 @@ zend_object_iterator_funcs spl_array_it_funcs = {
spl_array_it_rewind
};
-zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) /* {{{ */
+zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
{
- spl_array_it *iterator = emalloc(sizeof(spl_array_it));
+ spl_array_it *iterator;
spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+ if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+
+ iterator = emalloc(sizeof(spl_array_it));
+
object->refcount++;
- iterator->intern.data = (void*)object;
- iterator->intern.funcs = &spl_array_it_funcs;
+ iterator->intern.it.data = (void*)object;
+ iterator->intern.it.funcs = &spl_array_it_funcs;
+ iterator->intern.ce = ce;
+ iterator->intern.value = NULL;
iterator->object = array_object;
return (zend_object_iterator*)iterator;
@@ -1077,6 +1157,63 @@ SPL_METHOD(Array, count)
RETURN_LONG(count);
} /* }}} */
+static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg)
+{
+ spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+ zval tmp, *arg;
+
+ INIT_PZVAL(&tmp);
+ Z_TYPE(tmp) = IS_ARRAY;
+ Z_ARRVAL(tmp) = aht;
+
+ if (use_arg) {
+ if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
+ zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
+ return;
+ }
+ zend_call_method(NULL, NULL, NULL, fname, fname_len, &return_value, 2, &tmp, arg TSRMLS_CC);
+ } else {
+ zend_call_method(NULL, NULL, NULL, fname, fname_len, &return_value, 1, &tmp, NULL TSRMLS_CC);
+ }
+}
+
+#define SPL_ARRAY_METHOD(cname, fname, use_arg) \
+SPL_METHOD(cname, fname) \
+{ \
+ spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
+}
+
+/* {{{ proto int ArrayObject::asort()
+ proto int ArrayIterator::asort()
+ Sort the entries by values. */
+SPL_ARRAY_METHOD(Array, asort, 0)
+
+/* {{{ proto int ArrayObject::ksort()
+ proto int ArrayIterator::ksort()
+ Sort the entries by key. */
+SPL_ARRAY_METHOD(Array, ksort, 0)
+
+/* {{{ proto int ArrayObject::uasort(callback cmp_function)
+ proto int ArrayIterator::uasort(callback cmp_function)
+ Sort the entries by values user defined function. */
+SPL_ARRAY_METHOD(Array, uasort, 1)
+
+/* {{{ proto int ArrayObject::uksort(callback cmp_function)
+ proto int ArrayIterator::uksort(callback cmp_function)
+ Sort the entries by key using user defined function. */
+SPL_ARRAY_METHOD(Array, uksort, 1)
+
+/* {{{ proto int ArrayObject::natsort()
+ proto int ArrayIterator::natsort()
+ Sort the entries by values using "natural order" algorithm. */
+SPL_ARRAY_METHOD(Array, natsort, 0)
+
+/* {{{ proto int ArrayObject::natcasesort()
+ proto int ArrayIterator::natcasesort()
+ Sort the entries by key using case insensitive "natural order" algorithm. */
+SPL_ARRAY_METHOD(Array, natcasesort, 0)
+
/* {{{ proto mixed|NULL ArrayIterator::current()
Return current array entry */
SPL_METHOD(Array, current)
@@ -1107,7 +1244,11 @@ SPL_METHOD(Array, current)
Return current array key */
SPL_METHOD(Array, key)
{
- zval *object = getThis();
+ spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
+}
+
+void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
+{
spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
char *string_key;
uint string_length;
@@ -1273,17 +1414,28 @@ ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
ZEND_ARG_INFO(0, iteratorClass)
ZEND_END_ARG_INFO()
+static
+ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
+ ZEND_ARG_INFO(0, cmp_function )
+ZEND_END_ARG_INFO();
+
static zend_function_entry spl_funcs_ArrayObject[] = {
- SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
- SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, asort, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, ksort, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natsort, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natcasesort, NULL, ZEND_ACC_PUBLIC)
/* ArrayObject specific */
SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC)
SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
@@ -1293,23 +1445,29 @@ static zend_function_entry spl_funcs_ArrayObject[] = {
};
static zend_function_entry spl_funcs_ArrayIterator[] = {
- SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
- SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
- SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, asort, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, ksort, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natsort, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, natcasesort, NULL, ZEND_ACC_PUBLIC)
/* ArrayIterator specific */
- SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, valid, NULL, ZEND_ACC_PUBLIC)
- SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, valid, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
@@ -1355,6 +1513,7 @@ PHP_MINIT_FUNCTION(spl_array)
REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
+ spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
REGISTER_SPL_INTERFACE(Countable);
diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h
index 554964420..2e8519557 100755
--- a/ext/spl/spl_array.h
+++ b/ext/spl/spl_array.h
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_array.h,v 1.13.2.2 2006/01/01 12:50:13 sniper Exp $ */
+/* $Id: spl_array.h,v 1.13.2.2.2.1 2006/05/10 00:03:38 helly Exp $ */
#ifndef SPL_ARRAY_H
#define SPL_ARRAY_H
@@ -32,6 +32,7 @@ extern PHPAPI zend_class_entry *spl_ce_Countable;
PHP_MINIT_FUNCTION(spl_array);
extern void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC);
+extern void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC);
#endif /* SPL_ARRAY_H */
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index 1f949eaf3..a5b9a11cf 100755
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_directory.c,v 1.45.2.27 2006/04/06 19:01:56 tony2001 Exp $ */
+/* $Id: spl_directory.c,v 1.45.2.27.2.8 2006/09/29 13:11:28 bjori Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -205,9 +205,9 @@ static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_inclu
intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
intern->u.file.stream = php_stream_open_wrapper_ex(intern->file_name, intern->u.file.open_mode, (use_include_path ? USE_PATH : 0) | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, intern->u.file.context);
- if (intern->u.file.stream == NULL) {
+ if (!intern->file_name_len || !intern->u.file.stream) {
if (!EG(exception)) {
- zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot open file %s", intern->file_name);
+ zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot open file '%s'", intern->file_name_len ? intern->file_name : "");
}
intern->file_name = NULL; /* until here it is not a copy */
intern->u.file.open_mode = NULL;
@@ -218,12 +218,23 @@ static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_inclu
zend_list_addref(Z_RESVAL_P(intern->u.file.zcontext));
}
+ if (intern->file_name[intern->file_name_len-1] == '/'
+#if defined(PHP_WIN32) || defined(NETWARE)
+ ||intern->file_name[intern->file_name_len-1] == '\\'
+#endif
+ ) {
+ intern->file_name_len--;
+ }
+
intern->file_name = estrndup(intern->file_name, intern->file_name_len);
intern->u.file.open_mode = estrndup(intern->u.file.open_mode, intern->u.file.open_mode_len);
/* avoid reference counting in debug mode, thus do it manually */
ZVAL_RESOURCE(&intern->u.file.zresource, php_stream_get_resource_id(intern->u.file.stream));
intern->u.file.zresource.refcount = 1;
+
+ intern->u.file.delimiter = ',';
+ intern->u.file.enclosure = '"';
zend_hash_find(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline"), (void **) &intern->u.file.func_getCurr);
@@ -254,8 +265,8 @@ static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC)
switch (source->type) {
case SPL_FS_INFO:
- source->path_len = source->path_len;
- source->path = estrndup(source->path, source->path_len);
+ intern->path_len = source->path_len;
+ intern->path = estrndup(source->path, source->path_len);
intern->file_name_len = source->file_name_len;
intern->file_name = estrndup(source->file_name, intern->file_name_len);
break;
@@ -990,10 +1001,16 @@ zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
};
/* {{{ spl_ce_dir_get_iterator */
-zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
+zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
{
- spl_filesystem_dir_it *iterator = emalloc(sizeof(spl_filesystem_dir_it));
- spl_filesystem_object *dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
+ spl_filesystem_dir_it *iterator;
+ spl_filesystem_object *dir_object;
+
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ iterator = emalloc(sizeof(spl_filesystem_dir_it));
+ dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
object->refcount += 2;;
iterator->intern.data = (void*)object;
@@ -1195,10 +1212,16 @@ zend_object_iterator_funcs spl_filesystem_tree_it_funcs = {
};
/* {{{ spl_ce_dir_get_iterator */
-zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC)
+zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
{
- spl_filesystem_dir_it *iterator = emalloc(sizeof(spl_filesystem_dir_it));
- spl_filesystem_object *dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
+ spl_filesystem_dir_it *iterator;
+ spl_filesystem_object *dir_object;
+
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ iterator = emalloc(sizeof(spl_filesystem_dir_it));
+ dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC);
object->refcount++;
iterator->intern.data = (void*)object;
@@ -1211,14 +1234,10 @@ zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zva
/* }}} */
/* {{{ spl_filesystem_object_cast */
-static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC)
+static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(readobj TSRMLS_CC);
- if (should_free) {
- zval_dtor(readobj);
- }
-
if (type == IS_STRING) {
switch (intern->type) {
case SPL_FS_INFO:
@@ -1374,19 +1393,104 @@ static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent TS
return SUCCESS;
} /* }}} */
-static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
+static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function *func_ptr, int pass_num_args, zval *return_value, zval *arg2 TSRMLS_DC) /* {{{ */
+{
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcic;
+ zval z_fname;
+ zval * zresource_ptr = &intern->u.file.zresource, *retval;
+ int result;
+ int num_args = pass_num_args + (arg2 ? 2 : 1);
+
+ zval ***params = (zval***)safe_emalloc(num_args, sizeof(zval**), 0);
+
+ params[0] = &zresource_ptr;
+
+ if (arg2) {
+ params[1] = &arg2;
+ }
+
+ zend_get_parameters_array_ex(pass_num_args, params+(arg2 ? 2 : 1));
+
+ ZVAL_STRING(&z_fname, func_ptr->common.function_name, 0);
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.object_pp = NULL;
+ fci.function_name = &z_fname;
+ fci.retval_ptr_ptr = &retval;
+ fci.param_count = num_args;
+ fci.params = params;
+ fci.no_separation = 1;
+ fci.symbol_table = NULL;
+
+ fcic.initialized = 1;
+ fcic.function_handler = func_ptr;
+ fcic.calling_scope = NULL;
+ fcic.object_pp = NULL;
+
+ result = zend_call_function(&fci, &fcic TSRMLS_CC);
+
+ ZVAL_ZVAL(return_value, retval, 1, 1);
+
+ efree(params);
+ return result;
+} /* }}} */
+
+#define FileFunctionCall(func_name, pass_num_args, arg2) \
+{ \
+ zend_function *func_ptr; \
+ zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \
+ spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2 TSRMLS_CC); \
+}
+
+static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ int ret = SUCCESS;
+
+ do {
+ ret = spl_filesystem_file_read(intern, 1 TSRMLS_CC);
+ } while (ret == SUCCESS && !intern->u.file.current_line_len && (intern->flags & SPL_FILE_OBJECT_SKIP_EMPTY));
+
+ if (ret == SUCCESS) {
+ size_t buf_len = intern->u.file.current_line_len;
+ char *buf = estrndup(intern->u.file.current_line, buf_len);
+
+ if (intern->u.file.current_zval) {
+ zval_ptr_dtor(&intern->u.file.current_zval);
+ }
+ ALLOC_INIT_ZVAL(intern->u.file.current_zval);
+
+ php_fgetcsv(intern->u.file.stream, delimiter, enclosure, buf_len, buf, intern->u.file.current_zval TSRMLS_CC);
+ if (return_value) {
+ if (Z_TYPE_P(return_value) != IS_NULL) {
+ zval_dtor(return_value);
+ ZVAL_NULL(return_value);
+ }
+ ZVAL_ZVAL(return_value, intern->u.file.current_zval, 1, 0);
+ }
+ }
+ return ret;
+}
+/* }}} */
+
+static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
{
zval *retval = NULL;
- /* if overloaded call the function, otherwise do it directly */
- if (intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
+ /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
+ if (intern->flags & SPL_FILE_OBJECT_READ_CSV || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
if (php_stream_eof(intern->u.file.stream)) {
if (!silent) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot read from file %s", intern->file_name);
}
return FAILURE;
}
- zend_call_method_with_0_params(&getThis(), Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
+ if (intern->flags & SPL_FILE_OBJECT_READ_CSV) {
+ return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, NULL TSRMLS_CC);
+ } else {
+ zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
+ }
if (retval) {
if (intern->u.file.current_line || intern->u.file.current_zval) {
intern->u.file.current_line_num++;
@@ -1409,7 +1513,47 @@ static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object
}
} /* }}} */
-static void spl_filesystem_file_rewind(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+static int spl_filesystem_file_is_empty_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
+{
+ if (intern->u.file.current_line) {
+ return intern->u.file.current_line_len == 0;
+ } else if (intern->u.file.current_zval) {
+ switch(Z_TYPE_P(intern->u.file.current_zval)) {
+ case IS_STRING:
+ return Z_STRLEN_P(intern->u.file.current_zval) == 0;
+ case IS_ARRAY:
+ if ((intern->flags & SPL_FILE_OBJECT_READ_CSV)
+ && zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 1) {
+ zval ** first = Z_ARRVAL_P(intern->u.file.current_zval)->pListHead->pData;
+
+ return Z_TYPE_PP(first) == IS_STRING && Z_STRLEN_PP(first) == 0;
+ }
+ return zend_hash_num_elements(Z_ARRVAL_P(intern->u.file.current_zval)) == 0;
+ case IS_NULL:
+ return 1;
+ default:
+ return 0;
+ }
+ } else {
+ return 1;
+ }
+}
+/* }}} */
+
+static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */
+{
+ int ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
+
+ while ((intern->flags & SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && spl_filesystem_file_is_empty_line(intern TSRMLS_CC)) {
+ spl_filesystem_file_free_line(intern TSRMLS_CC);
+ ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent TSRMLS_CC);
+ }
+
+ return ret;
+}
+/* }}} */
+
+static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern TSRMLS_DC) /* {{{ */
{
if (-1 == php_stream_rewind(intern->u.file.stream)) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot rewind file %s", intern->file_name);
@@ -1417,6 +1561,9 @@ static void spl_filesystem_file_rewind(spl_filesystem_object *intern TSRMLS_DC)
spl_filesystem_file_free_line(intern TSRMLS_CC);
intern->u.file.current_line_num = 0;
}
+ if (intern->flags & SPL_FILE_OBJECT_READ_AHEAD) {
+ spl_filesystem_file_read_line(this_ptr, intern, 1 TSRMLS_CC);
+ }
} /* }}} */
/* {{{ proto void SplFileObject::__construct(string filename [, string mode = 'r' [, bool use_include_path [, resource context]]]])
@@ -1458,7 +1605,7 @@ SPL_METHOD(SplFileObject, __construct)
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
} /* }}} */
-/* {{{ proto void SplFileObject::__construct([int max_memory])
+/* {{{ proto void SplTempFileObject::__construct([int max_memory])
Construct a new temp file object */
SPL_METHOD(SplTempFileObject, __construct)
{
@@ -1501,7 +1648,7 @@ SPL_METHOD(SplFileObject, rewind)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- spl_filesystem_file_rewind(intern TSRMLS_CC);
+ spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
} /* }}} */
/* {{{ proto string SplFileObject::getFilename()
@@ -1528,7 +1675,11 @@ SPL_METHOD(SplFileObject, valid)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
+ if (intern->flags & SPL_FILE_OBJECT_READ_AHEAD) {
+ RETURN_BOOL(intern->u.file.current_line || intern->u.file.current_zval);
+ } else {
+ RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
+ }
} /* }}} */
/* {{{ proto string SplFileObject::fgets()
@@ -1549,10 +1700,10 @@ SPL_METHOD(SplFileObject, current)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- if (!intern->u.file.current_line) {
+ if (!intern->u.file.current_line && !intern->u.file.current_zval) {
spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
}
- if (intern->u.file.current_line) {
+ if (intern->u.file.current_line && (!(intern->flags & SPL_FILE_OBJECT_READ_CSV) || !intern->u.file.current_zval)) {
RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len, 1);
} else if (intern->u.file.current_zval) {
RETURN_ZVAL(intern->u.file.current_zval, 1, 0);
@@ -1580,6 +1731,9 @@ SPL_METHOD(SplFileObject, next)
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
spl_filesystem_file_free_line(intern TSRMLS_CC);
+ if (intern->flags & SPL_FILE_OBJECT_READ_AHEAD) {
+ spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
+ }
intern->u.file.current_line_num++;
} /* }}} */
@@ -1644,62 +1798,12 @@ SPL_METHOD(SplFileObject, getChildren)
/* return NULL */
} /* }}} */
-static int spl_filesystem_file_call(INTERNAL_FUNCTION_PARAMETERS, spl_filesystem_object *intern, zend_function *func_ptr, zval *arg2) /* {{{ */
-{
- zend_fcall_info fci;
- zend_fcall_info_cache fcic;
- zval z_fname;
- zval * zresource_ptr = &intern->u.file.zresource, *retval;
- int result;
-
- zval ***params = (zval***)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval**), (arg2 ? 2 : 1) * sizeof(zval**));
-
- params[0] = &zresource_ptr;
-
- if (arg2) {
- params[1] = &arg2;
- }
-
- zend_get_parameters_array_ex(ZEND_NUM_ARGS(), params+(arg2 ? 2 : 1));
-
- ZVAL_STRING(&z_fname, func_ptr->common.function_name, 0);
-
- fci.size = sizeof(fci);
- fci.function_table = EG(function_table);
- fci.object_pp = NULL;
- fci.function_name = &z_fname;
- fci.retval_ptr_ptr = &retval;
- fci.param_count = ZEND_NUM_ARGS() + (arg2 ? 2 : 1);
- fci.params = params;
- fci.no_separation = 1;
- fci.symbol_table = NULL;
-
- fcic.initialized = 1;
- fcic.function_handler = func_ptr;
- fcic.calling_scope = NULL;
- fcic.object_pp = NULL;
-
- result = zend_call_function(&fci, &fcic TSRMLS_CC);
-
- ZVAL_ZVAL(return_value, retval, 1, 1);
-
- efree(params);
- return result;
-} /* }}} */
-
-#define FileFunctionCall(func_name, arg2) \
-{ \
- zend_function *func_ptr; \
- zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \
- spl_filesystem_file_call(INTERNAL_FUNCTION_PARAM_PASSTHRU, intern, func_ptr, arg2); \
-}
-
/* {{{ FileFunction */
#define FileFunction(func_name) \
SPL_METHOD(SplFileObject, func_name) \
{ \
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \
- FileFunctionCall(func_name, NULL); \
+ FileFunctionCall(func_name, ZEND_NUM_ARGS(), NULL); \
}
/* }}} */
@@ -1708,16 +1812,86 @@ SPL_METHOD(SplFileObject, func_name) \
SPL_METHOD(SplFileObject, fgetcsv)
{
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- zval *arg2 = NULL;
- MAKE_STD_ZVAL(arg2);
- ZVAL_LONG(arg2, intern->u.file.max_line_len);
+ char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
+ char *delim, *enclo;
+ int d_len, e_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &delim, &d_len, &enclo, &e_len) == SUCCESS) {
+ switch(ZEND_NUM_ARGS())
+ {
+ case 2:
+ if (e_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
+ RETURN_FALSE;
+ }
+ enclosure = enclo[0];
+ /* no break */
+ case 1:
+ if (d_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
+ RETURN_FALSE;
+ }
+ delimiter = delim[0];
+ /* no break */
+ case 0:
+ break;
+ }
+ spl_filesystem_file_read_csv(intern, delimiter, enclosure, return_value TSRMLS_CC);
+ }
+}
+/* }}} */
- spl_filesystem_file_free_line(intern TSRMLS_CC);
- intern->u.file.current_line_num++;
+/* {{{ proto void SplFileObject::setCsvControl([string delimiter = ',' [, string enclosure = '"']])
+ Set the delimiter and enclosure character used in fgetcsv */
+SPL_METHOD(SplFileObject, setCsvControl)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char delimiter = ',', enclosure = '"';
+ char *delim, *enclo;
+ int d_len, e_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &delim, &d_len, &enclo, &e_len) == SUCCESS) {
+ switch(ZEND_NUM_ARGS())
+ {
+ case 2:
+ if (e_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "enclosure must be a character");
+ RETURN_FALSE;
+ }
+ enclosure = enclo[0];
+ /* no break */
+ case 1:
+ if (d_len != 1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "delimiter must be a character");
+ RETURN_FALSE;
+ }
+ delimiter = delim[0];
+ /* no break */
+ case 0:
+ break;
+ }
+ intern->u.file.delimiter = delimiter;
+ intern->u.file.enclosure = enclosure;
+ }
+}
+/* }}} */
- FileFunctionCall(fgetcsv, arg2);
+/* {{{ proto array SplFileObject::getCsvControl()
+ Get the delimiter and enclosure character used in fgetcsv */
+SPL_METHOD(SplFileObject, getCsvControl)
+{
+ spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char delimiter[2], enclosure[2];
- zval_ptr_dtor(&arg2);
+ array_init(return_value);
+
+ delimiter[0] = intern->u.file.delimiter;
+ delimiter[1] = '\0';
+ enclosure[0] = intern->u.file.enclosure;
+ enclosure[1] = '\0';
+
+ add_next_index_string(return_value, delimiter, 1);
+ add_next_index_string(return_value, enclosure, 1);
}
/* }}} */
@@ -1802,7 +1976,7 @@ SPL_METHOD(SplFileObject, fgetss)
spl_filesystem_file_free_line(intern TSRMLS_CC);
intern->u.file.current_line_num++;
- FileFunctionCall(fgetss, arg2);
+ FileFunctionCall(fgetss, ZEND_NUM_ARGS(), arg2);
zval_ptr_dtor(&arg2);
} /* }}} */
@@ -1825,7 +1999,7 @@ SPL_METHOD(SplFileObject, fscanf)
spl_filesystem_file_free_line(intern TSRMLS_CC);
intern->u.file.current_line_num++;
- FileFunctionCall(fscanf, NULL);
+ FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL);
}
/* }}} */
@@ -1900,7 +2074,7 @@ SPL_METHOD(SplFileObject, seek)
RETURN_FALSE;
}
- spl_filesystem_file_rewind(intern TSRMLS_CC);
+ spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC);
while(intern->u.file.current_line_num < line_pos) {
spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC);
@@ -1978,6 +2152,8 @@ static zend_function_entry spl_SplFileObject_functions[] = {
SPL_ME(SplFileObject, valid, NULL, ZEND_ACC_PUBLIC)
SPL_ME(SplFileObject, fgets, NULL, ZEND_ACC_PUBLIC)
SPL_ME(SplFileObject, fgetcsv, arginfo_file_object_fgetcsv, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, setCsvControl, arginfo_file_object_fgetcsv, ZEND_ACC_PUBLIC)
+ SPL_ME(SplFileObject, getCsvControl, NULL, ZEND_ACC_PUBLIC)
SPL_ME(SplFileObject, flock, arginfo_file_object_flock, ZEND_ACC_PUBLIC)
SPL_ME(SplFileObject, fflush, NULL, ZEND_ACC_PUBLIC)
SPL_ME(SplFileObject, ftell, NULL, ZEND_ACC_PUBLIC)
@@ -2006,7 +2182,7 @@ static zend_function_entry spl_SplFileObject_functions[] = {
};
static
-ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 1)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 0)
ZEND_ARG_INFO(0, max_memory)
ZEND_END_ARG_INFO()
@@ -2048,10 +2224,12 @@ PHP_MINIT_FUNCTION(spl_directory)
REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator);
REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator);
- REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new, spl_SplTempFileObject_functions);
-
REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE);
-
+ REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_AHEAD", SPL_FILE_OBJECT_READ_AHEAD);
+ REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY", SPL_FILE_OBJECT_SKIP_EMPTY);
+ REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV", SPL_FILE_OBJECT_READ_CSV);
+
+ REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new, spl_SplTempFileObject_functions);
return SUCCESS;
}
/* }}} */
diff --git a/ext/spl/spl_directory.h b/ext/spl/spl_directory.h
index 513fa7eb8..9a29c9b82 100755
--- a/ext/spl/spl_directory.h
+++ b/ext/spl/spl_directory.h
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_directory.h,v 1.12.2.5 2006/03/08 21:54:48 helly Exp $ */
+/* $Id: spl_directory.h,v 1.12.2.5.2.2 2006/07/15 15:08:41 helly Exp $ */
#ifndef SPL_DIRECTORY_H
#define SPL_DIRECTORY_H
@@ -82,11 +82,16 @@ struct _spl_filesystem_object {
long current_line_num;
zval zresource;
zend_function *func_getCurr;
+ char delimiter;
+ char enclosure;
} file;
} u;
};
#define SPL_FILE_OBJECT_DROP_NEW_LINE 0x00000001 /* drop new lines */
+#define SPL_FILE_OBJECT_READ_AHEAD 0x00000002 /* read on rewind/next */
+#define SPL_FILE_OBJECT_SKIP_EMPTY 0x00000006 /* skip empty lines */
+#define SPL_FILE_OBJECT_READ_CSV 0x00000008 /* read via fgetcsv */
#define SPL_FILE_DIR_CURRENT_AS_FILEINFO 0x00000010 /* make RecursiveDirectoryTree::current() return SplFileInfo */
#define SPL_FILE_DIR_CURRENT_AS_PATHNAME 0x00000020 /* make RecursiveDirectoryTree::current() return getPathname() */
diff --git a/ext/spl/spl_exceptions.c b/ext/spl/spl_exceptions.c
index 8a7b70b30..0688fbc34 100755
--- a/ext/spl/spl_exceptions.c
+++ b/ext/spl/spl_exceptions.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_exceptions.c,v 1.6.2.1 2006/01/01 12:50:13 sniper Exp $ */
+/* $Id: spl_exceptions.c,v 1.6.2.1.2.1 2006/05/10 00:03:38 helly Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -47,7 +47,7 @@ PHPAPI zend_class_entry *spl_ce_RangeException;
PHPAPI zend_class_entry *spl_ce_UnderflowException;
PHPAPI zend_class_entry *spl_ce_UnexpectedValueException;
-#define spl_ce_Exception zend_exception_get_default()
+#define spl_ce_Exception zend_exception_get_default(TSRMLS_C)
/* {{{ PHP_MINIT_FUNCTION(spl_exceptions) */
PHP_MINIT_FUNCTION(spl_exceptions)
diff --git a/ext/spl/spl_functions.c b/ext/spl/spl_functions.c
index 52f92f692..b0936ea09 100755
--- a/ext/spl/spl_functions.c
+++ b/ext/spl/spl_functions.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_functions.c,v 1.28.2.3 2006/03/09 11:43:45 sebastian Exp $ */
+/* $Id: spl_functions.c,v 1.28.2.3.2.2 2006/07/20 22:54:21 helly Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -36,16 +36,13 @@ void spl_destroy_class(zend_class_entry ** ppce)
/* }}} */
/* {{{ spl_register_interface */
-void spl_register_interface(zend_class_entry ** ppce, char * class_name, zend_function_entry *functions TSRMLS_DC)
+void spl_register_interface(zend_class_entry ** ppce, char * class_name, zend_function_entry * functions TSRMLS_DC)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, class_name, functions);
ce.name_length = strlen(class_name);
- *ppce = zend_register_internal_class(&ce TSRMLS_CC);
-
- /* entries changed by initialize */
- (*ppce)->ce_flags = ZEND_ACC_INTERFACE;
+ *ppce = zend_register_internal_interface(&ce TSRMLS_CC);
}
/* }}} */
@@ -98,14 +95,9 @@ void spl_register_functions(zend_class_entry * class_entry, zend_function_entry
/* }}} */
/* {{{ spl_register_property */
-void spl_register_property( zend_class_entry * class_entry, char *prop_name, zval *prop_val, int prop_flags TSRMLS_DC)
+void spl_register_property( zend_class_entry * class_entry, char *prop_name, int prop_name_len, int prop_flags TSRMLS_DC)
{
- if (!prop_val) {
- INIT_PZVAL(prop_val);
- prop_val->type = IS_NULL;
- }
-
- zend_declare_property(class_entry, prop_name, strlen(prop_name), prop_val, prop_flags TSRMLS_CC);
+ zend_declare_property_null(class_entry, prop_name, prop_name_len, prop_flags TSRMLS_CC);
}
/* }}} */
diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h
index d175ef64f..557215719 100755
--- a/ext/spl/spl_functions.h
+++ b/ext/spl/spl_functions.h
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_functions.h,v 1.19.2.3 2006/01/01 12:50:13 sniper Exp $ */
+/* $Id: spl_functions.h,v 1.19.2.3.2.1 2006/07/20 22:54:21 helly Exp $ */
#ifndef PHP_FUNCTIONS_H
#define PHP_FUNCTIONS_H
@@ -49,8 +49,8 @@ typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type T
#define REGISTER_SPL_FUNCTIONS(class_name, function_list) \
spl_register_functions(spl_ce_ ## class_name, function_list TSRMLS_CC);
-#define REGISTER_SPL_PROPERTY(class_name, prop_name) \
- spl_register_property(spl_ce_ ## class_name, prop_name, prop_val, prop_flags TSRMLS_CC);
+#define REGISTER_SPL_PROPERTY(class_name, prop_name, prop_flags) \
+ spl_register_property(spl_ce_ ## class_name, prop_name, sizeof(prop_name)-1, prop_flags TSRMLS_CC);
#define REGISTER_SPL_CLASS_CONST_LONG(class_name, const_name, value) \
zend_declare_class_constant_long(spl_ce_ ## class_name, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
@@ -64,7 +64,7 @@ void spl_register_interface(zend_class_entry ** ppce, char * class_name, zend_fu
void spl_register_parent_ce(zend_class_entry * class_entry, zend_class_entry * parent_class TSRMLS_DC);
void spl_register_functions(zend_class_entry * class_entry, zend_function_entry * function_list TSRMLS_DC);
-void spl_register_property( zend_class_entry * class_entry, char *prop_name, zval *prop_val, int prop_flags TSRMLS_DC);
+void spl_register_property( zend_class_entry * class_entry, char *prop_name, int prop_name_len, int prop_flags TSRMLS_DC);
/* sub: whether to allow subclasses/interfaces
allow = 0: allow all classes and interfaces
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index 0ba01180b..58853c6f5 100755
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_iterators.c,v 1.73.2.33 2006/07/17 21:13:32 helly Exp $ */
+/* $Id: spl_iterators.c,v 1.73.2.30.2.17 2006/07/21 21:26:11 helly Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -55,6 +55,8 @@ PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
PHPAPI zend_class_entry *spl_ce_EmptyIterator;
PHPAPI zend_class_entry *spl_ce_AppendIterator;
+PHPAPI zend_class_entry *spl_ce_RegexIterator;
+PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
zend_function_entry spl_funcs_RecursiveIterator[] = {
SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, NULL)
@@ -191,6 +193,13 @@ next_step:
switch (object->iterators[object->level].state) {
case RS_NEXT:
iterator->funcs->move_forward(iterator TSRMLS_CC);
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
case RS_START:
if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) {
break;
@@ -205,6 +214,14 @@ next_step:
} else {
zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
}
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ object->iterators[object->level].state = RS_NEXT;
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
if (retval) {
has_children = zend_is_true(retval);
zval_ptr_dtor(&retval);
@@ -233,6 +250,13 @@ next_step:
zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL);
}
object->iterators[object->level].state = RS_NEXT;
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
return /* self */;
case RS_SELF:
if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) {
@@ -280,7 +304,7 @@ next_step:
object->iterators[object->level].state = RS_NEXT;
}
object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator) * (++object->level+1));
- sub_iter = ce->get_iterator(ce, child TSRMLS_CC);
+ sub_iter = ce->get_iterator(ce, child, 0 TSRMLS_CC);
object->iterators[object->level].iterator = sub_iter;
object->iterators[object->level].zobject = child;
object->iterators[object->level].ce = ce;
@@ -290,6 +314,13 @@ next_step:
}
if (object->beginChildren) {
zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL);
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
}
goto next_step;
}
@@ -297,6 +328,13 @@ next_step:
if (object->level > 0) {
if (object->endChildren) {
zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
+ if (EG(exception)) {
+ if (!(object->flags & RIT_CATCH_GET_CHILD)) {
+ return;
+ } else {
+ zend_clear_exception(TSRMLS_C);
+ }
+ }
}
iterator->funcs->dtor(iterator TSRMLS_CC);
zval_ptr_dtor(&object->iterators[object->level].zobject);
@@ -315,7 +353,7 @@ static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zt
sub_iter = object->iterators[object->level].iterator;
sub_iter->funcs->dtor(sub_iter TSRMLS_CC);
zval_ptr_dtor(&object->iterators[object->level--].zobject);
- if (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator) {
+ if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) {
zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL);
}
}
@@ -325,7 +363,7 @@ static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zt
if (sub_iter->funcs->rewind) {
sub_iter->funcs->rewind(sub_iter TSRMLS_CC);
}
- if (object->beginIteration && !object->in_iteration) {
+ if (!EG(exception) && object->beginIteration && !object->in_iteration) {
zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL);
}
object->in_iteration = 1;
@@ -342,10 +380,16 @@ static void spl_recursive_it_rewind(zend_object_iterator *iter TSRMLS_DC)
spl_recursive_it_rewind_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC);
}
-static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject TSRMLS_DC)
+static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce, zval *zobject, int by_ref TSRMLS_DC)
{
- spl_recursive_it_iterator *iterator = emalloc(sizeof(spl_recursive_it_iterator));
- spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
+ spl_recursive_it_iterator *iterator;
+ spl_recursive_it_object *object;
+
+ if (by_ref) {
+ zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
+ }
+ iterator = emalloc(sizeof(spl_recursive_it_iterator));
+ object = (spl_recursive_it_object*)zend_object_store_get_object(zobject TSRMLS_CC);
zobject->refcount++;
iterator->intern.data = (void*)object;
@@ -432,7 +476,7 @@ SPL_METHOD(RecursiveIteratorIterator, __construct)
intern->nextElement = NULL;
}
ce_iterator = Z_OBJCE_P(iterator); /* respect inheritance, don't use spl_ce_RecursiveIterator */
- intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator TSRMLS_CC);
+ intern->iterators[0].iterator = ce_iterator->get_iterator(ce_iterator, iterator, 0 TSRMLS_CC);
if (inc_refcount) {
iterator->refcount++;
}
@@ -565,7 +609,11 @@ SPL_METHOD(RecursiveIteratorIterator, callHasChildren)
RETURN_FALSE;
} else {
zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval);
- RETURN_ZVAL(retval, 0, 1);
+ if (retval) {
+ RETURN_ZVAL(retval, 0, 1);
+ } else {
+ RETURN_FALSE;
+ }
}
} /* }}} */
@@ -827,6 +875,18 @@ int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC);
+static inline int spl_cit_check_flags(int flags)
+{
+ int cnt = 0;
+
+ cnt += (flags & CIT_CALL_TOSTRING) ? 1 : 0;
+ cnt += (flags & CIT_TOSTRING_USE_KEY) ? 1 : 0;
+ cnt += (flags & CIT_TOSTRING_USE_CURRENT) ? 1 : 0;
+ cnt += (flags & CIT_TOSTRING_USE_INNER) ? 1 : 0;
+
+ return cnt <= 1 ? SUCCESS : FAILURE;
+}
+
static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, dual_it_type dit_type)
{
zval *zobject, *retval;
@@ -871,13 +931,14 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
return NULL;
}
- if (((flags & CIT_CALL_TOSTRING) && (flags & (CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT)))
- || ((flags & (CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT)) == (CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT))) {
+ if (spl_cit_check_flags(flags) != SUCCESS) {
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
- zend_throw_exception(spl_ce_InvalidArgumentException, "Flags must contain only one of CATCH_GET_CHILD, CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT", 0 TSRMLS_CC);
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_CURRENT", 0 TSRMLS_CC);
return NULL;
}
intern->u.caching.flags |= flags & CIT_PUBLIC;
+ MAKE_STD_ZVAL(intern->u.caching.zcache);
+ array_init(intern->u.caching.zcache);
break;
}
case DIT_IteratorIterator: {
@@ -904,6 +965,13 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
}
if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) {
zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval);
+ if (EG(exception)) {
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+ return NULL;
+ }
if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) {
zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%s::getIterator() must return an object that implememnts Traversable", ce->name);
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
@@ -919,9 +987,35 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
case DIT_AppendIterator:
spl_instantiate(spl_ce_ArrayIterator, &intern->u.append.zarrayit, 1 TSRMLS_CC);
zend_call_method_with_0_params(&intern->u.append.zarrayit, spl_ce_ArrayIterator, &spl_ce_ArrayIterator->constructor, "__construct", NULL);
- intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit TSRMLS_CC);
+ intern->u.append.iterator = spl_ce_ArrayIterator->get_iterator(spl_ce_ArrayIterator, intern->u.append.zarrayit, 0 TSRMLS_CC);
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
return intern;
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ case DIT_RegexIterator:
+ case DIT_RecursiveRegexIterator: {
+ char *regex;
+ int regex_len;
+ long mode = REGIT_MODE_MATCH;
+
+ intern->u.regex.use_flags = ZEND_NUM_ARGS() >= 5;
+ intern->u.regex.flags = 0;
+ intern->u.regex.preg_flags = 0;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|lll", &zobject, ce_inner, &regex, &regex_len, &mode, &intern->u.regex.flags, &intern->u.regex.preg_flags) == FAILURE) {
+ php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+ return NULL;
+ }
+ if (mode < 0 || mode >= REGIT_MODE_MAX) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
+ php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
+ return NULL;
+ }
+ intern->u.regex.mode = mode;
+ intern->u.regex.regex = estrndup(regex, regex_len);
+ intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC);
+ intern->u.regex.pce->refcount++;
+ break;;
+ }
+#endif
default:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) {
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
@@ -930,7 +1024,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
break;
}
- php_set_error_handling(EH_THROW, zend_exception_get_default() TSRMLS_CC);
+ php_set_error_handling(EH_THROW, zend_exception_get_default(TSRMLS_C) TSRMLS_CC);
if (inc_refcount) {
zobject->refcount++;
@@ -938,7 +1032,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
intern->inner.zobject = zobject;
intern->inner.ce = dit_type == DIT_IteratorIterator ? ce : Z_OBJCE_P(zobject);
intern->inner.object = zend_object_store_get_object(zobject TSRMLS_CC);
- intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject TSRMLS_CC);
+ intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, zobject, 0 TSRMLS_CC);
php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
return intern;
@@ -1146,7 +1240,9 @@ static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern T
}
zval_ptr_dtor(&retval);
}
-
+ if (EG(exception)) {
+ return;
+ }
intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC);
}
spl_dual_it_free(intern TSRMLS_CC);
@@ -1201,7 +1297,11 @@ SPL_METHOD(RecursiveFilterIterator, hasChildren)
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
- RETURN_ZVAL(retval, 0, 1);
+ if (retval) {
+ RETURN_ZVAL(retval, 0, 1);
+ } else {
+ RETURN_FALSE;
+ }
} /* }}} */
/* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren()
@@ -1214,8 +1314,12 @@ SPL_METHOD(RecursiveFilterIterator, getChildren)
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
- spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
- zval_ptr_dtor(&retval);
+ if (!EG(exception) && retval) {
+ spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
} /* }}} */
/* {{{ proto void ParentIterator::__construct(RecursiveIterator it)
@@ -1235,7 +1339,11 @@ SPL_METHOD(ParentIterator, hasChildren)
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
- RETURN_ZVAL(retval, 0, 1);
+ if (retval) {
+ RETURN_ZVAL(retval, 0, 1);
+ } else {
+ RETURN_FALSE;
+ }
} /* }}} */
/* {{{ proto ParentIterator ParentIterator::getChildren()
@@ -1248,10 +1356,218 @@ SPL_METHOD(ParentIterator, getChildren)
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
- spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
- zval_ptr_dtor(&retval);
+ if (!EG(exception) && retval) {
+ spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC);
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+} /* }}} */
+
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+/* {{{ proto void RegexIterator::__construct(Iterator it, string regex [, int mode [, int flags [, int preg_flags]]])
+ Create an RegexIterator from another iterator and a regular expression */
+SPL_METHOD(RegexIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RegexIterator, zend_ce_iterator, DIT_RegexIterator);
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::accept()
+ Match (string)current() against regular expression */
+SPL_METHOD(RegexIterator, accept)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *subject, tmp[32], *result;
+ int subject_len, use_copy, count, result_len;
+ zval subject_copy, zcount, *replacement;
+
+ if (intern->u.regex.flags & REGIT_USE_KEY) {
+ if (intern->current.key_type == HASH_KEY_IS_LONG) {
+ subject_len = snprintf(tmp, sizeof(tmp), "%ld", intern->current.int_key);
+ subject = &tmp[0];
+ use_copy = 0;
+ } else {
+ subject_len = intern->current.str_key_len - 1;
+ subject = estrndup(intern->current.str_key, subject_len);
+ use_copy = 1;
+ }
+ } else {
+ zend_make_printable_zval(intern->current.data, &subject_copy, &use_copy);
+ if (use_copy) {
+ subject = Z_STRVAL(subject_copy);
+ subject_len = Z_STRLEN(subject_copy);
+ } else {
+ subject = Z_STRVAL_P(intern->current.data);
+ subject_len = Z_STRLEN_P(intern->current.data);
+ }
+ }
+
+ switch (intern->u.regex.mode)
+ {
+ case REGIT_MODE_MAX: /* won't happen but makes compiler happy */
+ case REGIT_MODE_MATCH:
+ count = pcre_exec(intern->u.regex.pce->re, intern->u.regex.pce->extra, subject, subject_len, 0, 0, NULL, 0);
+ RETVAL_BOOL(count >= 0);
+ break;
+
+ case REGIT_MODE_ALL_MATCHES:
+ case REGIT_MODE_GET_MATCH:
+ if (!use_copy) {
+ subject = estrndup(subject, subject_len);
+ use_copy = 1;
+ }
+ zval_ptr_dtor(&intern->current.data);
+ ALLOC_INIT_ZVAL(intern->current.data);
+ php_pcre_match_impl(intern->u.regex.pce, subject, subject_len, &zcount,
+ intern->current.data, intern->u.regex.mode == REGIT_MODE_ALL_MATCHES, intern->u.regex.use_flags, intern->u.regex.preg_flags, 0 TSRMLS_CC);
+ count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
+ RETVAL_BOOL(count > 0);
+ break;
+
+ case REGIT_MODE_SPLIT:
+ if (!use_copy) {
+ subject = estrndup(subject, subject_len);
+ use_copy = 1;
+ }
+ zval_ptr_dtor(&intern->current.data);
+ ALLOC_INIT_ZVAL(intern->current.data);
+ php_pcre_split_impl(intern->u.regex.pce, subject, subject_len, intern->current.data, -1, intern->u.regex.preg_flags TSRMLS_CC);
+ count = zend_hash_num_elements(Z_ARRVAL_P(intern->current.data));
+ RETVAL_BOOL(count > 1);
+ break;
+
+ case REGIT_MODE_REPLACE:
+ replacement = zend_read_property(intern->std.ce, getThis(), "replacement", sizeof("replacement")-1, 1 TSRMLS_CC);
+ result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, 0, NULL TSRMLS_CC);
+
+ if (intern->u.regex.flags & REGIT_USE_KEY) {
+ if (intern->current.key_type != HASH_KEY_IS_LONG) {
+ efree(intern->current.str_key);
+ }
+ intern->current.key_type = HASH_KEY_IS_STRING;
+ intern->current.str_key = result;
+ intern->current.str_key_len = result_len + 1;
+ } else {
+ zval_ptr_dtor(&intern->current.data);
+ MAKE_STD_ZVAL(intern->current.data);
+ ZVAL_STRINGL(intern->current.data, result, result_len, 0);
+ }
+ }
+
+ if (use_copy) {
+ efree(subject);
+ }
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::getMode()
+ Returns current operation mode */
+SPL_METHOD(RegexIterator, getMode)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(intern->u.regex.mode);
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::setMode(int new_mode)
+ Set new operation mode */
+SPL_METHOD(RegexIterator, setMode)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long mode;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) {
+ return;
+ }
+
+ if (mode < 0 || mode >= REGIT_MODE_MAX) {
+ zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Illegal mode %ld", mode);
+ return;// NULL
+ }
+
+ intern->u.regex.mode = mode;
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::getFlags()
+ Returns current operation flags */
+SPL_METHOD(RegexIterator, getFlags)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(intern->u.regex.flags);
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::setFlags(int new_flags)
+ Set operation flags */
+SPL_METHOD(RegexIterator, setFlags)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long flags;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
+ return;
+ }
+
+ intern->u.regex.flags = flags;
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::getFlags()
+ Returns current PREG flags (if in use or NULL) */
+SPL_METHOD(RegexIterator, getPregFlags)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (intern->u.regex.use_flags) {
+ RETURN_LONG(intern->u.regex.preg_flags);
+ } else {
+ return;
+ }
+} /* }}} */
+
+/* {{{ proto bool RegexIterator::setFlags(int new_flags)
+ Set PREG flags */
+SPL_METHOD(RegexIterator, setPregFlags)
+{
+ spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ long preg_flags;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) {
+ return;
+ }
+
+ intern->u.regex.preg_flags = preg_flags;
+ intern->u.regex.use_flags = 1;
+} /* }}} */
+
+/* {{{ proto void RecursiveRegexIterator::__construct(RecursiveIterator it, string regex [, int mode [, int flags [, int preg_flags]]])
+ Create an RecursiveRegexIterator from another recursive iterator and a regular expression */
+SPL_METHOD(RecursiveRegexIterator, __construct)
+{
+ spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator);
+} /* }}} */
+
+/* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren()
+ Return the inner iterator's children contained in a RecursiveRegexIterator */
+SPL_METHOD(RecursiveRegexIterator, getChildren)
+{
+ spl_dual_it_object *intern;
+ zval *retval, *regex;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval);
+ if (!EG(exception)) {
+ MAKE_STD_ZVAL(regex);
+ ZVAL_STRING(regex, intern->u.regex.regex, 1);
+ spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC);
+ zval_ptr_dtor(&regex);
+ }
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
} /* }}} */
+#endif
+
/* {{{ spl_dual_it_free_storage */
static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
{
@@ -1269,9 +1585,29 @@ static void spl_dual_it_free_storage(void *_object TSRMLS_DC)
if (object->dit_type == DIT_AppendIterator) {
object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC);
- zval_ptr_dtor(&object->u.append.zarrayit);
+ if (object->u.append.zarrayit) {
+ zval_ptr_dtor(&object->u.append.zarrayit);
+ }
+ }
+
+ if (object->dit_type == DIT_CachingIterator || object->dit_type == DIT_RecursiveCachingIterator) {
+ if (object->u.caching.zcache) {
+ zval_ptr_dtor(&object->u.caching.zcache);
+ object->u.caching.zcache = NULL;
+ }
}
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ if (object->dit_type == DIT_RegexIterator || object->dit_type == DIT_RecursiveRegexIterator) {
+ if (object->u.regex.pce) {
+ object->u.regex.pce->refcount--;
+ }
+ if (object->u.regex.regex) {
+ efree(object->u.regex.regex);
+ }
+ }
+#endif
+
zend_object_std_dtor(&object->std TSRMLS_CC);
efree(object);
@@ -1337,6 +1673,60 @@ static zend_function_entry spl_funcs_ParentIterator[] = {
{NULL, NULL, NULL}
};
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it___construct, 0, 0, 2)
+ ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
+ ZEND_ARG_INFO(0, regex)
+ ZEND_ARG_INFO(0, mode)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, preg_flags)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1)
+ ZEND_ARG_INFO(0, mode)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_preg_flags, 0, 0, 1)
+ ZEND_ARG_INFO(0, preg_flags)
+ZEND_END_ARG_INFO();
+
+static zend_function_entry spl_funcs_RegexIterator[] = {
+ SPL_ME(RegexIterator, __construct, arginfo_regex_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, accept, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getMode, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, setMode, arginfo_regex_it_set_mode, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getFlags, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, setFlags, arginfo_regex_it_set_flags, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, getPregFlags, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(RegexIterator, setPregFlags, arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rec_regex_it___construct, 0, 0, 2)
+ ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0)
+ ZEND_ARG_INFO(0, regex)
+ ZEND_ARG_INFO(0, mode)
+ ZEND_ARG_INFO(0, flags)
+ ZEND_ARG_INFO(0, preg_flags)
+ZEND_END_ARG_INFO();
+
+static zend_function_entry spl_funcs_RecursiveRegexIterator[] = {
+ SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(ParentIterator, hasChildren, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(RecursiveRegexIterator, getChildren, NULL, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+#endif
+
static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC)
{
/* FAILURE / SUCCESS */
@@ -1366,9 +1756,11 @@ static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS
spl_dual_it_free(intern TSRMLS_CC);
zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos);
zval_ptr_dtor(&zpos);
- intern->current.pos = pos;
- if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
- spl_dual_it_fetch(intern, 0 TSRMLS_CC);
+ if (!EG(exception)) {
+ intern->current.pos = pos;
+ if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) {
+ spl_dual_it_fetch(intern, 0 TSRMLS_CC);
+ }
}
} else {
/* emulate the forward seek, by next() calls */
@@ -1503,66 +1895,79 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
{
if (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) {
intern->u.caching.flags |= CIT_VALID;
+ /* Full cache ? */
+ if (intern->u.caching.flags & CIT_FULL_CACHE) {
+ zval *zcacheval;
+
+ MAKE_STD_ZVAL(zcacheval);
+ ZVAL_ZVAL(zcacheval, intern->current.data, 1, 0);
+ if (intern->current.key_type == HASH_KEY_IS_LONG) {
+ add_index_zval(intern->u.caching.zcache, intern->current.int_key, zcacheval);
+ } else {
+ zend_symtable_update(HASH_OF(intern->u.caching.zcache), intern->current.str_key, intern->current.str_key_len, &zcacheval, sizeof(void*), NULL);
+ }
+ }
+ /* Recursion ? */
if (intern->dit_type == DIT_RecursiveCachingIterator) {
zval *retval, *zchildren, zflags;
zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval);
- if (zend_is_true(retval)) {
- zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
- if (EG(exception) && intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
+ if (EG(exception)) {
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
zend_clear_exception(TSRMLS_C);
- if (zchildren) {
+ } else {
+ return;
+ }
+ } else {
+ if (zend_is_true(retval)) {
+ zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren);
+ if (EG(exception)) {
+ if (zchildren) {
+ zval_ptr_dtor(&zchildren);
+ }
+ if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
+ zend_clear_exception(TSRMLS_C);
+ } else {
+ zval_ptr_dtor(&retval);
+ return;
+ }
+ } else {
+ INIT_PZVAL(&zflags);
+ ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
+ spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
zval_ptr_dtor(&zchildren);
}
- } else {
- INIT_PZVAL(&zflags);
- ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC);
- spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC);
- zval_ptr_dtor(&zchildren);
}
- }
- zval_ptr_dtor(&retval);
- }
- if (intern->u.caching.flags & CIT_CALL_TOSTRING) {
- if (Z_TYPE_P(intern->current.data) == IS_OBJECT) {
- zval expr_copy;
- if (intern->current.data->value.obj.handlers->cast_object &&
- intern->current.data->value.obj.handlers->cast_object(intern->current.data, &expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS)
- {
- ALLOC_ZVAL(intern->u.caching.zstr);
- *intern->u.caching.zstr = expr_copy;
- INIT_PZVAL(intern->u.caching.zstr);
- zval_copy_ctor(intern->u.caching.zstr);
- zval_dtor(&expr_copy);
- } else {
- zend_class_entry *ce_data = spl_get_class_entry(intern->current.data TSRMLS_CC);
- if (ce_data && zend_hash_exists(&ce_data->function_table, "__tostring", sizeof("__tostring"))) {
- zend_call_method_with_0_params(&intern->current.data, ce_data, NULL, "__tostring", &intern->u.caching.zstr);
+ zval_ptr_dtor(&retval);
+ if (EG(exception)) {
+ if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) {
+ zend_clear_exception(TSRMLS_C);
} else {
- ALLOC_ZVAL(intern->u.caching.zstr);
- *intern->u.caching.zstr = *intern->current.data;
- zval_copy_ctor(intern->u.caching.zstr);
- INIT_PZVAL(intern->u.caching.zstr);
- convert_to_string(intern->u.caching.zstr);
+ return;
}
}
+ }
+ }
+ if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) {
+ int use_copy;
+ zval expr_copy;
+ ALLOC_ZVAL(intern->u.caching.zstr);
+ if (intern->u.caching.flags & CIT_TOSTRING_USE_INNER) {
+ *intern->u.caching.zstr = *intern->inner.zobject;
} else {
- /* This version requires zend_make_printable_zval() being able to
- * call __toString().
- */
- int use_copy;
- zval expr_copy;
- ALLOC_ZVAL(intern->u.caching.zstr);
*intern->u.caching.zstr = *intern->current.data;
- zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
- if (use_copy) {
- *intern->u.caching.zstr = expr_copy;
- INIT_PZVAL(intern->u.caching.zstr);
- zval_copy_ctor(intern->u.caching.zstr);
- zval_dtor(&expr_copy);
- } else {
- INIT_PZVAL(intern->u.caching.zstr);
- zval_copy_ctor(intern->u.caching.zstr);
- }
+ }
+ zend_make_printable_zval(intern->u.caching.zstr, &expr_copy, &use_copy);
+ if (use_copy) {
+ *intern->u.caching.zstr = expr_copy;
+ INIT_PZVAL(intern->u.caching.zstr);
+ zval_copy_ctor(intern->u.caching.zstr);
+ zval_dtor(&expr_copy);
+ } else {
+ INIT_PZVAL(intern->u.caching.zstr);
+ zval_copy_ctor(intern->u.caching.zstr);
}
}
spl_dual_it_next(intern, 0 TSRMLS_CC);
@@ -1574,6 +1979,7 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC)
static inline void spl_caching_it_rewind(spl_dual_it_object *intern TSRMLS_DC)
{
spl_dual_it_rewind(intern TSRMLS_CC);
+ zend_hash_clean(HASH_OF(intern->u.caching.zcache));
spl_caching_it_next(intern TSRMLS_CC);
}
@@ -1636,7 +2042,7 @@ SPL_METHOD(CachingIterator, __toString)
intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
- if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT))) {
+ if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) {
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not fetch string value (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
}
if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) {
@@ -1648,8 +2054,10 @@ SPL_METHOD(CachingIterator, __toString)
return;
}
} else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) {
- RETVAL_ZVAL(intern->current.data, 1, 0);
-
+ *return_value = *intern->current.data;
+ zval_copy_ctor(return_value);
+ convert_to_string(return_value);
+ INIT_PZVAL(return_value);
return;
}
if (intern->u.caching.zstr) {
@@ -1659,12 +2067,186 @@ SPL_METHOD(CachingIterator, __toString)
}
} /* }}} */
+/* {{{ proto void CachingIterator::offsetSet(mixed index, mixed newval)
+ Set given index in cache */
+SPL_METHOD(CachingIterator, offsetSet)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+ zval *value;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) {
+ return;
+ }
+
+ value->refcount++;
+ zend_symtable_update(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, &value, sizeof(value), NULL);
+}
+/* }}} */
+
+/* {{{ proto string CachingIterator::offsetGet(mixed index)
+ Return the internal cache if used */
+SPL_METHOD(CachingIterator, offsetGet)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+ zval **value;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
+ return;
+ }
+
+ if (zend_symtable_find(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1, (void**)&value) == FAILURE) {
+ zend_error(E_NOTICE, "Undefined index: %s", arKey);
+ return;
+ }
+
+ RETURN_ZVAL(*value, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto void CachingIterator::offsetUnset(mixed index)
+ Unset given index in cache */
+SPL_METHOD(CachingIterator, offsetUnset)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
+ return;
+ }
+
+ zend_symtable_del(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1);
+}
+/* }}} */
+
+/* {{{ proto bool CachingIterator::offsetExists(mixed index)
+ Return whether the requested index exists */
+SPL_METHOD(CachingIterator, offsetExists)
+{
+ spl_dual_it_object *intern;
+ char *arKey;
+ uint nKeyLength;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arKey, &nKeyLength) == FAILURE) {
+ return;
+ }
+
+ RETURN_BOOL(zend_symtable_exists(HASH_OF(intern->u.caching.zcache), arKey, nKeyLength+1));
+}
+/* }}} */
+
+/* {{{ proto bool CachingIterator::getCache()
+ Return the cache */
+SPL_METHOD(CachingIterator, getCache)
+{
+ spl_dual_it_object *intern;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name);
+ return;
+ }
+
+ RETURN_ZVAL(intern->u.caching.zcache, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto int CachingIterator::getFlags()
+ Return the internal flags */
+SPL_METHOD(CachingIterator, getFlags)
+{
+ spl_dual_it_object *intern;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ RETURN_LONG(intern->u.caching.flags);
+}
+/* }}} */
+
+/* {{{ proto void CachingIterator::setFlags()
+ Set the internal flags */
+SPL_METHOD(CachingIterator, setFlags)
+{
+ spl_dual_it_object *intern;
+ long flags;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) {
+ return;
+ }
+
+ if (spl_cit_check_flags(flags) != SUCCESS) {
+ zend_throw_exception(spl_ce_InvalidArgumentException , "Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER", 0 TSRMLS_CC);
+ return;
+ }
+ if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0 TSRMLS_CC);
+ return;
+ }
+ if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
+ zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0 TSRMLS_CC);
+ return;
+ }
+ if ((flags && CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
+ /* clear on (re)enable */
+ zend_hash_clean(HASH_OF(intern->u.caching.zcache));
+ }
+ intern->u.caching.flags = (intern->u.caching.flags & ~CIT_PUBLIC) | (flags & CIT_PUBLIC);
+}
+/* }}} */
+
static
ZEND_BEGIN_ARG_INFO(arginfo_caching_it___construct, 0)
ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
+static
+ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it_offsetGet, 0, 0, 1)
+ ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it_offsetSet, 0, 0, 2)
+ ZEND_ARG_INFO(0, index)
+ ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO();
+
static zend_function_entry spl_funcs_CachingIterator[] = {
SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC)
SPL_ME(CachingIterator, rewind, NULL, ZEND_ACC_PUBLIC)
@@ -1675,6 +2257,13 @@ static zend_function_entry spl_funcs_CachingIterator[] = {
SPL_ME(CachingIterator, hasNext, NULL, ZEND_ACC_PUBLIC)
SPL_ME(CachingIterator, __toString, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, getFlags, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, setFlags, arginfo_caching_it_setFlags, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetGet, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC)
+ SPL_ME(CachingIterator, getCache, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
@@ -1927,7 +2516,7 @@ int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/
intern->inner.zobject = *it;
intern->inner.ce = Z_OBJCE_PP(it);
intern->inner.object = zend_object_store_get_object(*it TSRMLS_CC);
- intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it TSRMLS_CC);
+ intern->inner.iterator = intern->inner.ce->get_iterator(intern->inner.ce, *it, 0 TSRMLS_CC);
spl_dual_it_rewind(intern TSRMLS_CC);
return SUCCESS;
} else {
@@ -1972,7 +2561,7 @@ SPL_METHOD(AppendIterator, append)
APPENDIT_CHECK_CTOR(intern);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
+ if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &it, zend_ce_iterator) == FAILURE) {
return;
}
spl_array_iterator_append(intern->u.append.zarrayit, it TSRMLS_CC);
@@ -2024,6 +2613,30 @@ SPL_METHOD(AppendIterator, next)
spl_append_it_next(intern TSRMLS_CC);
} /* }}} */
+/* {{{ proto int AppendIterator::getIteratorIndex()
+ Get index of iterator */
+SPL_METHOD(AppendIterator, getIteratorIndex)
+{
+ spl_dual_it_object *intern;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ APPENDIT_CHECK_CTOR(intern);
+ spl_array_iterator_key(intern->u.append.zarrayit, return_value TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto ArrayIterator AppendIterator::getArrayIterator()
+ Get access to inner ArrayIterator */
+SPL_METHOD(AppendIterator, getArrayIterator)
+{
+ spl_dual_it_object *intern;
+
+ intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ APPENDIT_CHECK_CTOR(intern);
+ RETURN_ZVAL(intern->u.append.zarrayit, 1, 0);
+} /* }}} */
+
static
ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0)
ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
@@ -2038,66 +2651,105 @@ static zend_function_entry spl_funcs_AppendIterator[] = {
SPL_ME(dual_it, current, NULL, ZEND_ACC_PUBLIC)
SPL_ME(AppendIterator, next, NULL, ZEND_ACC_PUBLIC)
SPL_ME(dual_it, getInnerIterator, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, getIteratorIndex, NULL, ZEND_ACC_PUBLIC)
+ SPL_ME(AppendIterator, getArrayIterator, NULL, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
-/* {{{ proto array iterator_to_array(Traversable it)
- Copy the iterator into an array */
-PHP_FUNCTION(iterator_to_array)
+PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC)
{
- zval *obj, **data;
zend_object_iterator *iter;
- char *str_key;
- uint str_key_len;
- ulong int_key;
- int key_type;
+ zend_class_entry *ce = Z_OBJCE_P(obj);
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
- RETURN_FALSE;
+ iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC);
+
+ if (EG(exception)) {
+ goto done;
}
-
- array_init(return_value);
-
- iter = Z_OBJCE_P(obj)->get_iterator(Z_OBJCE_P(obj), obj TSRMLS_CC);
if (iter->funcs->rewind) {
iter->funcs->rewind(iter TSRMLS_CC);
+ if (EG(exception)) {
+ goto done;
+ }
}
- if (EG(exception)) {
- return;
- }
+
while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
- iter->funcs->get_current_data(iter, &data TSRMLS_CC);
if (EG(exception)) {
- return;
+ goto done;
}
- (*data)->refcount++;
- if (iter->funcs->get_current_key) {
- key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
- if (EG(exception)) {
- return;
- }
- switch(key_type) {
- case HASH_KEY_IS_STRING:
- add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
- efree(str_key);
- break;
- case HASH_KEY_IS_LONG:
- add_index_zval(return_value, int_key, *data);
- break;
- }
- } else {
- add_next_index_zval(return_value, *data);
+ if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) {
+ goto done;
}
iter->funcs->move_forward(iter TSRMLS_CC);
if (EG(exception)) {
- return;
+ goto done;
}
}
+
+done:
iter->funcs->dtor(iter TSRMLS_CC);
+ return EG(exception) ? FAILURE : SUCCESS;
+}
+/* }}} */
+
+static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ zval **data, *return_value = (zval*)puser;
+ char *str_key;
+ uint str_key_len;
+ ulong int_key;
+ int key_type;
+
+ iter->funcs->get_current_data(iter, &data TSRMLS_CC);
if (EG(exception)) {
- return;
+ return ZEND_HASH_APPLY_STOP;
+ }
+ if (iter->funcs->get_current_key) {
+ key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC);
+ if (EG(exception)) {
+ return ZEND_HASH_APPLY_STOP;
+ }
+ (*data)->refcount++;
+ switch(key_type) {
+ case HASH_KEY_IS_STRING:
+ add_assoc_zval_ex(return_value, str_key, str_key_len, *data);
+ efree(str_key);
+ break;
+ case HASH_KEY_IS_LONG:
+ add_index_zval(return_value, int_key, *data);
+ break;
+ }
+ } else {
+ (*data)->refcount++;
+ add_next_index_zval(return_value, *data);
}
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+/* {{{ proto array iterator_to_array(Traversable it)
+ Copy the iterator into an array */
+PHP_FUNCTION(iterator_to_array)
+{
+ zval *obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+
+ if (spl_iterator_apply(obj, spl_iterator_to_array_apply, (void*)return_value TSRMLS_CC) != SUCCESS) {
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+}
+
+static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ (*(long*)puser)++;
+ return ZEND_HASH_APPLY_KEEP;
}
/* }}} */
@@ -2105,38 +2757,64 @@ PHP_FUNCTION(iterator_to_array)
Count the elements in an iterator */
PHP_FUNCTION(iterator_count)
{
- zval *obj;
- zend_object_iterator *iter;
- long count = 0;
+ zval *obj;
+ long count = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) {
RETURN_FALSE;
}
- iter = Z_OBJCE_P(obj)->get_iterator(Z_OBJCE_P(obj), obj TSRMLS_CC);
+ if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) {
+ RETURN_LONG(count);
+ }
+}
+/* }}} */
- if (iter->funcs->rewind) {
- iter->funcs->rewind(iter TSRMLS_CC);
+typedef struct {
+ zval *obj;
+ zval *args;
+ long count;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+} spl_iterator_apply_info;
+
+static int spl_iterator_func_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */
+{
+ zval *retval;
+ spl_iterator_apply_info *apply_info = (spl_iterator_apply_info*)puser;
+ int result;
+
+ apply_info->count++;
+ zend_fcall_info_call(&apply_info->fci, &apply_info->fcc, &retval, NULL TSRMLS_CC);
+ if (retval) {
+ result = zend_is_true(retval) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_STOP;
+ zval_ptr_dtor(&retval);
+ } else {
+ result = ZEND_HASH_APPLY_STOP;
}
- if (EG(exception)) {
+ return result;
+}
+/* }}} */
+
+/* {{{ proto int iterator_apply(Traversable it, mixed function [, mixed params])
+ Calls a function for every element in an iterator */
+PHP_FUNCTION(iterator_apply)
+{
+ spl_iterator_apply_info apply_info;
+
+ apply_info.args = NULL;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of|a!", &apply_info.obj, zend_ce_traversable, &apply_info.fci, &apply_info.fcc, &apply_info.args) == FAILURE) {
return;
}
- while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) {
- if (EG(exception)) {
- return;
- }
- count++;
- iter->funcs->move_forward(iter TSRMLS_CC);
- if (EG(exception)) {
- return;
- }
- }
- iter->funcs->dtor(iter TSRMLS_CC);
- if (EG(exception)) {
- return;
+
+ apply_info.count = 0;
+ zend_fcall_info_args(&apply_info.fci, apply_info.args TSRMLS_CC);
+ if (spl_iterator_apply(apply_info.obj, spl_iterator_func_apply, (void*)&apply_info TSRMLS_CC) == SUCCESS) {
+ RETVAL_LONG(apply_info.count);
+ } else {
+ RETVAL_FALSE;
}
-
- RETURN_LONG(count);
+ zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC);
}
/* }}} */
@@ -2177,6 +2855,7 @@ PHP_MINIT_FUNCTION(spl_iterators)
REGISTER_SPL_STD_CLASS_EX(IteratorIterator, spl_dual_it_new, spl_funcs_IteratorIterator);
REGISTER_SPL_ITERATOR(IteratorIterator);
+ REGISTER_SPL_IMPLEMENTS(IteratorIterator, OuterIterator);
REGISTER_SPL_SUB_CLASS_EX(FilterIterator, IteratorIterator, spl_dual_it_new, spl_funcs_FilterIterator);
spl_ce_FilterIterator->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
@@ -2192,11 +2871,14 @@ PHP_MINIT_FUNCTION(spl_iterators)
REGISTER_SPL_SUB_CLASS_EX(LimitIterator, IteratorIterator, spl_dual_it_new, spl_funcs_LimitIterator);
REGISTER_SPL_SUB_CLASS_EX(CachingIterator, IteratorIterator, spl_dual_it_new, spl_funcs_CachingIterator);
+ REGISTER_SPL_IMPLEMENTS(CachingIterator, ArrayAccess);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CALL_TOSTRING", CIT_CALL_TOSTRING);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY);
REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER);
+ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE);
REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator);
REGISTER_SPL_IMPLEMENTS(RecursiveCachingIterator, RecursiveIterator);
@@ -2206,8 +2888,24 @@ PHP_MINIT_FUNCTION(spl_iterators)
REGISTER_SPL_SUB_CLASS_EX(AppendIterator, IteratorIterator, spl_dual_it_new, spl_funcs_AppendIterator);
REGISTER_SPL_IMPLEMENTS(RecursiveIteratorIterator, OuterIterator);
+
REGISTER_SPL_SUB_CLASS_EX(InfiniteIterator, IteratorIterator, spl_dual_it_new, spl_funcs_InfiniteIterator);
-
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ REGISTER_SPL_SUB_CLASS_EX(RegexIterator, FilterIterator, spl_dual_it_new, spl_funcs_RegexIterator);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "USE_KEY", REGIT_USE_KEY);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "MATCH", REGIT_MODE_MATCH);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "GET_MATCH", REGIT_MODE_GET_MATCH);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "ALL_MATCHES", REGIT_MODE_ALL_MATCHES);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "SPLIT", REGIT_MODE_SPLIT);
+ REGISTER_SPL_CLASS_CONST_LONG(RegexIterator, "REPLACE", REGIT_MODE_REPLACE);
+ REGISTER_SPL_PROPERTY(RegexIterator, "replacement", 0);
+ REGISTER_SPL_SUB_CLASS_EX(RecursiveRegexIterator, RegexIterator, spl_dual_it_new, spl_funcs_RecursiveRegexIterator);
+ REGISTER_SPL_IMPLEMENTS(RecursiveRegexIterator, RecursiveIterator);
+#else
+ spl_ce_RegexIterator = NULL;
+ spl_ce_RecursiveRegexIterator = NULL;
+#endif
+
REGISTER_SPL_STD_CLASS_EX(EmptyIterator, NULL, spl_funcs_EmptyIterator);
REGISTER_SPL_ITERATOR(EmptyIterator);
diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h
index 3b39b03cd..c434f4264 100755
--- a/ext/spl/spl_iterators.h
+++ b/ext/spl/spl_iterators.h
@@ -16,13 +16,16 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_iterators.h,v 1.18.2.7 2006/03/05 17:39:49 helly Exp $ */
+/* $Id: spl_iterators.h,v 1.18.2.7.2.9 2006/09/28 22:33:06 tony2001 Exp $ */
#ifndef SPL_ITERATORS_H
#define SPL_ITERATORS_H
#include "php.h"
#include "php_spl.h"
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+#include "ext/pcre/php_pcre.h"
+#endif
#define spl_ce_Traversable zend_ce_traversable
#define spl_ce_Iterator zend_ce_iterator
@@ -45,11 +48,14 @@ extern PHPAPI zend_class_entry *spl_ce_NoRewindIterator;
extern PHPAPI zend_class_entry *spl_ce_InfiniteIterator;
extern PHPAPI zend_class_entry *spl_ce_EmptyIterator;
extern PHPAPI zend_class_entry *spl_ce_AppendIterator;
+extern PHPAPI zend_class_entry *spl_ce_RegexIterator;
+extern PHPAPI zend_class_entry *spl_ce_RecursiveRegexIterator;
PHP_MINIT_FUNCTION(spl_iterators);
PHP_FUNCTION(iterator_to_array);
PHP_FUNCTION(iterator_count);
+PHP_FUNCTION(iterator_apply);
typedef enum {
DIT_Default = 0,
@@ -63,21 +69,41 @@ typedef enum {
DIT_NoRewindIterator,
DIT_InfiniteIterator,
DIT_AppendIterator,
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ DIT_RegexIterator,
+ DIT_RecursiveRegexIterator,
+#endif
DIT_Unknown = ~0
} dual_it_type;
enum {
/* public */
CIT_CALL_TOSTRING = 0x00000001,
- CIT_CATCH_GET_CHILD = 0x00000002,
- CIT_TOSTRING_USE_KEY = 0x00000010,
- CIT_TOSTRING_USE_CURRENT = 0x00000020,
+ CIT_TOSTRING_USE_KEY = 0x00000002,
+ CIT_TOSTRING_USE_CURRENT = 0x00000004,
+ CIT_TOSTRING_USE_INNER = 0x00000008,
+ CIT_CATCH_GET_CHILD = 0x00000010,
+ CIT_FULL_CACHE = 0x00000100,
CIT_PUBLIC = 0x0000FFFF,
/* private */
CIT_VALID = 0x00010000,
CIT_HAS_CHILDREN = 0x00020000
};
+enum {
+ /* public */
+ REGIT_USE_KEY = 0x00000001,
+};
+
+typedef enum {
+ REGIT_MODE_MATCH,
+ REGIT_MODE_GET_MATCH,
+ REGIT_MODE_ALL_MATCHES,
+ REGIT_MODE_SPLIT,
+ REGIT_MODE_REPLACE,
+ REGIT_MODE_MAX,
+} regex_mode;
+
typedef struct _spl_dual_it_object {
zend_object std;
struct {
@@ -101,17 +127,32 @@ typedef struct _spl_dual_it_object {
long count;
} limit;
struct {
- int flags; /* CIT_* */
+ long flags; /* CIT_* */
zval *zstr;
zval *zchildren;
+ zval *zcache;
} caching;
struct {
zval *zarrayit;
zend_object_iterator *iterator;
} append;
+#if HAVE_PCRE || HAVE_BUNDLED_PCRE
+ struct {
+ int use_flags;
+ long flags;
+ regex_mode mode;
+ long preg_flags;
+ pcre_cache_entry *pce;
+ char *regex;
+ } regex;
+#endif
} u;
} spl_dual_it_object;
+typedef int (*spl_iterator_apply_func_t)(zend_object_iterator *iter, void *puser TSRMLS_DC);
+
+PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC);
+
#endif /* SPL_ITERATORS_H */
/*
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
index fc7259e1e..c13d3620a 100755
--- a/ext/spl/spl_observer.c
+++ b/ext/spl/spl_observer.c
@@ -16,7 +16,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: spl_observer.c,v 1.2.2.6 2006/03/29 14:28:42 tony2001 Exp $ */
+/* $Id: spl_observer.c,v 1.2.2.6.2.1 2006/08/23 09:32:24 bjori Exp $ */
#ifdef HAVE_CONFIG_H
# include "config.h"
@@ -261,7 +261,7 @@ SPL_METHOD(SplObjectStorage, next)
static
ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
- ZEND_ARG_INFO(0, object 0)
+ ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO();
static zend_function_entry spl_funcs_SplObjectStorage[] = {
diff --git a/ext/spl/tests/array_013.phpt b/ext/spl/tests/array_013.phpt
index 6d74bcb41..905b8339c 100755
--- a/ext/spl/tests/array_013.phpt
+++ b/ext/spl/tests/array_013.phpt
@@ -78,4 +78,4 @@ one=>1
two=>2
===Append===
-Fatal error: ArrayIterator::append(): Cannot append properties to objects, use ArrayIterator::offsetSet() instead in %sarray_013.php on line %d
+Catchable fatal error: ArrayIterator::append(): Cannot append properties to objects, use ArrayIterator::offsetSet() instead in %sarray_013.php on line %d
diff --git a/ext/spl/tests/array_019.phpt b/ext/spl/tests/array_019.phpt
index 1416d8407..43d53b127 100755
--- a/ext/spl/tests/array_019.phpt
+++ b/ext/spl/tests/array_019.phpt
@@ -28,5 +28,5 @@ int(1)
int(2)
int(3)
int(4)
-int(5)
-===DONE===
+
+Fatal error: An iterator cannot be used with foreach by reference in %sarray_019.php on line %d
diff --git a/ext/spl/tests/array_021.phpt b/ext/spl/tests/array_021.phpt
index f2ae0c87e..b38cedf0c 100755
--- a/ext/spl/tests/array_021.phpt
+++ b/ext/spl/tests/array_021.phpt
@@ -1,5 +1,7 @@
--TEST--
SPL: ArrayObject::seek() and exceptions
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php
diff --git a/ext/spl/tests/array_022.phpt b/ext/spl/tests/array_022.phpt
index d1eafd677..9cb2193f1 100755
--- a/ext/spl/tests/array_022.phpt
+++ b/ext/spl/tests/array_022.phpt
@@ -1,5 +1,7 @@
--TEST--
SPL: ArrayObject/Iterator and reference to self
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
==ArrayObject===
<?php
@@ -68,27 +70,3 @@ object(MyArrayIterator)#%d (2) {
string(3) "Foo"
}
===DONE===
---UEXPECTF--
-==ArrayObject===
-object(MyArrayObject)#%d (1) {
- [u"bar"]=>
- unicode(3) "baz"
-}
-object(MyArrayObject)#%d (2) {
- [u"bar"]=>
- unicode(3) "baz"
- [u"baz"]=>
- unicode(3) "Foo"
-}
-==ArrayIterator===
-object(MyArrayIterator)#%d (1) {
- [u"bar"]=>
- unicode(3) "baz"
-}
-object(MyArrayIterator)#%d (2) {
- [u"bar"]=>
- unicode(3) "baz"
- [u"baz"]=>
- unicode(3) "Foo"
-}
-===DONE===
diff --git a/ext/spl/tests/bug36941.phpt b/ext/spl/tests/bug36941.phpt
index 528ba4a46..2ae03b448 100755
--- a/ext/spl/tests/bug36941.phpt
+++ b/ext/spl/tests/bug36941.phpt
@@ -1,5 +1,7 @@
--TEST--
Bug #36941 (ArrayIterator does not clone itself)
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
===ArrayObject===
<?php
diff --git a/ext/spl/tests/bug37457.phpt b/ext/spl/tests/bug37457.phpt
new file mode 100755
index 000000000..4395287bc
--- /dev/null
+++ b/ext/spl/tests/bug37457.phpt
@@ -0,0 +1,82 @@
+--TEST--
+Bug #37457 (Crash when an exception is thrown in accept() method of FilterIterator)
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class Collection implements Iterator
+{
+ protected $array, $valid = false;
+
+ public function __construct(array $a)
+ {
+ echo __METHOD__ . "\n";
+ $this->array = $a;
+ }
+
+ public function current()
+ {
+ echo __METHOD__ . "\n";
+ return current($this->array);
+ }
+
+ public function key()
+ {
+ echo __METHOD__ . "\n";
+ return key($this->array);
+ }
+
+ public function next()
+ {
+ echo __METHOD__ . "\n";
+ $this->valid = (false !== next($this->array));
+ }
+
+ public function valid()
+ {
+ echo __METHOD__ . "\n";
+ return $this->valid;
+ }
+
+ public function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->valid = (false !== reset($this->array));
+ }
+}
+
+class TestFilter extends FilterIterator
+{
+ public function accept()
+ {
+ echo __METHOD__ . "\n";
+ throw new Exception("Failure in Accept");
+ }
+}
+
+$test = new TestFilter(new Collection(array(0)));
+
+try
+{
+ foreach ($test as $item)
+ {
+ echo $item;
+ }
+}
+catch (Exception $e)
+{
+ var_dump($e->getMessage());
+}
+
+?>
+===DONE===
+--EXPECTF--
+Collection::__construct
+Collection::rewind
+Collection::valid
+Collection::current
+Collection::key
+TestFilter::accept
+string(17) "Failure in Accept"
+===DONE===
diff --git a/ext/spl/tests/fileobject_003.phpt b/ext/spl/tests/fileobject_003.phpt
new file mode 100755
index 000000000..74f2002d0
--- /dev/null
+++ b/ext/spl/tests/fileobject_003.phpt
@@ -0,0 +1,89 @@
+--TEST--
+SPL: SplFileInfo cloning
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function test($name, $lc, $lp)
+{
+ static $i = 0;
+ echo "===$i===\n";
+ $i++;
+
+ $o = new SplFileInfo($name);
+
+ var_dump($o);
+ $c = clone $o;
+ var_dump($c);
+ var_dump($o === $c);
+ var_dump($o == $c);
+ var_dump($o->getPathname() == $c->getPathname());
+
+ $f = new SplFileObject($name);
+ var_dump($name);
+ var_dump($f->getPathName());
+ $l = substr($f->getPathName(), -1);
+ var_dump($l != '/' && $l != '\\' && $l == $lc);
+ var_dump($f->getFileName());
+ $l = substr($f->getFileName(), -1);
+ var_dump($l != '/' && $l != '\\' && $l == $lc);
+ var_dump($f->getPath());
+ $l = substr($f->getPath(), -1);
+ var_dump($l != '/' && $l != '\\' && $l == $lp);
+}
+
+test(dirname(__FILE__) . '/' . 'fileobject_001a.txt', 't', substr(dirname(__FILE__),-1));
+test(dirname(__FILE__) . '/', substr(dirname(__FILE__),-1), 'l');
+test(dirname(__FILE__), substr(dirname(__FILE__),-1), 'l');
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===0===
+object(SplFileInfo)#%d (0) {
+}
+object(SplFileInfo)#%d (0) {
+}
+bool(false)
+bool(true)
+bool(true)
+string(%d) "%sfileobject_001a.txt"
+string(%d) "%sfileobject_001a.txt"
+bool(true)
+string(%d) "%sfileobject_001a.txt"
+bool(true)
+string(%d) "%stests"
+bool(true)
+===1===
+object(SplFileInfo)#%d (0) {
+}
+object(SplFileInfo)#%d (0) {
+}
+bool(false)
+bool(true)
+bool(true)
+string(%d) "%stests/"
+string(%d) "%stests"
+bool(true)
+string(%d) "%stests"
+bool(true)
+string(%d) "%sspl"
+bool(true)
+===2===
+object(SplFileInfo)#1 (0) {
+}
+object(SplFileInfo)#2 (0) {
+}
+bool(false)
+bool(true)
+bool(true)
+string(%d) "%stests"
+string(%d) "%stests"
+bool(true)
+string(%d) "%stests"
+bool(true)
+string(%d) "%sspl"
+bool(true)
+===DONE===
diff --git a/ext/spl/tests/iterator_027.phpt b/ext/spl/tests/iterator_027.phpt
new file mode 100755
index 000000000..601515e8f
--- /dev/null
+++ b/ext/spl/tests/iterator_027.phpt
@@ -0,0 +1,85 @@
+--TEST--
+SPL: CachingIterator::FULL_CACHE
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+$ar = array(1, 2, array(31, 32, array(331)), 4);
+
+$it = new RecursiveArrayIterator($ar);
+$it = new RecursiveIteratorIterator($it);
+$it = new CachingIterator($it, CachingIterator::FULL_CACHE);
+
+foreach($it as $k=>$v)
+{
+ echo "$k=>$v\n";
+}
+
+echo "===CHECK===\n";
+
+for ($i = 0; $i < 4; $i++)
+{
+ if (isset($it[$i]))
+ {
+ var_dump($i, $it[$i]);
+ }
+}
+
+$it[2] = 'foo';
+$it[3] = 'bar';
+$it['baz'] = '25';
+
+var_dump($it[2]);
+var_dump($it[3]);
+var_dump($it['baz']);
+
+unset($it[0]);
+unset($it[2]);
+unset($it['baz']);
+
+var_dump(isset($it[0])); // unset
+var_dump(isset($it[1])); // still present
+var_dump(isset($it[2])); // unset
+var_dump(isset($it[3])); // still present
+var_dump(isset($it['baz']));
+
+echo "===REWIND===\n";
+
+$it->rewind(); // cleans and reads first element
+var_dump(isset($it[0])); // pre-fetched
+var_dump(isset($it[1])); // deleted
+var_dump(isset($it[2])); // unset
+var_dump(isset($it[3])); // deleted
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+0=>1
+1=>2
+0=>31
+1=>32
+0=>331
+3=>4
+===CHECK===
+int(0)
+int(331)
+int(1)
+int(32)
+int(3)
+int(4)
+string(3) "foo"
+string(3) "bar"
+string(2) "25"
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+===REWIND===
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/spl/tests/iterator_029.phpt b/ext/spl/tests/iterator_029.phpt
new file mode 100755
index 000000000..3e836adef
--- /dev/null
+++ b/ext/spl/tests/iterator_029.phpt
@@ -0,0 +1,40 @@
+--TEST--
+SPL: RegexIterator
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+$ar = array(0, "123", 123, 22 => "abc", "a2b", 22, "a2d" => 7, 42);
+
+foreach(new RegexIterator(new ArrayIterator($ar), "/2/") as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+?>
+===KEY===
+<?php
+
+foreach(new RegexIterator(new ArrayIterator($ar), "/2/", 0, RegexIterator::USE_KEY) as $k => $v)
+{
+ echo "$k=>$v\n";
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+1=>123
+2=>123
+23=>a2b
+24=>22
+25=>42
+===KEY===
+2=>123
+22=>abc
+23=>a2b
+24=>22
+a2d=>7
+25=>42
+===DONE===
diff --git a/ext/spl/tests/iterator_035.phpt b/ext/spl/tests/iterator_035.phpt
index eebc7f22a..9dfe35d5f 100644
--- a/ext/spl/tests/iterator_035.phpt
+++ b/ext/spl/tests/iterator_035.phpt
@@ -14,4 +14,4 @@ $a[] = &$tmp;
echo "Done\n";
?>
--EXPECTF--
-Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %s on line %d
+Fatal error: Cannot assign by reference to overloaded object in %s on line %d
diff --git a/ext/spl/tests/iterator_036.phpt b/ext/spl/tests/iterator_036.phpt
new file mode 100755
index 000000000..3eb0eefa6
--- /dev/null
+++ b/ext/spl/tests/iterator_036.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: CachingIterator and __toString and flags = 0
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function test($it)
+{
+ foreach($it as $v)
+ {
+ var_dump((string)$it);
+ }
+}
+
+$ar = new ArrayIterator(array(1, 2, 3));
+
+test(new CachingIterator($ar, 0));
+
+?>
+===DONE===
+--EXPECTF--
+
+Fatal error: Method CachingIterator::__toString() must not throw an exception in %siterator_036.php on line %d
diff --git a/ext/spl/tests/iterator_037.phpt b/ext/spl/tests/iterator_037.phpt
new file mode 100755
index 000000000..be79468f3
--- /dev/null
+++ b/ext/spl/tests/iterator_037.phpt
@@ -0,0 +1,133 @@
+--TEST--
+SPL: CachingIterator and __toString
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function test($ar, $flags)
+{
+ echo "===$flags===\n";
+ $it = new CachingIterator($ar, 0);
+ try
+ {
+ $it->setFlags($flags);
+ }
+ catch (Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ var_dump($it->getFlags());
+ return;
+ }
+ var_dump($it->getFlags());
+ try
+ {
+ foreach($it as $v)
+ {
+ var_dump((string)$it);
+ }
+ }
+ catch (Exception $e)
+ {
+ echo 'Exception: ' . $e->getMessage() . "\n";
+ }
+}
+
+class MyItem
+{
+ function __construct($value)
+ {
+ $this->value = $value;
+ }
+
+ function __toString()
+ {
+ return (string)$this->value;
+ }
+}
+
+class MyArrayIterator extends ArrayIterator
+{
+ function __toString()
+ {
+ return $this->key() . ':' . $this->current();
+ }
+}
+
+$ar = new MyArrayIterator(array(1, 2, 3));
+
+test($ar, CachingIterator::CALL_TOSTRING);
+test($ar, CachingIterator::TOSTRING_USE_KEY);
+test($ar, CachingIterator::TOSTRING_USE_CURRENT);
+
+$ar = new MyArrayIterator(array(new MyItem(1), new MyItem(2), new MyItem(3)));
+
+test($ar, CachingIterator::TOSTRING_USE_INNER);
+test($ar, CachingIterator::CALL_TOSTRING | CachingIterator::TOSTRING_USE_KEY);
+test($ar, CachingIterator::CALL_TOSTRING | CachingIterator::TOSTRING_USE_CURRENT);
+test($ar, CachingIterator::CALL_TOSTRING | CachingIterator::TOSTRING_USE_INNER);
+test($ar, CachingIterator::TOSTRING_USE_KEY | CachingIterator::TOSTRING_USE_CURRENT);
+test($ar, CachingIterator::TOSTRING_USE_KEY | CachingIterator::TOSTRING_USE_INNER);
+
+echo "===X===\n";
+try
+{
+ $it = new CachingIterator($ar, CachingIterator::CALL_TOSTRING);
+ $it->setFlags(0);
+}
+catch (Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+try
+{
+ $it = new CachingIterator($ar, CachingIterator::TOSTRING_USE_INNER);
+ $it->setFlags(0);
+}
+catch (Exception $e)
+{
+ echo 'Exception: ' . $e->getMessage() . "\n";
+}
+
+?>
+===DONE===
+--EXPECTF--
+===1===
+int(1)
+string(1) "1"
+string(1) "2"
+string(1) "3"
+===2===
+int(2)
+string(1) "0"
+string(1) "1"
+string(1) "2"
+===4===
+int(4)
+string(1) "1"
+string(1) "2"
+string(1) "3"
+===8===
+int(8)
+string(3) "0:1"
+string(3) "1:2"
+string(3) "2:3"
+===3===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===5===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===9===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===6===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===10===
+Exception: Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER
+int(0)
+===X===
+Exception: Unsetting flag CALL_TO_STRING is not possible
+Exception: Unsetting flag TOSTRING_USE_INNER is not possible
+===DONE===
diff --git a/ext/spl/tests/iterator_038.phpt b/ext/spl/tests/iterator_038.phpt
new file mode 100755
index 000000000..71f911c57
--- /dev/null
+++ b/ext/spl/tests/iterator_038.phpt
@@ -0,0 +1,21 @@
+--TEST--
+SPL: RoRewindIterator and string keys
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+foreach(new NoRewindIterator(new ArrayIterator(array('Hello'=>0, 'World'=>1))) as $k => $v)
+{
+ var_dump($v);
+ var_dump($k);
+}
+
+?>
+===DONE===
+--EXPECT--
+int(0)
+string(5) "Hello"
+int(1)
+string(5) "World"
+===DONE===
diff --git a/ext/spl/tests/iterator_039.phpt b/ext/spl/tests/iterator_039.phpt
new file mode 100755
index 000000000..5dcaaa226
--- /dev/null
+++ b/ext/spl/tests/iterator_039.phpt
@@ -0,0 +1,123 @@
+--TEST--
+SPL: LimitIterator and backward seeking
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class NumericArrayIterator implements Iterator
+{
+ protected $a;
+ protected $i = 0;
+
+ public function __construct($a)
+ {
+ echo __METHOD__ . "\n";
+ $this->a = $a;
+ }
+
+ public function valid()
+ {
+ echo __METHOD__ . "\n";
+ return $this->i < count($this->a);
+ }
+
+ public function rewind()
+ {
+ echo __METHOD__ . "\n";
+ $this->i = 0;
+ }
+
+ public function key()
+ {
+ echo __METHOD__ . "\n";
+ return $this->i;
+ }
+
+ public function current()
+ {
+ echo __METHOD__ . "\n";
+ return $this->a[$this->i];
+ }
+
+ public function next()
+ {
+ echo __METHOD__ . "\n";
+ $this->i++;
+ }
+}
+
+$it = new LimitIterator(new NumericArrayIterator(array(12, 25, 42, 56)));
+
+foreach($it as $k => $v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+echo "===SEEK===\n";
+
+$it->seek(2);
+
+echo "===LOOP===\n";
+
+foreach(new NoRewindIterator($it) as $k => $v)
+{
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+NumericArrayIterator::__construct
+NumericArrayIterator::rewind
+NumericArrayIterator::valid
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(0)
+int(12)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(1)
+int(25)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(2)
+int(42)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(3)
+int(56)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+===SEEK===
+NumericArrayIterator::rewind
+NumericArrayIterator::valid
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+===LOOP===
+int(2)
+int(42)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+NumericArrayIterator::current
+NumericArrayIterator::key
+int(3)
+int(56)
+NumericArrayIterator::next
+NumericArrayIterator::valid
+===DONE===
diff --git a/ext/spl/tests/iterator_040.phpt b/ext/spl/tests/iterator_040.phpt
new file mode 100755
index 000000000..a162cac68
--- /dev/null
+++ b/ext/spl/tests/iterator_040.phpt
@@ -0,0 +1,49 @@
+--TEST--
+SPL: RecursiveFilterIterator
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRecursiveFilterIterator extends RecursiveFilterIterator
+{
+ function accept()
+ {
+ return true;
+ }
+}
+
+$ar = array(1, array(21, 22), 3);
+$it = new RecursiveArrayIterator($ar);
+$it = new MyRecursiveFilterIterator($it);
+$it = new RecursiveIteratorIterator($it);
+
+foreach($it as $k => $v)
+{
+ echo "===\n";
+ var_dump($it->getDepth());
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===
+int(0)
+int(0)
+int(1)
+===
+int(1)
+int(0)
+int(21)
+===
+int(1)
+int(1)
+int(22)
+===
+int(0)
+int(2)
+int(3)
+===DONE===
diff --git a/ext/spl/tests/iterator_041.phpt b/ext/spl/tests/iterator_041.phpt
new file mode 100755
index 000000000..af42b1cde
--- /dev/null
+++ b/ext/spl/tests/iterator_041.phpt
@@ -0,0 +1,119 @@
+--TEST--
+SPL: iterator_to_array() and exceptions
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ static protected $fail = 0;
+ public $state;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function __construct()
+ {
+ $this->state = MyArrayIterator::$fail;
+ self::fail(0, __FUNCTION__);
+ parent::__construct(array(1, 2));
+ self::fail(1, __FUNCTION__);
+ }
+
+ function rewind()
+ {
+ self::fail(2, __FUNCTION__);
+ return parent::rewind();
+ }
+
+ function valid()
+ {
+ self::fail(3, __FUNCTION__);
+ return parent::valid();
+ }
+
+ function current()
+ {
+ self::fail(4, __FUNCTION__);
+ return parent::current();
+ }
+
+ function key()
+ {
+ self::fail(5, __FUNCTION__);
+ return parent::key();
+ }
+
+ function next()
+ {
+ self::fail(6, __FUNCTION__);
+ return parent::next();
+ }
+
+ function __destruct()
+ {
+// self::fail(7, __FUNCTION__);
+ }
+
+ static function test($func, $skip = null)
+ {
+ echo "===$func===\n";
+ self::$fail = 0;
+ while(self::$fail < 10)
+ {
+ try
+ {
+ var_dump($func(new MyArrayIterator()));
+ break;
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+ if (isset($skip[self::$fail]))
+ {
+ self::$fail = $skip[self::$fail];
+ }
+ else
+ {
+ self::$fail++;
+ }
+ }
+ }
+}
+
+MyArrayIterator::test('iterator_to_array');
+MyArrayIterator::test('iterator_count', array(3 => 6));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===iterator_to_array===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 4: current()
+State 5: key()
+State 6: next()
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
+===iterator_count===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 6: next()
+int(2)
+===DONE===
diff --git a/ext/spl/tests/iterator_041a.phpt b/ext/spl/tests/iterator_041a.phpt
new file mode 100755
index 000000000..d03cbba9d
--- /dev/null
+++ b/ext/spl/tests/iterator_041a.phpt
@@ -0,0 +1,109 @@
+--TEST--
+SPL: iterator_to_array() and exceptions from destruct
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ static protected $fail = 0;
+ public $state;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function __construct()
+ {
+ $this->state = MyArrayIterator::$fail;
+ self::fail(0, __FUNCTION__);
+ parent::__construct(array(1, 2));
+ self::fail(1, __FUNCTION__);
+ }
+
+ function rewind()
+ {
+ self::fail(2, __FUNCTION__);
+ return parent::rewind();
+ }
+
+ function valid()
+ {
+ self::fail(3, __FUNCTION__);
+ return parent::valid();
+ }
+
+ function current()
+ {
+ self::fail(4, __FUNCTION__);
+ return parent::current();
+ }
+
+ function key()
+ {
+ self::fail(5, __FUNCTION__);
+ return parent::key();
+ }
+
+ function next()
+ {
+ self::fail(6, __FUNCTION__);
+ return parent::next();
+ }
+
+ function __destruct()
+ {
+ self::fail(7, __FUNCTION__);
+ }
+
+ static function test($func, $skip = null)
+ {
+ echo "===$func===\n";
+ self::$fail = 7;
+ while(self::$fail < 10)
+ {
+ try
+ {
+ var_dump($func(new MyArrayIterator()));
+ break;
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+ if (isset($skip[self::$fail]))
+ {
+ self::$fail = $skip[self::$fail];
+ }
+ else
+ {
+ self::$fail++;
+ }
+ }
+ }
+}
+
+MyArrayIterator::test('iterator_to_array');
+MyArrayIterator::test('iterator_count', array(3 => 6));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECT--
+===iterator_to_array===
+State 7: __destruct()
+array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(2)
+}
+===iterator_count===
+State 7: __destruct()
+int(2)
+===DONE===
diff --git a/ext/spl/tests/iterator_041b.phpt b/ext/spl/tests/iterator_041b.phpt
new file mode 100755
index 000000000..9afb93526
--- /dev/null
+++ b/ext/spl/tests/iterator_041b.phpt
@@ -0,0 +1,107 @@
+--TEST--
+SPL: iterator_to_array() and exceptions from delayed destruct
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyArrayIterator extends ArrayIterator
+{
+ static protected $fail = 0;
+ public $state;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function __construct()
+ {
+ $this->state = MyArrayIterator::$fail;
+ self::fail(0, __FUNCTION__);
+ parent::__construct(array(1, 2));
+ self::fail(1, __FUNCTION__);
+ }
+
+ function rewind()
+ {
+ self::fail(2, __FUNCTION__);
+ return parent::rewind();
+ }
+
+ function valid()
+ {
+ self::fail(3, __FUNCTION__);
+ return parent::valid();
+ }
+
+ function current()
+ {
+ self::fail(4, __FUNCTION__);
+ return parent::current();
+ }
+
+ function key()
+ {
+ self::fail(5, __FUNCTION__);
+ return parent::key();
+ }
+
+ function next()
+ {
+ self::fail(6, __FUNCTION__);
+ return parent::next();
+ }
+
+ function __destruct()
+ {
+ self::fail(7, __FUNCTION__);
+ }
+
+ static function test($func, $skip = null)
+ {
+ echo "===$func===\n";
+ self::$fail = 0;
+ while(self::$fail < 10)
+ {
+ try
+ {
+ var_dump($func(new MyArrayIterator()));
+ break;
+ }
+ catch (Exception $e)
+ {
+ echo $e->getMessage() . "\n";
+ }
+ if (isset($skip[self::$fail]))
+ {
+ self::$fail = $skip[self::$fail];
+ }
+ else
+ {
+ self::$fail++;
+ }
+ }
+ }
+}
+
+MyArrayIterator::test('iterator_to_array');
+MyArrayIterator::test('iterator_count', array(3 => 6));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===iterator_to_array===
+State 0: __construct()
+State 1: __construct()
+State 2: rewind()
+State 3: valid()
+State 4: current()
+State 5: key()
+State 6: next()
+
+Fatal error: Ignoring exception from MyArrayIterator::__destruct() while an exception is already active (Uncaught Exception in %s on line %d) in %siterator_041b.php on line %d
diff --git a/ext/spl/tests/iterator_042.phpt b/ext/spl/tests/iterator_042.phpt
new file mode 100755
index 000000000..861545065
--- /dev/null
+++ b/ext/spl/tests/iterator_042.phpt
@@ -0,0 +1,104 @@
+--TEST--
+SPL: AppendIterator and its ArrayIterator
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function test_error_handler($errno, $msg, $filename, $linenum, $vars)
+{
+ echo "Error $msg in $filename on line $linenum\n";
+ return true;
+}
+
+set_error_handler('test_error_handler');
+
+$it = new AppendIterator;
+
+$it->append(array());
+$it->append(new ArrayIterator(array(1)));
+$it->append(new ArrayIterator(array(21, 22)));
+
+var_dump($it->getArrayIterator());
+
+$it->append(new ArrayIterator(array(31, 32, 33)));
+
+var_dump($it->getArrayIterator());
+
+$idx = 0;
+
+foreach($it as $k => $v)
+{
+ echo '===' . $idx++ . "===\n";
+ var_dump($it->getIteratorIndex());
+ var_dump($k);
+ var_dump($v);
+}
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Error Argument 1 passed to AppendIterator::append() must implement interface Iterator, array given in %siterator_042.php on line %d
+object(ArrayIterator)#%d (2) {
+ [0]=>
+ object(ArrayIterator)#%d (1) {
+ [0]=>
+ int(1)
+ }
+ [1]=>
+ object(ArrayIterator)#%d (2) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+ }
+}
+object(ArrayIterator)#%d (3) {
+ [0]=>
+ object(ArrayIterator)#%d (1) {
+ [0]=>
+ int(1)
+ }
+ [1]=>
+ object(ArrayIterator)#%d (2) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+ }
+ [2]=>
+ object(ArrayIterator)#5 (3) {
+ [0]=>
+ int(31)
+ [1]=>
+ int(32)
+ [2]=>
+ int(33)
+ }
+}
+===0===
+int(0)
+int(0)
+int(1)
+===1===
+int(1)
+int(0)
+int(21)
+===2===
+int(1)
+int(1)
+int(22)
+===3===
+int(2)
+int(0)
+int(31)
+===4===
+int(2)
+int(1)
+int(32)
+===5===
+int(2)
+int(2)
+int(33)
+===DONE===
diff --git a/ext/spl/tests/iterator_043.phpt b/ext/spl/tests/iterator_043.phpt
new file mode 100755
index 000000000..c49e33473
--- /dev/null
+++ b/ext/spl/tests/iterator_043.phpt
@@ -0,0 +1,20 @@
+--TEST--
+SPL: RecursiveCachingIterator and uninitialized getChildren()
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+$it = new RecursiveCachingIterator(new RecursiveArrayIterator(array(1,2)));
+
+var_dump($it->getChildren());
+$it->rewind();
+var_dump($it->getChildren());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+NULL
+NULL
+===DONE===
diff --git a/ext/spl/tests/iterator_044.phpt b/ext/spl/tests/iterator_044.phpt
new file mode 100755
index 000000000..e25e0d1dd
--- /dev/null
+++ b/ext/spl/tests/iterator_044.phpt
@@ -0,0 +1,169 @@
+--TEST--
+SPL: CachingIterator and offsetGet/Exists using flag FULL_CACHE
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyFoo
+{
+ function __toString()
+ {
+ return 'foo';
+ }
+}
+
+class MyCachingIterator extends CachingIterator
+{
+ function __construct(Iterator $it, $flags = 0)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ function test($ar)
+ {
+ foreach($ar as $k => $v)
+ {
+ echo "===$k===\n";
+ var_dump($v);
+ var_dump($this->offsetExists($v));
+ var_dump($this->offsetGet($v));
+ }
+ }
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)));
+
+try
+{
+ var_dump($it->offsetExists(0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+try
+{
+ var_dump($it->offsetGet(0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)), CachingIterator::FULL_CACHE);
+
+var_dump($it->offsetExists());
+var_dump($it->offsetGet());
+
+$checks = array(0, new stdClass, new MyFoo, NULL, 2, 'foo', 3);
+
+$it->test($checks);
+
+echo "===FILL===\n";
+
+foreach($it as $v); // read all into cache
+
+$it->test($checks);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+
+Notice: Undefined index: 0 in %siterator_044.php on line %d
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+
+Warning: CachingIterator::offsetExists() expects exactly 1 parameter, 0 given in %s/iterator_044.php on line %d
+NULL
+
+Warning: CachingIterator::offsetGet() expects exactly 1 parameter, 0 given in %s/iterator_044.php on line %d
+NULL
+===0===
+int(0)
+bool(false)
+
+Notice: Undefined index: 0 in %siterator_044.php on line %d
+NULL
+===1===
+object(stdClass)#%d (0) {
+}
+
+Warning: CachingIterator::offsetExists() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+
+Warning: CachingIterator::offsetGet() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+===2===
+object(MyFoo)#%d (0) {
+}
+bool(false)
+
+Notice: Undefined index: foo in %siterator_044.php on line %d
+NULL
+===3===
+NULL
+bool(false)
+
+Notice: Undefined index: in %siterator_044.php on line %d
+NULL
+===4===
+int(2)
+bool(false)
+
+Notice: Undefined index: 2 in %siterator_044.php on line %d
+NULL
+===5===
+string(3) "foo"
+bool(false)
+
+Notice: Undefined index: foo in %siterator_044.php on line %d
+NULL
+===6===
+int(3)
+bool(false)
+
+Notice: Undefined index: 3 in %siterator_044.php on line %d
+NULL
+===FILL===
+===0===
+int(0)
+bool(true)
+int(0)
+===1===
+object(stdClass)#1 (0) {
+}
+
+Warning: CachingIterator::offsetExists() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+
+Warning: CachingIterator::offsetGet() expects parameter 1 to be string, object given in %siterator_044.php on line %d
+NULL
+===2===
+object(MyFoo)#2 (0) {
+}
+bool(true)
+int(1)
+===3===
+NULL
+bool(false)
+
+Notice: Undefined index: in %siterator_044.php on line %d
+NULL
+===4===
+int(2)
+bool(true)
+int(4)
+===5===
+string(3) "foo"
+bool(true)
+int(1)
+===6===
+int(3)
+bool(false)
+
+Notice: Undefined index: 3 in %siterator_044.php on line %d
+NULL
+===DONE===
diff --git a/ext/spl/tests/iterator_045.phpt b/ext/spl/tests/iterator_045.phpt
new file mode 100755
index 000000000..ce29349cf
--- /dev/null
+++ b/ext/spl/tests/iterator_045.phpt
@@ -0,0 +1,171 @@
+--TEST--
+SPL: CachingIterator and offsetSet/Unset, getCache using flag FULL_CACHE
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyFoo
+{
+ function __toString()
+ {
+ return 'foo';
+ }
+}
+
+class MyCachingIterator extends CachingIterator
+{
+ function __construct(Iterator $it, $flags = 0)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ function testSet($ar)
+ {
+ echo __METHOD__ . "()\n";
+ foreach($ar as $k => $v)
+ {
+ echo "set($k,$v)\n";
+ $this->offsetSet($k, $v);
+ }
+ }
+
+ function testUnset($ar)
+ {
+ echo __METHOD__ . "()\n";
+ foreach($ar as $k => $v)
+ {
+ echo "unset($v)\n";
+ $this->offsetUnset($v);
+ }
+ }
+
+ function fill()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $v) ;
+ }
+
+ function show()
+ {
+ echo __METHOD__ . "()\n";
+ var_dump($this->getCache());
+ }
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)));
+
+try
+{
+ var_dump($it->offsetSet(0, 0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+try
+{
+ var_dump($it->offsetUnset(0));
+}
+catch(Exception $e)
+{
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 1, 2, 3)), CachingIterator::FULL_CACHE);
+
+var_dump($it->offsetSet());
+var_dump($it->offsetSet(0));
+var_dump($it->offsetUnset());
+
+$checks = array(0 => 25, 1 => 42, 3 => 'FooBar');
+$unsets = array(0, 2);
+
+$it->testSet($checks);
+$it->show();
+$it->testUnset($unsets);
+$it->show();
+$it->fill();
+$it->show();
+$it->testSet($checks);
+$it->show();
+$it->testUnset($unsets);
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct)
+
+Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 0 given in %siterator_045.php on line %d
+NULL
+
+Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 1 given in %siterator_045.php on line %d
+NULL
+
+Warning: CachingIterator::offsetUnset() expects exactly 1 parameter, 0 given in %siterator_045.php on line %d
+NULL
+MyCachingIterator::testSet()
+set(0,25)
+set(1,42)
+set(3,FooBar)
+MyCachingIterator::show()
+array(3) {
+ [0]=>
+ int(25)
+ [1]=>
+ int(42)
+ [3]=>
+ string(6) "FooBar"
+}
+MyCachingIterator::testUnset()
+unset(0)
+unset(2)
+MyCachingIterator::show()
+array(2) {
+ [1]=>
+ int(42)
+ [3]=>
+ string(6) "FooBar"
+}
+MyCachingIterator::fill()
+MyCachingIterator::show()
+array(4) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(1)
+ [2]=>
+ int(2)
+ [3]=>
+ int(3)
+}
+MyCachingIterator::testSet()
+set(0,25)
+set(1,42)
+set(3,FooBar)
+MyCachingIterator::show()
+array(4) {
+ [0]=>
+ int(25)
+ [1]=>
+ int(42)
+ [2]=>
+ int(2)
+ [3]=>
+ string(6) "FooBar"
+}
+MyCachingIterator::testUnset()
+unset(0)
+unset(2)
+MyCachingIterator::show()
+array(2) {
+ [1]=>
+ int(42)
+ [3]=>
+ string(6) "FooBar"
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_046.phpt b/ext/spl/tests/iterator_046.phpt
new file mode 100755
index 000000000..34d9c027b
--- /dev/null
+++ b/ext/spl/tests/iterator_046.phpt
@@ -0,0 +1,53 @@
+--TEST--
+SPL: CachingIterator and __toString using bypassed string keys
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyFoo
+{
+ function __toString()
+ {
+ return 'foo';
+ }
+}
+
+class MyCachingIterator extends CachingIterator
+{
+ function __construct(Iterator $it, $flags = 0)
+ {
+ parent::__construct($it, $flags);
+ }
+
+ function fill()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $v) ;
+ }
+
+ function show()
+ {
+ echo __METHOD__ . "()\n";
+ foreach($this as $v)
+ {
+ var_dump((string)$this);
+ }
+ }
+}
+
+$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 'bar'=>2)), CachingIterator::TOSTRING_USE_KEY);
+
+$it->fill();
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+MyCachingIterator::fill()
+MyCachingIterator::show()
+string(1) "0"
+string(3) "foo"
+string(3) "bar"
+===DONE===
diff --git a/ext/spl/tests/iterator_047.phpt b/ext/spl/tests/iterator_047.phpt
new file mode 100755
index 000000000..b313df301
--- /dev/null
+++ b/ext/spl/tests/iterator_047.phpt
@@ -0,0 +1,119 @@
+--TEST--
+SPL: RecursiveCachingIterator and exception in has/getChildren
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRecursiveArrayIterator extends RecursiveArrayIterator
+{
+ static public $fail = 0;
+
+ static function fail($state, $method)
+ {
+ if (self::$fail == $state)
+ {
+ throw new Exception("State $state: $method()");
+ }
+ }
+
+ function hasChildren()
+ {
+ echo __METHOD__ . "()\n";
+ self::fail(1, __METHOD__);
+ return parent::hasChildren();
+ }
+
+ function getChildren()
+ {
+ echo __METHOD__ . "()\n";
+ self::fail(2, __METHOD__);
+ return parent::getChildren();
+ }
+}
+
+class MyRecursiveCachingIterator extends RecursiveCachingIterator
+{
+ function show()
+ {
+ MyRecursiveArrayIterator::$fail = 0;
+ while(MyRecursiveArrayIterator::$fail < 4)
+ {
+ echo "===" . MyRecursiveArrayIterator::$fail . "===\n";
+ try
+ {
+ foreach(new RecursiveIteratorIterator($this) as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+ catch (Exception $e)
+ {
+ echo "Exception: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine() . "\n";
+ }
+ MyRecursiveArrayIterator::$fail++;
+ }
+ }
+}
+
+$it = new MyRecursiveArrayIterator(array(0, array(10), 2, array(30), 4));
+$it = new MyRecursiveCachingIterator($it);
+
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+===0===
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(0)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(10)
+MyRecursiveArrayIterator::hasChildren()
+int(2)
+int(2)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(30)
+MyRecursiveArrayIterator::hasChildren()
+int(4)
+int(4)
+===1===
+MyRecursiveArrayIterator::hasChildren()
+Exception: State 1: MyRecursiveArrayIterator::hasChildren() in %siterator_047.php on line %d
+===2===
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(0)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+Exception: State 2: MyRecursiveArrayIterator::getChildren() in %siterator_047.php on line %d
+===3===
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(0)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(10)
+MyRecursiveArrayIterator::hasChildren()
+int(2)
+int(2)
+MyRecursiveArrayIterator::hasChildren()
+MyRecursiveArrayIterator::getChildren()
+MyRecursiveArrayIterator::hasChildren()
+int(0)
+int(30)
+MyRecursiveArrayIterator::hasChildren()
+int(4)
+int(4)
+===DONE===
diff --git a/ext/spl/tests/iterator_048.phpt b/ext/spl/tests/iterator_048.phpt
new file mode 100755
index 000000000..5e141d9c7
--- /dev/null
+++ b/ext/spl/tests/iterator_048.phpt
@@ -0,0 +1,38 @@
+--TEST--
+SPL: RecursiveRegexIterator and exception in has/getChildren
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRecursiveRegexIterator extends RecursiveRegexIterator
+{
+ function show()
+ {
+ foreach(new RecursiveIteratorIterator($this) as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+
+ function accept()
+ {
+ return $this->hasChildren() || parent::accept();
+ }
+}
+
+$ar = new RecursiveArrayIterator(array('Foo', array('Bar'), 'FooBar', array('Baz'), 'Biz'));
+$it = new MyRecursiveRegexIterator($ar, '/Bar/');
+
+$it->show();
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(0)
+string(3) "Bar"
+int(2)
+string(6) "FooBar"
+===DONE===
diff --git a/ext/spl/tests/iterator_049.phpt b/ext/spl/tests/iterator_049.phpt
new file mode 100755
index 000000000..8e2564380
--- /dev/null
+++ b/ext/spl/tests/iterator_049.phpt
@@ -0,0 +1,24 @@
+--TEST--
+SPL: ArrayIterator with NULL key
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+$ar = new ArrayIterator(array(NULL=>NULL));
+@var_dump($ar);
+var_dump($ar->getArrayCopy());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+object(ArrayIterator)#%d (1) {
+ [""]=>
+ NULL
+}
+array(1) {
+ [""]=>
+ NULL
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_049b.phpt b/ext/spl/tests/iterator_049b.phpt
new file mode 100755
index 000000000..9b894cd1c
--- /dev/null
+++ b/ext/spl/tests/iterator_049b.phpt
Binary files differ
diff --git a/ext/spl/tests/iterator_050.phpt b/ext/spl/tests/iterator_050.phpt
new file mode 100755
index 000000000..6bd84a3a8
--- /dev/null
+++ b/ext/spl/tests/iterator_050.phpt
@@ -0,0 +1,93 @@
+--TEST--
+SPL: RegexIterator::GET_MATCH
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::GET_MATCH);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::GET_MATCH);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+array(3) {
+ [0]=>
+ string(3) "1,2"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+}
+int(2)
+array(3) {
+ [0]=>
+ string(3) "1,2"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+}
+int(0)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+int(1)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+int(2)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+object(ArrayIterator)#%d (9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_051.phpt b/ext/spl/tests/iterator_051.phpt
new file mode 100755
index 000000000..626d27474
--- /dev/null
+++ b/ext/spl/tests/iterator_051.phpt
@@ -0,0 +1,95 @@
+--TEST--
+SPL: RegexIterator::GET_MATCH, USE_KEY
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::GET_MATCH, RegexIterator::USE_KEY);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::GET_MATCH, RegexIterator::USE_KEY);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(3) "1,2"
+array(3) {
+ [0]=>
+ string(3) "1,2"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+}
+string(5) "1,2,3"
+array(3) {
+ [0]=>
+ string(3) "1,2"
+ [1]=>
+ string(1) "1"
+ [2]=>
+ string(1) "2"
+}
+int(1)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+string(3) "1,2"
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+string(5) "1,2,3"
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "1"
+}
+int(0)
+array(2) {
+ [0]=>
+ string(1) "0"
+ [1]=>
+ string(1) "0"
+}
+object(ArrayIterator)#%d (7) {
+ [1]=>
+ int(0)
+ ["1,2"]=>
+ int(1)
+ ["1,2,3"]=>
+ int(2)
+ [0]=>
+ int(3)
+ ["FooBar"]=>
+ int(4)
+ [","]=>
+ int(5)
+ [",,"]=>
+ int(6)
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_052.phpt b/ext/spl/tests/iterator_052.phpt
new file mode 100755
index 000000000..9bd7d899e
--- /dev/null
+++ b/ext/spl/tests/iterator_052.phpt
@@ -0,0 +1,314 @@
+--TEST--
+SPL: RegexIterator::ALL_MATCHES
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ public $uk, $re;
+
+ function __construct($it, $re, $mode, $flags = 0)
+ {
+ $this->uk = $flags & self::USE_KEY;
+ $this->re = $re;
+ parent::__construct($it, $re, $mode, $flags);
+ }
+
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+
+ function accept()
+ {
+ @preg_match_all($this->re, (string)($this->uk ? $this->key() : $this->current()), $sub);
+ $ret = parent::accept();
+ var_dump($sub == $this->current());
+ return $ret;
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::ALL_MATCHES);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::ALL_MATCHES);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+int(0)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(1)
+array(3) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(3) "1,2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [2]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(2)
+array(3) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(3) "1,2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [2]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(3)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(4)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(5)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(6)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(7)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(8)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(0)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+}
+bool(true)
+int(1)
+array(2) {
+ [0]=>
+ array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ }
+ [1]=>
+ array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(2)
+array(2) {
+ [0]=>
+ array(3) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ [2]=>
+ string(1) "3"
+ }
+ [1]=>
+ array(3) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ [2]=>
+ string(1) "3"
+ }
+}
+bool(true)
+int(3)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(4)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(5)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(6)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(7)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+bool(true)
+int(8)
+array(2) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+}
+object(ArrayIterator)#%d (9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_053.phpt b/ext/spl/tests/iterator_053.phpt
new file mode 100755
index 000000000..4d68b0113
--- /dev/null
+++ b/ext/spl/tests/iterator_053.phpt
@@ -0,0 +1,314 @@
+--TEST--
+SPL: RegexIterator::ALL_MATCHES
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ public $uk, $re;
+
+ function __construct($it, $re, $mode, $flags = 0)
+ {
+ $this->uk = $flags & self::USE_KEY;
+ $this->re = $re;
+ parent::__construct($it, $re, $mode, $flags);
+ }
+
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+
+ function accept()
+ {
+ @preg_match_all($this->re, (string)($this->uk ? $this->key() : $this->current()), $sub);
+ $ret = parent::accept();
+ var_dump($sub == $this->current());
+ return $ret;
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::ALL_MATCHES, RegexIterator::USE_KEY);
+$it->show();
+
+$it = new MyRegexIterator($ar, '/(\d)/', RegexIterator::ALL_MATCHES, RegexIterator::USE_KEY);
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+bool(true)
+int(0)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(1)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(2)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(3)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(4)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(5)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(6)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(7)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(8)
+array(3) {
+ [0]=>
+ array(0) {
+ }
+ [1]=>
+ array(0) {
+ }
+ [2]=>
+ array(0) {
+ }
+}
+bool(true)
+int(0)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "0"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "0"
+ }
+}
+bool(true)
+int(1)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "1"
+ }
+}
+bool(true)
+int(2)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "2"
+ }
+}
+bool(true)
+int(3)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "3"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "3"
+ }
+}
+bool(true)
+int(4)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "4"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "4"
+ }
+}
+bool(true)
+int(5)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "5"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "5"
+ }
+}
+bool(true)
+int(6)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "6"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "6"
+ }
+}
+bool(true)
+int(7)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "7"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "7"
+ }
+}
+bool(true)
+int(8)
+array(2) {
+ [0]=>
+ array(1) {
+ [0]=>
+ string(1) "8"
+ }
+ [1]=>
+ array(1) {
+ [0]=>
+ string(1) "8"
+ }
+}
+object(ArrayIterator)#%d (9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_054.phpt b/ext/spl/tests/iterator_054.phpt
new file mode 100755
index 000000000..3f724697a
--- /dev/null
+++ b/ext/spl/tests/iterator_054.phpt
@@ -0,0 +1,84 @@
+--TEST--
+SPL: RegexIterator::SPLIT
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1','1,2','1,2,3','',NULL,array(),'FooBar',',',',,'));
+$it = new MyRegexIterator($ar, '/,/', RegexIterator::SPLIT);
+
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(1)
+array(2) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+}
+int(2)
+array(3) {
+ [0]=>
+ string(1) "1"
+ [1]=>
+ string(1) "2"
+ [2]=>
+ string(1) "3"
+}
+int(7)
+array(2) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+}
+int(8)
+array(3) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+ [2]=>
+ string(0) ""
+}
+object(ArrayIterator)#%d (9) {
+ [0]=>
+ %s(1) "1"
+ [1]=>
+ %s(3) "1,2"
+ [2]=>
+ %s(5) "1,2,3"
+ [3]=>
+ %s(0) ""
+ [4]=>
+ NULL
+ [5]=>
+ array(0) {
+ }
+ [6]=>
+ %s(6) "FooBar"
+ [7]=>
+ %s(1) ","
+ [8]=>
+ %s(2) ",,"
+}
+===DONE===
diff --git a/ext/spl/tests/iterator_055.phpt b/ext/spl/tests/iterator_055.phpt
new file mode 100755
index 000000000..35a050c39
--- /dev/null
+++ b/ext/spl/tests/iterator_055.phpt
@@ -0,0 +1,61 @@
+--TEST--
+SPL: RegexIterator::SPLIT, USE_KEY
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyRegexIterator extends RegexIterator
+{
+ function show()
+ {
+ foreach($this as $k => $v)
+ {
+ var_dump($k);
+ var_dump($v);
+ }
+ }
+}
+
+$ar = new ArrayIterator(array('1'=>0,'1,2'=>1,'1,2,3'=>2,0=>3,'FooBar'=>4,','=>5,',,'=>6));
+$it = new MyRegexIterator($ar, '/(\d),(\d)/', RegexIterator::SPLIT, RegexIterator::USE_KEY);
+
+$it->show();
+
+var_dump($ar);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(3) "1,2"
+array(2) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(0) ""
+}
+string(5) "1,2,3"
+array(2) {
+ [0]=>
+ string(0) ""
+ [1]=>
+ string(2) ",3"
+}
+object(ArrayIterator)#%d (7) {
+ [1]=>
+ int(0)
+ ["1,2"]=>
+ int(1)
+ ["1,2,3"]=>
+ int(2)
+ [0]=>
+ int(3)
+ ["FooBar"]=>
+ int(4)
+ [","]=>
+ int(5)
+ [",,"]=>
+ int(6)
+}
+===DONE===
diff --git a/ext/spl/tests/spl_004.phpt b/ext/spl/tests/spl_004.phpt
new file mode 100755
index 000000000..60da28042
--- /dev/null
+++ b/ext/spl/tests/spl_004.phpt
@@ -0,0 +1,86 @@
+--TEST--
+SPL: iterator_apply()
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+function my_error_handler($errno, $errstr, $errfile, $errline) {
+ echo "Error: $errstr\n";
+}
+
+set_error_handler('my_error_handler');
+
+function test_arg($arg)
+{
+ if ($arg instanceof Iterator)
+ {
+ var_dump($arg->key());
+ var_dump($arg->current());
+ }
+ else
+ {
+ var_dump($arg);
+ }
+ return true;
+}
+
+function test()
+{
+ static $arg = 0;
+ var_dump($arg++);
+ return true;
+}
+
+$it = new RecursiveArrayIterator(array(1, array(21, 22), 3));
+
+var_dump(iterator_apply($it, 'test', NULL));
+
+echo "===ARGS===\n";
+var_dump(iterator_apply($it, 'test_arg', array($it)));
+
+echo "===RECURSIVE===\n";
+$it = new RecursiveIteratorIterator($it);
+var_dump(iterator_apply($it, 'test'));
+
+echo "===ERRORS===\n";
+var_dump(iterator_apply($it, 'test', 1));
+var_dump(iterator_apply($it, 'non_existing_functon'));
+var_dump(iterator_apply($it, 'non_existing_functon', NULL, 2));
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+int(0)
+int(1)
+int(2)
+int(3)
+===ARGS===
+int(0)
+int(1)
+int(1)
+array(2) {
+ [0]=>
+ int(21)
+ [1]=>
+ int(22)
+}
+int(2)
+int(3)
+int(3)
+===RECURSIVE===
+int(3)
+int(4)
+int(5)
+int(6)
+int(4)
+===ERRORS===
+Error: Argument 3 passed to iterator_apply() must be an array, integer given
+Error: iterator_apply() expects parameter 3 to be array, integer given
+NULL
+Error: iterator_apply() expects parameter 2 to be function,%sstring given
+NULL
+Error: iterator_apply() expects at most 3 parameters, 4 given
+NULL
+===DONE===
diff --git a/ext/spl/tests/spl_005.phpt b/ext/spl/tests/spl_005.phpt
new file mode 100755
index 000000000..bb297bb6b
--- /dev/null
+++ b/ext/spl/tests/spl_005.phpt
@@ -0,0 +1,23 @@
+--TEST--
+SPL: spl_object_hash()
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(spl_object_hash(new stdClass));
+var_dump(spl_object_hash(42));
+var_dump(spl_object_hash());
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+string(32) "%s"
+
+Warning: spl_object_hash() expects parameter 1 to be object, integer given in %sspl_005.php on line %d
+NULL
+
+Warning: spl_object_hash() expects exactly 1 parameter, 0 given in %sspl_005.php on line %d
+NULL
+===DONE===