diff options
| author | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:36:21 -0400 |
|---|---|---|
| committer | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:36:21 -0400 |
| commit | d29a4fd2dd3b5d4cf6e80b602544d7b71d794e76 (patch) | |
| tree | b38e2e5c6974b9a15f103e5cf884cba9fff90ef4 /ext/spl | |
| parent | a88a88d0986a4a32288c102cdbfebd78d7e91d99 (diff) | |
| download | php-upstream/5.2.0.tar.gz | |
Imported Upstream version 5.2.0upstream/5.2.0
Diffstat (limited to 'ext/spl')
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, ®ex, ®ex_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(®ex); + } + 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 Binary files differnew file mode 100755 index 000000000..9b894cd1c --- /dev/null +++ b/ext/spl/tests/iterator_049b.phpt 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=== |
