diff options
Diffstat (limited to 'ext/spl')
707 files changed, 56136 insertions, 0 deletions
diff --git a/ext/spl/CREDITS b/ext/spl/CREDITS new file mode 100755 index 0000000..b1bef82 --- /dev/null +++ b/ext/spl/CREDITS @@ -0,0 +1,2 @@ +SPL +Marcus Boerger, Etienne Kneuss diff --git a/ext/spl/README b/ext/spl/README new file mode 100755 index 0000000..b2aeb59 --- /dev/null +++ b/ext/spl/README @@ -0,0 +1,7 @@ +This is an extension that aims to implement some efficient data access +interfaces and classes. You'll find the classes documented using php +code in the file spl.php or in the corresponding .inc file in the examples +subdirectory. Based on the internal implementations or the files in the +examples subdirectory there are also some .php files to experiment with. + +For more information look at: http://php.net/~helly/php/ext/spl diff --git a/ext/spl/TODO b/ext/spl/TODO new file mode 100755 index 0000000..68b00da --- /dev/null +++ b/ext/spl/TODO @@ -0,0 +1,4 @@ +This is the ToDo of ext/spl: + +Implement the classes/interfaces from the .inc files in +directory examples.
\ No newline at end of file diff --git a/ext/spl/config.m4 b/ext/spl/config.m4 new file mode 100755 index 0000000..a0f0d1a --- /dev/null +++ b/ext/spl/config.m4 @@ -0,0 +1,27 @@ +dnl $Id$ +dnl config.m4 for extension SPL + + AC_MSG_CHECKING(whether zend_object_value is packed) + old_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$INCLUDES -I$abs_srcdir $CPPFLAGS" + AC_TRY_RUN([ +#include "Zend/zend_types.h" +int main(int argc, char **argv) { + return ((sizeof(zend_object_handle) + sizeof(zend_object_handlers*)) == sizeof(zend_object_value)) ? 0 : 1; +} + ], [ + ac_result=1 + AC_MSG_RESULT(yes) + ],[ + ac_result=0 + AC_MSG_RESULT(no) + ], [ + ac_result=0 + AC_MSG_RESULT(no) + ]) + 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_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c, no) + PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h]) + PHP_ADD_EXTENSION_DEP(spl, pcre, true) diff --git a/ext/spl/config.w32 b/ext/spl/config.w32 new file mode 100644 index 0000000..77cbd20 --- /dev/null +++ b/ext/spl/config.w32 @@ -0,0 +1,7 @@ +// $Id$ +// vim:ft=javascript + +EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c", false /*never shared */); +AC_DEFINE('HAVE_SPL', 1); +PHP_SPL="yes"; +PHP_INSTALL_HEADERS("ext/spl", "php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h"); diff --git a/ext/spl/doxygen.cfg b/ext/spl/doxygen.cfg new file mode 100755 index 0000000..4b71787 --- /dev/null +++ b/ext/spl/doxygen.cfg @@ -0,0 +1,217 @@ +# Doxyfile 1.3.9.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = SPL-StandardPHPLibrary +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = NO +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = YES +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = YES +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = spl.php \ + examples \ + internal +FILE_PATTERNS = *.inc \ + *.php +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = YES +CHM_FILE = ../spl.chm +HHC_LOCATION = hhc.exe +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 1 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = YES +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1200 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/ext/spl/examples/autoload.inc b/ext/spl/examples/autoload.inc new file mode 100644 index 0000000..5871e7d --- /dev/null +++ b/ext/spl/examples/autoload.inc @@ -0,0 +1,50 @@ +<?php + +/** @file autoload.inc + * @ingroup Examples + * @brief function __autoload + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** \internal + * Tries to load class $classname from directory $dir. + */ +function __load_class($classname, $dir) +{ + $file = $dir . '/' . $classname . '.inc'; + if (file_exists($file)) + { + require_once($file); + return true; + } + return false; +} + +/** + * @brief Class loader for SPL example classes + * @author Marcus Boerger + * @version 1.0 + * + * Loads classes automatically from include_path as given by ini or from + * current directory of script or include file. + */ +function __autoload($classname) { + $classname = strtolower($classname); + $inc = split(':', ini_get('include_path')); + $inc[] = '.'; + $inc[] = dirname($_SERVER['PATH_TRANSLATED']); + foreach($inc as $dir) + { + if (__load_class($classname, $dir)) + { + fprintf(STDERR, 'Loading class('.$classname.")\n"); + return; + } + } + fprintf(STDERR, 'Class not found ('.$classname.")\n"); +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/cachingrecursiveiterator.inc b/ext/spl/examples/cachingrecursiveiterator.inc new file mode 100644 index 0000000..4fa6b23 --- /dev/null +++ b/ext/spl/examples/cachingrecursiveiterator.inc @@ -0,0 +1,28 @@ +<?php + +/** @file cachingrecursiveiterator.inc + * @ingroup Examples + * @brief class CachingRecursiveIterator + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief Compatibility to PHP 5.0 + * @author Marcus Boerger + * @version 1.2 + * @deprecated + * + * Class RecursiveCachingIterator was named CachingRecursiveIterator until + * PHP 5.0.6. + * + * @see RecursiveCachingIterator + */ + +class CachingRecursiveIterator extends RecursiveCachingIterator +{ +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/callbackfilteriterator.inc b/ext/spl/examples/callbackfilteriterator.inc new file mode 100644 index 0000000..5175701 --- /dev/null +++ b/ext/spl/examples/callbackfilteriterator.inc @@ -0,0 +1,122 @@ +<?php + +/** @file callbackfilteriterator.inc + * @ingroup Examples + * @brief class CallbackFilterIterator + * @author Marcus Boerger + * @author Kevin McArthur + * @date 2006 - 2006 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief A non abstract FiletrIterator that uses a callback foreach element + * @author Marcus Boerger + * @author Kevin McArthur + * @version 1.0 + */ +class CallbackFilterIterator extends FilterIterator +{ + const USE_FALSE = 0; /**< mode: accept no elements, no callback */ + const USE_TRUE = 1; /**< mode: accept all elements, no callback */ + const USE_VALUE = 2; /**< mode: pass value to callback */ + const USE_KEY = 3; /**< mode: pass key to callback */ + const USE_BOTH = 4; /**< mode: pass value and key to callback */ + + const REPLACE = 0x00000001; /**< flag: pass key/value by reference */ + + private $callback; /**< callback to use */ + private $mode; /**< mode any of USE_VALUE, USE_KEY, USE_BOTH */ + private $flags; /**< flags (REPLACE) */ + private $key; /**< key value */ + private $current; /**< current value */ + + /** Construct a CallbackFilterIterator + * + * @param it inner iterator (iterator to filter) + * @param callback callback function + * @param mode any of USE_VALUE, USE_KEY, USE_BOTH + * @param flags any of 0, REPLACE + */ + public function __construct(Iterator $it, $callback, $mode = self::USE_VALUE, $flags = 0) + { + parent::__construct($it); + $this->callback = $callback; + $this->mode = $mode; + $this->flags = $flags; + } + + /** Call the filter callback + * @return result of filter callback + */ + public function accept() + { + $this->key = parent::key(); + $this->current = parent::current(); + + switch($this->mode) { + default: + case self::USE_FALSE; + return false; + case self::USE_TRUE: + return true; + case self::USE_VALUE: + if($this->flags & self::REPLACE) { + return (bool) call_user_func($this->callback, &$this->current); + } else { + return (bool) call_user_func($this->callback, $this->current); + } + case self::USE_KEY: + if($this->flags & self::REPLACE) { + return (bool) call_user_func($this->callback, &$this->key); + } else { + return (bool) call_user_func($this->callback, $this->key); + } + case SELF::USE_BOTH: + if($this->flags & self::REPLACE) { + return (bool) call_user_func($this->callback, &$this->key, &$this->current); + } else { + return (bool) call_user_func($this->callback, $this->key, $this->current); + } + } + } + + /** @return current key value */ + function key() + { + return $this->key; + } + + /** @return current value */ + function current() + { + return $this->current; + } + + /** @return operation mode */ + function getMode() + { + return $this->mode; + } + + /** @param $mode set new mode, @see mode */ + function setMode($mode) + { + $this->mode = $mode; + } + + /** @return operation flags */ + function getFlags() + { + return $this->flags; + } + + /** @param $flags set new flags, @see flags */ + function setFlags($flags) + { + $this->flags = $flags; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/class_tree.php b/ext/spl/examples/class_tree.php new file mode 100755 index 0000000..fc021d5 --- /dev/null +++ b/ext/spl/examples/class_tree.php @@ -0,0 +1,113 @@ +<?php + +/** @file class_tree.php + * @brief Class Tree example + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2008 + * @version 1.1 + * + * Usage: php class_tree.php \<class\> + * + * Simply specify the root class or interface to tree with parameter \<class\>. + */ + +if ($argc < 2) { + echo <<<EOF +Usage: php ${_SERVER['PHP_SELF']} <class> + +Displays a graphical tree for the given <class>. + +<class> The class or interface for which to generate the tree graph. + + +EOF; + exit(1); +} + +if (!class_exists("RecursiveTreeIterator", false)) require_once("recursivetreeiterator.inc"); + +/** \brief Collects sub classes for given class or interface + */ +class SubClasses extends RecursiveArrayIterator +{ + /** @param base base class to collect sub classes for + * @param check_interfaces whether we deal with interfaces + */ + function __construct($base, $check_interfaces = false) + { + foreach(get_declared_classes() as $cname) + { + $parent = get_parent_class($cname); + if (strcasecmp($parent, $base) == 0) + { + $this->offsetSet($cname, new SubClasses($cname)); + } + if ($check_interfaces) + { + if ($parent) + { + $parent_imp = class_implements($parent); + } + foreach(class_implements($cname) as $iname) + { + if (strcasecmp($iname, $base) == 0) + { + if (!$parent || !in_array($iname, $parent_imp)) + { + $this->offsetSet($cname, new SubClasses($cname)); + } + } + } + } + } + if ($check_interfaces) + { + foreach(get_declared_interfaces() as $cname) + { + foreach(class_implements($cname) as $iname) + { + if (strcasecmp($iname, $base) == 0) + { + $this->offsetSet($cname, new SubClasses($cname, true)); + } + } + } + } + $this->uksort('strnatcasecmp'); + } + + /** @return key() since that is the name we need + */ + function current() + { + $result = parent::key(); + $parent = get_parent_class($result); + if ($parent) + { + $interfaces = array_diff(class_implements($result), class_implements($parent)); + if ($interfaces) + { + $implements = array(); + foreach($interfaces as $interface) + { + $implements = array_merge($implements, class_implements($interface)); + } + $interfaces = array_diff($interfaces, $implements); + natcasesort($interfaces); + $result .= ' (' . join(', ', $interfaces) . ')'; + } + } + return $result; + } +} + +$it = new RecursiveTreeIterator(new SubClasses($argv[1], true)); + +echo $argv[1]."\n"; +foreach($it as $c=>$v) +{ + echo "$v\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/dba_array.php b/ext/spl/examples/dba_array.php new file mode 100755 index 0000000..346ac1f --- /dev/null +++ b/ext/spl/examples/dba_array.php @@ -0,0 +1,52 @@ +<?php + +/** @file dba_array.php + * @brief Program DBA array utility + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2005 + * + * Usage php dba_array.php \<file\> \<handler\> \<key\> [\<value\>] + * + * If \<value\> is specified then \<key\> is set to \<value\> in \<file\>. + * Else the value of \<key\> is printed only. + * + * Note: configure with --enable-dba + */ + +if ($argc < 4) { + echo <<<EOF +Usage: php ${_SERVER['PHP_SELF']} <file> <handler> <key> [<value>] + +If <value> is specified then <key> is set to <value> in <file>. +Else the value of <key> is printed only. + + +EOF; + exit(1); +} + +if (!class_exists("DbaReader", false)) require_once("dbareader.inc"); + +try { + if ($argc > 2) { + $dba = new DbaArray($argv[1], $argv[2]); + if ($dba && $argc > 3) { + if ($argc > 4) { + $dba[$argv[3]] = $argv[4]; + } + var_dump(array('Index' => $argv[3], 'Value' => $dba[$argv[3]])); + } + unset($dba); + } + else + { + echo "Not enough parameters\n"; + exit(1); + } +} +catch (exception $err) { + var_dump($err); + exit(1); +} +?>
\ No newline at end of file diff --git a/ext/spl/examples/dba_dump.php b/ext/spl/examples/dba_dump.php new file mode 100755 index 0000000..2c698d4 --- /dev/null +++ b/ext/spl/examples/dba_dump.php @@ -0,0 +1,42 @@ +<?php + +/** @file dba_dump.php + * @brief Program DBA dump utility + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2005 + * + * Usage: php dba_dump.php \<file\> \<handler\> [\<regex\>] + * + * Show all groups in the ini file specified by \<file\>. + * The regular expression \<regex\> is used to filter the by setting name. + * + * Note: configure with --enable-dba + */ + +if ($argc < 3) { + echo <<<EOF +Usage: php ${_SERVER['PHP_SELF']} <file> <handler> [<regex>] + +Show all groups in the ini file specified by <file>. +The regular expression <regex> is used to filter the by setting name. + + +EOF; + exit(1); +} + +if (!class_exists("DbaReader", false)) require_once("dbareader.inc"); +if (!class_exists("KeyFilter", false)) require_once("keyfilter.inc"); + +$db = new DbaReader($argv[1], $argv[2]); + +if ($argc>3) { + $db = new KeyFilter($db, $argv[3]); +} + +foreach($db as $key => $val) { + echo "'$key' => '$val'\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/dbaarray.inc b/ext/spl/examples/dbaarray.inc new file mode 100644 index 0000000..d448ad7 --- /dev/null +++ b/ext/spl/examples/dbaarray.inc @@ -0,0 +1,95 @@ +<?php + +/** @file dbaarray.inc + * @ingroup Examples + * @brief class DbaArray + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +if (!class_exists("DbaReader", false)) require_once("dbareader.inc"); + +/** @ingroup Examples + * @brief This implements a DBA Array + * @author Marcus Boerger + * @version 1.0 + */ +class DbaArray extends DbaReader implements ArrayAccess +{ + + /** + * Open database $file with $handler in read only mode. + * + * @param file Database file to open. + * @param handler Handler to use for database access. + */ + function __construct($file, $handler) + { + $this->db = dba_popen($file, "c", $handler); + if (!$this->db) { + throw new exception("Databse could not be opened"); + } + } + + /** + * Close database. + */ + function __destruct() + { + parent::__destruct(); + } + + /** + * Read an entry. + * + * @param $name key to read from + * @return value associated with $name + */ + function offsetGet($name) + { + $data = dba_fetch($name, $this->db); + if($data) { + //return unserialize($data); + return $data; + } + else + { + return NULL; + } + } + + /** + * Set an entry. + * + * @param $name key to write to + * @param $value value to write + */ + function offsetSet($name, $value) + { + //dba_replace($name, serialize($value), $this->db); + dba_replace($name, $value, $this->db); + return $value; + } + + /** + * @return whether key $name exists. + */ + function offsetExists($name) + { + return dba_exists($name, $this->db); + } + + /** + * Delete a key/value pair. + * + * @param $name key to delete. + */ + function offsetUnset($name) + { + return dba_delete($name, $this->db); + } +} + +?> diff --git a/ext/spl/examples/dbareader.inc b/ext/spl/examples/dbareader.inc new file mode 100644 index 0000000..b097912 --- /dev/null +++ b/ext/spl/examples/dbareader.inc @@ -0,0 +1,96 @@ +<?php + +/** @file dbareader.inc + * @ingroup Examples + * @brief class DbaReader + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief This implements a DBA Iterator. + * @author Marcus Boerger + * @version 1.0 + */ +class DbaReader implements Iterator +{ + + protected $db = NULL; + private $key = false; + private $val = false; + + /** + * Open database $file with $handler in read only mode. + * + * @param file Database file to open. + * @param handler Handler to use for database access. + */ + function __construct($file, $handler) { + if (!$this->db = dba_open($file, 'r', $handler)) { + throw new exception('Could not open file ' . $file); + } + } + + /** + * Close database. + */ + function __destruct() { + dba_close($this->db); + } + + /** + * Rewind to first element. + */ + function rewind() { + $this->key = dba_firstkey($this->db); + $this->fetch_data(); + } + + /** + * Move to next element. + * + * @return void + */ + function next() { + $this->key = dba_nextkey($this->db); + $this->fetch_data(); + } + + /** + * Fetches the current data if $key is valid + */ + private function fetch_data() { + if ($this->key !== false) { + $this->val = dba_fetch($this->key, $this->db); + } + } + + /** + * @return Current data. + */ + function current() { + return $this->val; + } + + /** + * @return Whether more elements are available. + */ + function valid() { + if ($this->db && $this->key !== false) { + return true; + } else { + return false; + } + } + + /** + * @return Current key. + */ + function key() { + return $this->key; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/directoryfilterdots.inc b/ext/spl/examples/directoryfilterdots.inc new file mode 100644 index 0000000..37f14b7 --- /dev/null +++ b/ext/spl/examples/directoryfilterdots.inc @@ -0,0 +1,45 @@ +<?php + +/** @file directoryfilterdots.inc + * @ingroup Examples + * @brief class DirectoryFilterDots + * @author Marcus Boerger + * @date 2003 - 2006 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief A filtered DirectoryIterator + * @author Marcus Boerger + * @version 1.2 + * + * This Iterator takes a pathname from which it creates a RecursiveDirectoryIterator + * and makes it recursive. Further more it filters the entries '.' and '..'. + */ +class DirectoryFilterDots extends RecursiveFilterIterator +{ + /** Construct from a path. + * @param $path directory to iterate + */ + function __construct($path) + { + parent::__construct(new RecursiveDirectoryIterator($path)); + } + + /** @return whether the current entry is neither '.' nor '..' + */ + function accept() + { + return !$this->getInnerIterator()->isDot(); + } + + /** @return the current entries path name + */ + function key() + { + return $this->getInnerIterator()->getPathname(); + } +} + +?> diff --git a/ext/spl/examples/directorygraphiterator.inc b/ext/spl/examples/directorygraphiterator.inc new file mode 100644 index 0000000..5808e3b --- /dev/null +++ b/ext/spl/examples/directorygraphiterator.inc @@ -0,0 +1,34 @@ +<?php + +/** @file directorygraphiterator.inc + * @ingroup Examples + * @brief class DirectoryGraphIterator + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief A tree iterator that only shows directories. + * @author Marcus Boerger + * @version 1.1 + */ +class DirectoryGraphIterator extends DirectoryTreeIterator +{ + function __construct($path) + { + RecursiveIteratorIterator::__construct( + new RecursiveCachingIterator( + new ParentIterator( + new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME + ) + ), + CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD + ), + parent::SELF_FIRST + ); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/directorytree.inc b/ext/spl/examples/directorytree.inc new file mode 100644 index 0000000..7bd9c2c --- /dev/null +++ b/ext/spl/examples/directorytree.inc @@ -0,0 +1,27 @@ +<?php + +/** @file directorytree.inc + * @ingroup Examples + * @brief class DirectoryTree + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief A directory iterator that does not show '.' and '..'. + * @author Marcus Boerger + * @version 1.0 + */ +class DirectoryTree extends RecursiveIteratorIterator +{ + /** Construct from a path. + * @param $path directory to iterate + */ + function __construct($path) { + parent::__construct(new DirectoryFilterDots($path)); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/directorytree.php b/ext/spl/examples/directorytree.php new file mode 100755 index 0000000..dc26d6c --- /dev/null +++ b/ext/spl/examples/directorytree.php @@ -0,0 +1,37 @@ +<?php + +/** @file directorytree.php + * @brief Program Directory tree example + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2005 + * + * Usage: php directorytree.php \<path\> [\<start\> [\<count\>]] + * + * Simply specify the path to tree with parameter \<path\>. + */ + +if ($argc < 2) { + echo <<<EOF +Usage: php ${_SERVER['PHP_SELF']} <path> + +Displays a graphical directory tree for the given <path>. + +<path> The directory for which to generate the directory tree graph. + + +EOF; + exit(1); +} + +if (!class_exists("DirectoryTreeIterator", false)) require_once("directorytreeiterator.inc"); + +$length = $argc > 3 ? $argv[3] : -1; + +echo $argv[1]."\n"; +foreach(new LimitIterator(new DirectoryTreeIterator($argv[1]), @$argv[2], $length) as $key=>$file) { +//foreach(new DirectoryTreeIterator($argv[1]) as $file) { + echo $file . "\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/directorytreeiterator.inc b/ext/spl/examples/directorytreeiterator.inc new file mode 100644 index 0000000..8e65d0d --- /dev/null +++ b/ext/spl/examples/directorytreeiterator.inc @@ -0,0 +1,54 @@ +<?php + +/** @file directorytreeiterator.inc + * @ingroup Examples + * @brief class DirectoryTreeIterator + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief DirectoryIterator to generate ASCII graphic directory trees + * @author Marcus Boerger + * @version 1.1 + */ +class DirectoryTreeIterator extends RecursiveIteratorIterator +{ + /** Construct from a path. + * @param $path directory to iterate + */ + function __construct($path) + { + parent::__construct( + new RecursiveCachingIterator( + new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_FILENAME + ), + CachingIterator::CALL_TOSTRING|CachingIterator::CATCH_GET_CHILD + ), + parent::SELF_FIRST + ); + } + + /** @return the current element prefixed with ASCII graphics + */ + function current() + { + $tree = ''; + for ($l=0; $l < $this->getDepth(); $l++) { + $tree .= $this->getSubIterator($l)->hasNext() ? '| ' : ' '; + } + return $tree . ($this->getSubIterator($l)->hasNext() ? '|-' : '\-') + . $this->getSubIterator($l)->__toString(); + } + + /** Aggregates the inner iterator + */ + function __call($func, $params) + { + return call_user_func_array(array($this->getSubIterator(), $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/dualiterator.inc b/ext/spl/examples/dualiterator.inc new file mode 100644 index 0000000..4cee203 --- /dev/null +++ b/ext/spl/examples/dualiterator.inc @@ -0,0 +1,210 @@ +<?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.3 + */ +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_0 = 0x00; + + const DEFAULT_FLAGS = 0x13; + + 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 = 0x13 /*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 key value depending on KEY_* flags + */ + function key() + { + switch($this->flags & 0xF0) + { + default: + case self::KEY_LHS: + return $this->lhs->key(); + case self::KEY_RHS: + return $this->rhs->key(); + case self::KEY_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); + $it = new RecursiveCompareDualIterator($it); + } + else + { + return false; + } + } + else + { + $it = new DualIterator($lhs, $rhs, self::CURRENT_0 | self::KEY_0); + } + + if ($identical) + { + foreach($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/findfile.inc b/ext/spl/examples/findfile.inc new file mode 100644 index 0000000..02ab792 --- /dev/null +++ b/ext/spl/examples/findfile.inc @@ -0,0 +1,65 @@ +<?php + +/** @file findfile.inc + * @ingroup Examples + * @brief class FindFile + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +if (!class_exists("FindFile", false)) require_once("findfile.inc"); +if (!class_exists("AppendIterator", false)) require_once("appenditerator.inc"); + +/** @ingroup Examples + * @brief Base class to find files + * @author Marcus Boerger + * @version 1.1 + * + */ +class FindFile extends FilterIterator +{ + /** @internal filename to find */ + private $file; + + /** Construct from path and filename + * + * @param $path the directory to search in + * If path contains ';' then this parameter is split and every + * part of it is used as separate directory. + * @param $file the name of the files to search fro + */ + function __construct($path, $file) + { + $this->file = $file; + $list = split(PATH_SEPARATOR, $path); + if (count($list) <= 1) { + parent::__construct(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path))); + } else { + $it = new AppendIterator(); + foreach($list as $path) { + $it->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path))); + } + parent::__construct($it); + } + } + + /** @return whether the current file matches the given filename + */ + function accept() + { + return !strcmp($this->current(), $this->file); + } + + /** @return the filename to search for. + * @note This may be overloaded and contain a regular expression for an + * extended class that uses regular expressions to search. + */ + function getSearch() + { + return $this->file; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/findfile.php b/ext/spl/examples/findfile.php new file mode 100755 index 0000000..60146cb --- /dev/null +++ b/ext/spl/examples/findfile.php @@ -0,0 +1,33 @@ +<?php + +/** @file findfile.php + * @brief Program Find a specific file by name. + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2005 + * + * Usage: php findfile.php \<path\> \<name\> + * + * \<path\> Path to search in. You can specify multiple paths by separating + * them with ';'. + * \<name\> Filename to look for. + */ + +if ($argc < 3) { + echo <<<EOF +Usage: php findfile.php <path> <name> + +Find a specific file by name. + +<path> Path to search in. +<name> Filename to look for. + + +EOF; + exit(1); +} + +if (!class_exists("FindFile", false)) require_once("findfile.inc"); + +foreach(new FindFile($argv[1], $argv[2]) as $file) echo $file->getPathname()."\n"; +?>
\ No newline at end of file diff --git a/ext/spl/examples/findregex.php b/ext/spl/examples/findregex.php new file mode 100755 index 0000000..b43ee0c --- /dev/null +++ b/ext/spl/examples/findregex.php @@ -0,0 +1,36 @@ +<?php + +/** @file findregex.php + * @brief Program Find a specific file by name. + * @ingroup Examples + * @author Marcus Boerger, Adam Trachtenberg + * @date 2004 + * + * Usage: php findregex.php \<path\> \<name\> + * + * \<path\> Path to search in. + * \<name\> Filename to look for. + */ + +if ($argc < 3) { + echo <<<EOF +Usage: php findregex.php <file> <name> + +Find a specific file by name. + +<path> Path to search in. +<name> Regex for filenames to look for. + + +EOF; + exit(1); +} + +if (!class_exists("RegexFindFile", false)) require_once("regexfindfile.inc"); + +foreach(new RegexFindFile($argv[1], $argv[2]) as $file) +{ + echo $file->getPathname()."\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/ini_groups.php b/ext/spl/examples/ini_groups.php new file mode 100755 index 0000000..5136911 --- /dev/null +++ b/ext/spl/examples/ini_groups.php @@ -0,0 +1,41 @@ +<?php + +/** @file ini_groups.php + * @brief Program List groups within an ini file + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2005 + * + * Usage: php dba_dump.php \<file\> [\<regex\>] + * + * Show all groups in the ini file specified by \<file\>. + * The regular expression \<regex\> is used to filter the result. + * + * Note: configure with --enable-dba + */ + +if ($argc < 2) { + echo <<<EOF +Usage: php dba_dump.php <file> [<regex>] + +Show all groups in the ini file specified by <file>. +The regular expression <regex> is used to filter the result. + + +EOF; + exit(1); +} + +if (!class_exists("KeyFilter", false)) require_once("keyfilter.inc"); +if (!class_exists("IniGroups", false)) require_once("inigroups.inc"); + +$it = new IniGroups($argv[1]); +if ($argc>2) { + $it = new KeyFilter($it, $argv[2]); +} + +foreach($it as $group) { + echo "$group\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/inigroups.inc b/ext/spl/examples/inigroups.inc new file mode 100644 index 0000000..62cfa3e --- /dev/null +++ b/ext/spl/examples/inigroups.inc @@ -0,0 +1,54 @@ +<?php + +/** @file inigroups.inc + * @ingroup Examples + * @brief class IniGroups + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +if (!class_exists("KeyFilter", false)) require_once("keyfilter.inc"); +if (!class_exists("DbaReader", false)) require_once("dbareader.inc"); + +/** @ingroup Examples + * @brief Class to iterate all groups within an ini file. + * @author Marcus Boerger + * @version 1.1 + * + * Using this class you can iterator over all groups of a ini file. + * + * This class uses a 'is-a' relation to KeyFilter in contrast to a 'has-a' + * relation. Doing so both current() and key() methods must be overwritten. + * If it would use a 'has-a' relation there would be much more to type... + * but for puritists that would allow correctness in so far as then no + * key() would be needed. + */ +class IniGroups extends KeyFilter +{ + /** + * Construct an ini file group iterator from a filename. + * + * @param file Ini file to open. + */ + function __construct($file) { + parent::__construct(new DbaReader($file, 'inifile'), '^\[.*\]$'); + } + + /** + * @return The current group. + */ + function current() { + return substr(parent::key(),1,-1); + } + + /** + * @return The current group. + */ + function key() { + return substr(parent::key(),1,-1); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/keyfilter.inc b/ext/spl/examples/keyfilter.inc new file mode 100644 index 0000000..eaf6b77 --- /dev/null +++ b/ext/spl/examples/keyfilter.inc @@ -0,0 +1,64 @@ +<?php + +/** @file keyfilter.inc + * @ingroup Examples + * @brief class KeyFilter + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief Regular expression filter for string iterators + * @author Marcus Boerger + * @version 1.1 + * + * Instances of this class act as a filter around iterators whose elements + * are strings. In other words you can put an iterator into the constructor + * and the instance will only return elements which match the given regular + * expression. + */ +class KeyFilter extends FilterIterator +{ + /** @internal regular exoression used as filter */ + private $regex; + + /** + * 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. + * + * @param it Object that implements at least spl_forward + * @param regex Regular expression used as a filter. + */ + function __construct(Iterator $it, $regex) + { + parent::__construct($it); + $this->regex = $regex; + } + + /** \return whether the current key mathes the regular expression + */ + function accept() + { + return ereg($this->regex, $this->getInnerIterator()->key()); + } + + /** @return regular expression used as filter + */ + function getRegex() + { + return $this->regex; + } + + /** + * hidden __clone + */ + protected function __clone() + { + // disallow clone + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/nocvsdir.php b/ext/spl/examples/nocvsdir.php new file mode 100755 index 0000000..6993268 --- /dev/null +++ b/ext/spl/examples/nocvsdir.php @@ -0,0 +1,55 @@ +<?php + +/** @file nocvsdir.php + * @brief Program Dir without CVS subdirs + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2006 + * @version 1.1 + * + * Usage: php nocvsdir.php \<path\> + * + * Simply specify the path to tree with parameter \<path\>. + */ + +if ($argc < 2) { + echo <<<EOF +Usage: php ${_SERVER['PHP_SELF']} <path> + +Show the directory and all it's contents without any CVS directory in <path>. + +<path> The directory for which to generate the directory. + + +EOF; + exit(1); +} + +if (!class_exists("RecursiveFilterIterator")) require_once("recursivefilteriterator.inc"); + +class NoCvsDirectory extends RecursiveFilterIterator +{ + function __construct($path) + { + parent::__construct(new RecursiveDirectoryIterator($path)); + } + + function accept() + { + return $this->getInnerIterator()->getFilename() != 'CVS'; + } + + function getChildren() + { + return new NoCvsDirectory($this->key()); + } +} + +$it = new RecursiveIteratorIterator(new NoCvsDirectory($argv[1])); + +foreach($it as $pathname => $file) +{ + echo $pathname."\n"; +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/phar_from_dir.php b/ext/spl/examples/phar_from_dir.php new file mode 100755 index 0000000..2ee15ca --- /dev/null +++ b/ext/spl/examples/phar_from_dir.php @@ -0,0 +1,50 @@ +<?php + +/** @file phar_from_dir.php + * @brief Create phar archive from directory + * @ingroup examples + * @author Marcus Boerger + * @date 2003 - 2007 + * @version 1.0 + * + * Usage: php phar_create_from_dir.php \<archive\> \<directory\> [\<regex\>] + * + * Create phar archive \<archive\> using entries from \<directory\> that + * optionally match \<regex\>. + */ + +if ($argc < 3) +{ + echo <<<EOF +php phar_from_dir.php archive directory [regex] + +Packs files in a given directory into a phar archive. + +archive name of the archive to create +directory input directory to pack +regex optional expression to match files in directory + +EOF; + exit(1); +} + +$phar = new Phar($argv[1], 0, 'newphar'); + +$dir = new RecursiveDirectoryIterator($argv[2]); +$dir = new RecursiveIteratorIterator($dir); +if ($argc > 3) +{ + $dir = new RegexIterator($dir, '/'.$argv[3].'/'); +} + +$phar->begin(); + +foreach($dir as $file) +{ + echo "$file\n"; + copy($file, "phar://newphar/$file"); +} + +$phar->commit(); + +?>
\ No newline at end of file diff --git a/ext/spl/examples/recursivecomparedualiterator.inc b/ext/spl/examples/recursivecomparedualiterator.inc new file mode 100644 index 0000000..75265c1 --- /dev/null +++ b/ext/spl/examples/recursivecomparedualiterator.inc @@ -0,0 +1,69 @@ +<?php + +/** @file recursivecomparedualiterator.inc + * @ingroup Examples + * @brief class DualIterator + * @author Marcus Boerger + * @date 2003 - 2006 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief Recursive comparison iterator for a RecursiveDualIterator + * @author Marcus Boerger + * @version 1.0 + */ +class RecursiveCompareDualIterator extends RecursiveIteratorIterator +{ + /** Used to keep end of recursion equality. That is en leaving a nesting + * level we need to check whether both child iterators are at their end. + */ + protected $equal = false; + + /** Construct from RecursiveDualIterator + * + * @param $it RecursiveDualIterator + * @param $mode should be LEAVES_ONLY + * @param $flags should be 0 + */ + function __construct(RecursiveDualIterator $it, $mode = self::LEAVES_ONLY, $flags = 0) + { + parent::__construct($it); + } + + /** Rewind iteration andcomparison process. Starting with $equal = true. + */ + function rewind() + { + $this->equal = true; + parent::rewind(); + } + + /** Calculate $equal + * @see $equal + */ + function endChildren() + { + $this->equal &= !$this->getInnerIterator()->getLHS()->valid() + && !$this->getInnerIterator()->getRHS()->valid(); + } + + /** @return whether both inner iterators are valid and have identical + * current and key values or both are non valid. + */ + function areIdentical() + { + return $this->equal && $this->getInnerIterator()->areIdentical(); + } + + /** @return whether both inner iterators are valid and have equal current + * and key values or both are non valid. + */ + function areEqual() + { + return $this->equal && $this->getInnerIterator()->areEqual(); + } +} + +?> diff --git a/ext/spl/examples/recursivedualiterator.inc b/ext/spl/examples/recursivedualiterator.inc new file mode 100644 index 0000000..cfa3bcc --- /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 RecursiveIterator instances + * + * @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/regexfindfile.inc b/ext/spl/examples/regexfindfile.inc new file mode 100644 index 0000000..d5dd722 --- /dev/null +++ b/ext/spl/examples/regexfindfile.inc @@ -0,0 +1,40 @@ +<?php + +/** @file regexfindfile.inc + * @ingroup Examples + * @brief class RegexFindFile + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief Find files by regular expression + * @author Marcus Boerger + * @version 1.1 + * + */ +class RegexFindFile extends FindFile +{ + /** Construct from path and regular expression + * + * @param $path the directory to search in + * If path contains ';' then this parameter is split and every + * part of it is used as separate directory. + * @param $regex perl style regular expression to find files with + */ + function __construct($path, $regex) + { + parent::__construct($path, $regex); + } + + /** @return whether the current filename matches the regular expression. + */ + function accept() + { + return preg_match($this->getSearch(), $this->current()); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/searchiterator.inc b/ext/spl/examples/searchiterator.inc new file mode 100644 index 0000000..944a4ac --- /dev/null +++ b/ext/spl/examples/searchiterator.inc @@ -0,0 +1,58 @@ +<?php + +/** @file searchiterator.inc + * @ingroup Examples + * @brief abstract class SearchIterator + * @author Marcus Boerger + * @date 2003 - 2005 + * + * SPL - Standard PHP Library + */ + +/** @ingroup Examples + * @brief Iterator to search for a specific element + * @author Marcus Boerger + * @version 1.0 + * + * This extended FilterIterator stops after finding the first acceptable + * value. + */ +abstract class SearchIterator extends FilterIterator +{ + /** @internal whether an entry was found already */ + private $done = false; + + /** Rewind and reset so that it once again searches. + * @return void + */ + function rewind() + { + parent::rewind(); + $this->done = false; + } + + /** @return whether the current element is valid + * which can only happen once per iteration. + */ + function valid() + { + return !$this->done && parent::valid(); + } + + /** Do not move forward but instead mark as finished. + * @return void + */ + function next() + { + $this->done = true; + } + + /** Aggregates the inner iterator + */ + function __call($func, $params) + { + return call_user_func_array(array($this->getInnerIterator(), $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/tests/dualiterator_001.phpt b/ext/spl/examples/tests/dualiterator_001.phpt new file mode 100644 index 0000000..53c1153 --- /dev/null +++ b/ext/spl/examples/tests/dualiterator_001.phpt @@ -0,0 +1,48 @@ +--TEST-- +SPL: DualIterator +--SKIPIF-- +<?php if (!extension_loaded("spl") || !extension_loaded("reflection")) 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=== +<?php exit(0); ?> +--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/examples/tests/examples.inc b/ext/spl/examples/tests/examples.inc new file mode 100644 index 0000000..feeba7d --- /dev/null +++ b/ext/spl/examples/tests/examples.inc @@ -0,0 +1,23 @@ +<?php + +class IncludeFiles extends ArrayIterator +{ + function __construct($path, $classes) + { + parent::__construct(); + foreach($classes as $c) + { + $this->append($path . '/' . strtolower($c) . '.inc'); + } + } +} + +$classes = array( +); + +foreach (new IncludeFiles(dirname(__FILE__). '/..', $classes) as $file) +{ + require_once($file); +} + +?>
\ No newline at end of file diff --git a/ext/spl/examples/tree.php b/ext/spl/examples/tree.php new file mode 100755 index 0000000..9c2cc55 --- /dev/null +++ b/ext/spl/examples/tree.php @@ -0,0 +1,40 @@ +<?php + +/** @file tree.php + * @brief Program Tree view example + * @ingroup Examples + * @author Marcus Boerger + * @date 2003 - 2005 + * + * Usage: php tree.php \<path\> + * + * Simply specify the path to tree with parameter \<path\>. + */ + +// The following line only operates on classes which are converted to c already. +// But does not generate a graphical output. +//foreach(new RecursiveIteratorIterator(new ParentIterator(new RecursiveDirectoryIterator($argv[1])), 1) as $file) { + +if ($argc < 2) { + echo <<<EOF +Usage: php ${_SERVER['PHP_SELF']} <path> + +Displays a graphical tree for the given <path>. + +<path> The directory for which to generate the tree graph. + + +EOF; + exit(1); +} + +if (!class_exists("DirectoryTreeIterator", false)) require_once("directorytreeiterator.inc"); +if (!class_exists("DirectoryGraphIterator", false)) require_once("directorygraphiterator.inc"); + +echo $argv[1]."\n"; +foreach(new DirectoryGraphIterator($argv[1]) as $file) +{ + echo $file . "\n"; +} + +?> diff --git a/ext/spl/internal/appenditerator.inc b/ext/spl/internal/appenditerator.inc new file mode 100644 index 0000000..28e32b1 --- /dev/null +++ b/ext/spl/internal/appenditerator.inc @@ -0,0 +1,122 @@ +<?php + +/** @file appenditerator.inc + * @ingroup SPL + * @brief class AppendIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Iterator that iterates over several iterators one after the other + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + */ +class AppendIterator implements OuterIterator +{ + /** @internal array of inner iterators */ + private $iterators; + + /** Construct an empty AppendIterator + */ + function __construct() + { + $this->iterators = new ArrayIterator(); + } + + /** Append an Iterator + * @param $it Iterator to append + * + * If the current state is invalid but the appended iterator is valid + * the AppendIterator itself becomes valid. However there will be no + * call to $it->rewind(). Also if the current state is invalid the inner + * ArrayIterator will be rewound und forwarded to the appended element. + */ + function append(Iterator $it) + { + $this->iterators->append($it); + } + + /** @return the current inner Iterator + */ + function getInnerIterator() + { + return $this->iterators->current(); + } + + /** Rewind to the first element of the first inner Iterator. + * @return void + */ + function rewind() + { + $this->iterators->rewind(); + if ($this->iterators->valid()) + { + $this->getInnerIterator()->rewind(); + } + } + + /** @return whether the current element is valid + */ + function valid() + { + return $this->iterators->valid() && $this->getInnerIterator()->valid(); + } + + /** @return the current value if it is valid or \c NULL + */ + function current() + { + /* Using $this->valid() would be exactly the same; it would omit + * the access to a non valid element in the inner iterator. Since + * the user didn't respect the valid() return value false this + * must be intended hence we go on. */ + return $this->iterators->valid() ? $this->getInnerIterator()->current() : NULL; + } + + /** @return the current key if it is valid or \c NULL + */ + function key() + { + return $this->iterators->valid() ? $this->getInnerIterator()->key() : NULL; + } + + /** Move to the next element. If this means to another Iterator that + * rewind that Iterator. + * @return void + */ + function next() + { + if (!$this->iterators->valid()) + { + return; /* done all */ + } + $this->getInnerIterator()->next(); + if ($this->getInnerIterator()->valid()) + { + return; /* found valid element in current inner iterator */ + } + $this->iterators->next(); + while ($this->iterators->valid()) + { + $this->getInnerIterator()->rewind(); + if ($this->getInnerIterator()->valid()) + { + return; /* found element as first elemet in another iterator */ + } + $this->iterators->next(); + } + } + + /** Aggregates the inner iterator + */ + function __call($func, $params) + { + return call_user_func_array(array($this->getInnerIterator(), $func), $params); + } +} + +?> diff --git a/ext/spl/internal/cachingiterator.inc b/ext/spl/internal/cachingiterator.inc new file mode 100644 index 0000000..33258ab --- /dev/null +++ b/ext/spl/internal/cachingiterator.inc @@ -0,0 +1,157 @@ +<?php + +/** @file cachingiterator.inc + * @ingroup SPL + * @brief class CachingIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Cached iteration over another Iterator + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.0 + * + * This iterator wrapper does a one ahead iteration. This way it knows whether + * the inner iterator has one more element. + * + * @note If you want to convert the elements into strings and the inner + * Iterator is an internal Iterator then you need to provide the + * flag CALL_TOSTRING to do the conversion when the actual element + * is being fetched. Otherwise the conversion would happen with the + * already changed iterator. If you do not need this then it you should + * omit this flag because it costs unneccessary work and time. + */ +class CachingIterator implements OuterIterator +{ + const CALL_TOSTRING = 0x00000001; + const CATCH_GET_CHILD = 0x00000002; + const TOSTRING_USE_KEY = 0x00000010; + const TOSTRING_USE_CURRENT = 0x00000020; + + private $it; + private $current; + private $key; + private $valid; + private $strValue; + + /** Construct from another iterator + * + * @param it Iterator to cache + * @param flags Bitmask: + * - CALL_TOSTRING (whether to call __toString() for every element) + */ + function __construct(Iterator $it, $flags = self::CALL_TOSTRING) + { + if ((($flags & self::CALL_TOSTRING) && ($flags & (self::TOSTRING_USE_KEY|self::TOSTRING_USE_CURRENT))) + || ((flags & (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT)) == (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT))) + { + throw new InvalidArgumentException('Flags must contain only one of CIT_CALL_TOSTRING, CIT_TOSTRING_USE_KEY, CIT_TOSTRING_USE_CURRENT'); + } + $this->it = $it; + $this->flags = $flags & (0x0000FFFF); + $this->next(); + } + + /** Rewind the Iterator + */ + function rewind() + { + $this->it->rewind(); + $this->next(); + } + + /** Forward to the next element + */ + function next() + { + if ($this->valid = $this->it->valid()) { + $this->current = $this->it->current(); + $this->key = $this->it->key(); + if ($this->flags & self::CALL_TOSTRING) { + if (is_object($this->current)) { + $this->strValue = $this->current->__toString(); + } else { + $this->strValue = (string)$this->current; + } + } + } else { + $this->current = NULL; + $this->key = NULL; + $this->strValue = NULL; + } + $this->it->next(); + } + + /** @return whether the iterator is valid + */ + function valid() + { + return $this->valid; + } + + /** @return whether there is one more element + */ + function hasNext() + { + return $this->it->valid(); + } + + /** @return the current element + */ + function current() + { + return $this->current; + } + + /** @return the current key + */ + function key() + { + return $this->key; + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->it, $func), $params); + } + + /** @return the string represenatation that was generated for the current + * element + * @throw exception when CALL_TOSTRING was not specified in constructor + */ + function __toString() + { + if ($this->flags & self::TOSTRING_USE_KEY) + { + return $this->key; + } + else if ($this->flags & self::TOSTRING_USE_CURRENT) + { + return $this->current; + } + if (!$this->flags & self::CALL_TOSTRING) + { + throw new exception('CachingIterator does not fetch string value (see CachingIterator::__construct)'); + } + return $this->strValue; + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } +} + +?> diff --git a/ext/spl/internal/emptyiterator.inc b/ext/spl/internal/emptyiterator.inc new file mode 100644 index 0000000..ac80e79 --- /dev/null +++ b/ext/spl/internal/emptyiterator.inc @@ -0,0 +1,62 @@ +<?php + +/** @file emptyiterator.inc + * @ingroup SPL + * @brief class EmptyIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief An empty Iterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + */ +class EmptyIterator implements Iterator +{ + /** No operation. + * @return void + */ + function rewind() + { + // nothing to do + } + + /** @return \c false + */ + function valid() + { + return false; + } + + /** This function must not be called. It throws an exception upon access. + * @throw Exception + * @return void + */ + function current() + { + throw new Exception('Accessing the value of an EmptyIterator'); + } + + /** This function must not be called. It throws an exception upon access. + * @throw Exception + * @return void + */ + function key() + { + throw new Exception('Accessing the key of an EmptyIterator'); + } + + /** No operation. + * @return void + */ + function next() + { + // nothing to do + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/filteriterator.inc b/ext/spl/internal/filteriterator.inc new file mode 100644 index 0000000..3330cc9 --- /dev/null +++ b/ext/spl/internal/filteriterator.inc @@ -0,0 +1,127 @@ +<?php + +/** @file filteriterator.inc + * @ingroup SPL + * @brief class FilterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Abstract filter for iterators + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.0 + * + * Instances of this class act as a filter around iterators. In other words + * you can put an iterator into the constructor and the instance will only + * return selected (accepted) elements. + * + * The only thing that needs to be done to make this work is implementing + * method accept(). Typically this invloves reading the current element or + * key of the inner Iterator and checking whether it is acceptable. + */ +abstract class FilterIterator implements OuterIterator +{ + private $it; + + /** + * Constructs a filter around another iterator. + * + * @param it Iterator to filter + */ + function __construct(Iterator $it) { + $this->it = $it; + } + + /** + * Rewind the inner iterator. + */ + function rewind() { + $this->it->rewind(); + $this->fetch(); + } + + /** + * Accept function to decide whether an element of the inner iterator + * should be accessible through the Filteriterator. + * + * @return whether or not to expose the current element of the inner + * iterator. + */ + abstract function accept(); + + /** + * Fetch next element and store it. + * + * @return void + */ + protected function fetch() { + while ($this->it->valid()) { + if ($this->accept()) { + return; + } + $this->it->next(); + }; + } + + /** + * Move to next element + * + * @return void + */ + function next() { + $this->it->next(); + $this->fetch(); + } + + /** + * @return Whether more elements are available + */ + function valid() { + return $this->it->valid(); + } + + /** + * @return The current key + */ + function key() { + return $this->it->key(); + } + + /** + * @return The current value + */ + function current() { + return $this->it->current(); + } + + /** + * hidden __clone + */ + protected function __clone() { + // disallow clone + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->it, $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/infiniteiterator.inc b/ext/spl/internal/infiniteiterator.inc new file mode 100644 index 0000000..04d7827 --- /dev/null +++ b/ext/spl/internal/infiniteiterator.inc @@ -0,0 +1,48 @@ +<?php + +/** @file infiniteiterator.inc + * @ingroup SPL + * @brief class InfiniteIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief An infinite Iterator + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1 + * + * This Iterator takes another Iterator and infinitvely iterates it by + * rewinding it when its end is reached. + * + * \note Even an InfiniteIterator stops if its inner Iterator is empty. + * + \verbatim + $it = new ArrayIterator(array(1,2,3)); + $infinite = new InfiniteIterator($it); + $limit = new LimitIterator($infinite, 0, 5); + foreach($limit as $val=>$key) + { + echo "$val=>$key\n"; + } + \endverbatim + */ +class InfiniteIterator extends IteratorIterator +{ + /** Move the inner Iterator forward to its next element or rewind it. + * @return void + */ + function next() + { + $this->getInnerIterator()->next(); + if (!$this->getInnerIterator()->valid()) + { + $this->getInnerIterator()->rewind(); + } + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/iteratoriterator.inc b/ext/spl/internal/iteratoriterator.inc new file mode 100644 index 0000000..37676e0 --- /dev/null +++ b/ext/spl/internal/iteratoriterator.inc @@ -0,0 +1,121 @@ +<?php + +/** @file iteratoriterator.inc + * @ingroup SPL + * @brief class IteratorIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Basic Iterator wrapper + * @since PHP 5.1 + * + * This iterator wrapper allows to convert anything that is traversable into + * an Iterator. It is very important to understand that most classes that do + * not implement Iterator have their reasone to. Most likely they do not allow + * the full Iterator feature set. If so you need to provide techniques to + * prevent missuse. If you do not you must expect exceptions or fatal erros. + * + * It is also possible to derive the class and implement IteratorAggregate by + * downcasting the instances returned in getIterator. See the following + * example (assuming BaseClass implements Traversable): + \code + class SomeClass extends BaseClass implements IteratorAggregate + { + function getIterator() + { + return new IteratorIterator($this, 'BaseClass'); + } + } + \endcode + * + * As you can see in the example this approach requires that the class to + * downcast to is actually a base class of the specified iterator to wrap. + * Omitting the downcast in the above example would result in an endless loop + * since IteratorIterator::__construct() would call SomeClass::getIterator(). + */ +class IteratorIterator implements OuterIterator +{ + /** Construct an IteratorIterator from an Iterator or an IteratorAggregate. + * + * @param iterator inner iterator + * @param classname optional class the iterator has to be downcasted to + */ + function __construct(Traversable $iterator, $classname = null) + { + if ($iterator instanceof IteratorAggregate) + { + $iterator = $iterator->getIterator(); + } + if ($iterator instanceof Iterator) + { + $this->iterator = $iterator; + } + else + { + throw new Exception("Classes that only implement Traversable can be wrapped only after converting class IteratorIterator into c code"); + } + } + + /** \return the inner iterator as passed to the constructor + */ + function getInnerIterator() + { + return $this->iterator; + } + + /** \return whether the iterator is valid + */ + function valid() + { + return $this->iterator->valid(); + } + + /** \return current key + */ + function key() + { + return $this->iterator->key(); + } + + /** \return current value + */ + function current() + { + return $this->iterator->current(); + } + + /** forward to next element + */ + function next() + { + return $this->iterator->next(); + } + + /** rewind to the first element + */ + function rewind() + { + return $this->iterator->rewind(); + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->iterator, $func), $params); + } + + /** The inner iterator must be private because when this class will be + * converted to c code it won't no longer be available. + */ + private $iterator; +} + +?> diff --git a/ext/spl/internal/limititerator.inc b/ext/spl/internal/limititerator.inc new file mode 100644 index 0000000..c5bddea --- /dev/null +++ b/ext/spl/internal/limititerator.inc @@ -0,0 +1,134 @@ +<?php + +/** @file limititerator.inc + * @ingroup SPL + * @brief class LimitIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Limited Iteration over another Iterator + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.0 + * + * A class that starts iteration at a certain offset and only iterates over + * a specified amount of elements. + * + * This class uses SeekableIterator::seek() if available and rewind() plus + * a skip loop otehrwise. + */ +class LimitIterator implements OuterIterator +{ + private $it; + private $offset; + private $count; + private $pos; + + /** Construct + * + * @param it Iterator to limit + * @param offset Offset to first element + * @param count Maximum number of elements to show or -1 for all + */ + function __construct(Iterator $it, $offset = 0, $count = -1) + { + if ($offset < 0) { + throw new exception('Parameter offset must be > 0'); + } + if ($count < 0 && $count != -1) { + throw new exception('Parameter count must either be -1 or a value greater than or equal to 0'); + } + $this->it = $it; + $this->offset = $offset; + $this->count = $count; + $this->pos = 0; + } + + /** Seek to specified position + * @param position offset to seek to (relative to beginning not offset + * specified in constructor). + * @throw exception when position is invalid + */ + function seek($position) { + if ($position < $this->offset) { + throw new exception('Cannot seek to '.$position.' which is below offset '.$this->offset); + } + if ($position > $this->offset + $this->count && $this->count != -1) { + throw new exception('Cannot seek to '.$position.' which is behind offset '.$this->offset.' plus count '.$this->count); + } + if ($this->it instanceof SeekableIterator) { + $this->it->seek($position); + $this->pos = $position; + } else { + while($this->pos < $position && $this->it->valid()) { + $this->next(); + } + } + } + + /** Rewind to offset specified in constructor + */ + function rewind() + { + $this->it->rewind(); + $this->pos = 0; + $this->seek($this->offset); + } + + /** @return whether iterator is valid + */ + function valid() { + return ($this->count == -1 || $this->pos < $this->offset + $this->count) + && $this->it->valid(); + } + + /** @return current key + */ + function key() { + return $this->it->key(); + } + + /** @return current element + */ + function current() { + return $this->it->current(); + } + + /** Forward to nect element + */ + function next() { + $this->it->next(); + $this->pos++; + } + + /** @return current position relative to zero (not to offset specified in + * constructor). + */ + function getPosition() { + return $this->pos; + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } + + /** Aggregate the inner iterator + * + * @param func Name of method to invoke + * @param params Array of parameters to pass to method + */ + function __call($func, $params) + { + return call_user_func_array(array($this->it, $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/multipleiterator.inc b/ext/spl/internal/multipleiterator.inc new file mode 100644 index 0000000..2ed71d5 --- /dev/null +++ b/ext/spl/internal/multipleiterator.inc @@ -0,0 +1,223 @@ +<?php +/** @file multipleiterator.inc + * @ingroup SPL + * @brief class MultipleIterator + * @author Johannes Schlueter + * @author Marcus Boerger + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Iterator that iterates over several iterators one after the other + * @author Johannes Schlueter + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.3 + */ +class MultipleIterator implements Iterator +{ + /** Inner Iterators */ + private $iterators; + + /** Flags: const MIT_* */ + private $flags; + + /** do not require all sub iterators to be valid in iteration */ + const MIT_NEED_ANY = 0; + + /** require all sub iterators to be valid in iteration */ + const MIT_NEED_ALL = 1; + + /** keys are created from sub iterators position */ + const MIT_KEYS_NUMERIC = 0; + + /** keys are created from sub iterators associated infromation */ + const MIT_KEYS_ASSOC = 2; + + /** Construct a new empty MultipleIterator + * @param flags MIT_* flags + */ + public function __construct($flags = self::MIT_NEED_ALL|self::MIT_KEYS_NUMERIC) + { + $this->iterators = new SplObjectStorage(); + $this->flags = $flags; + } + + /** @return current flags MIT_* */ + public function getFlags() + { + return $this->flags; + } + + /** @param $flags new flags. */ + public function setFlags($flags) + { + $this->flags = $flags; + } + + /** @param $iter new Iterator to attach. + * @param $inf associative info forIteraotr, must be NULL, integer or string + * + * @throws IllegalValueException if a inf is none of NULL, integer or string + * @throws IllegalValueException if a inf is already an associated info + */ + public function attachIterator(Iterator $iter, $inf = NULL) + { + + if (!is_null($inf)) + { + if (!is_int($inf) && !is_string($inf)) + { + throw new IllegalValueException('Inf must be NULL, integer or string'); + } + foreach($this->iterators as $iter) + { + if ($inf == $this->iterators->getInfo()) + { + throw new IllegalValueException('Key duplication error'); + } + } + } + $this->iterators->attach($iter, $inf); + } + + /** @param $iter attached Iterator that should be detached. */ + public function detachIterator(Iterator $iter) + { + $this->iterators->detach($iter); + } + + /** @param $iter Iterator to check + * @return whether $iter is attached or not + */ + public function containsIterator(Iterator $iter) + { + return $this->iterator->contains($iter); + } + + /** @return number of attached Iterator instances. */ + public function countIterators() + { + return $this->iterators->count(); + } + + /** Rewind all attached Iterator instances. */ + public function rewind() + { + foreach($this->iterators as $iter) + { + $iter->rewind(); + } + } + + /** + * @return whether all or one sub iterator is valid depending on flags. + * In mode MIT_NEED_ALL we expect all sub iterators to be valid and + * return flase on the first non valid one. If that flag is not set we + * return true on the first valid sub iterator found. If no Iterator + * is attached, we always return false. + */ + public function valid() + { + if (!sizeof($this->iterators)) { + return false; + } + // The following code is an optimized version that executes as few + // valid() calls as necessary and that only checks the flags once. + $expect = $this->flags & self::MIT_NEED_ALL ? true : false; + foreach($this->iterators as $iter) + { + if ($expect != $iter->valid()) + { + return !$expect; + } + } + return $expect; + } + + /** Move all attached Iterator instances forward. That is invoke + * their next() method regardless of their state. + */ + public function next() + { + foreach($this->iterators as $iter) + { + $iter->next(); + } + } + + /** @return false if no sub Iterator is attached and an array of + * all registered Iterator instances current() result. + * @throws RuntimeException if mode MIT_NEED_ALL is set and at least one + * attached Iterator is not valid(). + * @throws IllegalValueException if a key is NULL and MIT_KEYS_ASSOC is set. + */ + public function current() + { + if (!sizeof($this->iterators)) + { + return false; + } + $retval = array(); + foreach($this->iterators as $iter) + { + if ($it->valid()) + { + if ($this->flags & self::MIT_KEYS_ASSOC) + { + $key = $this->iterators->getInfo(); + if (is_null($key)) + { + throw new IllegalValueException('Sub-Iterator is associated with NULL'); + } + $retval[$key] = $iter->current(); + } + else + { + $retval[] = $iter->current(); + } + } + else if ($this->flags & self::MIT_NEED_ALL) + { + throw new RuntimeException('Called current() with non valid sub iterator'); + } + else + { + $retval[] = NULL; + } + } + return $retval; + } + + /** @return false if no sub Iterator is attached and an array of + * all registered Iterator instances key() result. + * @throws LogicException if mode MIT_NEED_ALL is set and at least one + * attached Iterator is not valid(). + */ + public function key() + { + if (!sizeof($this->iterators)) + { + return false; + } + $retval = array(); + foreach($this->iterators as $iter) + { + if ($it->valid()) + { + $retval[] = $iter->key(); + } + else if ($this->flags & self::MIT_NEED_ALL) + { + throw new LogicException('Called key() with non valid sub iterator'); + } + else + { + $retval[] = NULL; + } + } + return $retval; + } +} diff --git a/ext/spl/internal/norewinditerator.inc b/ext/spl/internal/norewinditerator.inc new file mode 100644 index 0000000..8747a61 --- /dev/null +++ b/ext/spl/internal/norewinditerator.inc @@ -0,0 +1,28 @@ +<?php + +/** @file norewinditerator.inc + * @ingroup SPL + * @brief class NoRewindIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief An Iterator wrapper that doesn't call rewind + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1 + */ +class NoRewindIterator extends IteratorIterator +{ + /** Simply prevent execution of inner iterators rewind(). + */ + function rewind() + { + // nothing to do + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/outeriterator.inc b/ext/spl/internal/outeriterator.inc new file mode 100644 index 0000000..f26d29d --- /dev/null +++ b/ext/spl/internal/outeriterator.inc @@ -0,0 +1,25 @@ +<?php + +/** @file outeriterator.inc + * @ingroup SPL + * @brief class OuterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Interface to access the current inner iteraor of iterator wrappers + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + */ +interface OuterIterator extends Iterator +{ + /** @return inner iterator + */ + function getInnerIterator(); +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/parentiterator.inc b/ext/spl/internal/parentiterator.inc new file mode 100644 index 0000000..cc377fc --- /dev/null +++ b/ext/spl/internal/parentiterator.inc @@ -0,0 +1,32 @@ +<?php + +/** @file parentiterator.inc + * @ingroup SPL + * @brief class FilterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Iterator to filter parents + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.1 + * + * This extended FilterIterator allows a recursive iteration using + * RecursiveIteratorIterator that only shows those elements which have + * children. + */ +class ParentIterator extends RecursiveFilterIterator +{ + /** @return whetehr the current element has children + */ + function accept() + { + return $this->it->hasChildren(); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivearrayiterator.inc b/ext/spl/internal/recursivearrayiterator.inc new file mode 100644 index 0000000..a9450e1 --- /dev/null +++ b/ext/spl/internal/recursivearrayiterator.inc @@ -0,0 +1,59 @@ +<?php + +/** @file recursivearrayiterator.inc + * @ingroup Examples + * @brief class RecursiveArrayIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief A recursive array iterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + * + * Passes the RecursiveIterator interface to the inner Iterator and provides + * the same functionality as FilterIterator. This allows you to skip parents + * and all their childs before loading them all. You need to care about + * function getChildren() because it may not always suit your needs. The + * builtin behavior uses reflection to return a new instance of the exact same + * class it is called from. That is you extend RecursiveFilterIterator and + * getChildren() will create instance of that class. The problem is that doing + * this does not transport any state or control information of your accept() + * implementation to the new instance. To overcome this problem you might + * need to overwrite getChildren(), call this implementation and pass the + * control vaules manually. + */ +class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator +{ + /** @return whether the current element has children + */ + function hasChildren() + { + return is_array($this->current()); + } + + /** @return an iterator for the current elements children + * + * @note the returned iterator will be of the same class as $this + */ + function getChildren() + { + if ($this->current() instanceof self) + { + return $this->current(); + } + if (empty($this->ref)) + { + $this->ref = new ReflectionClass($this); + } + return $this->ref->newInstance($this->current()); + } + + private $ref; +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivecachingiterator.inc b/ext/spl/internal/recursivecachingiterator.inc new file mode 100644 index 0000000..0676d43 --- /dev/null +++ b/ext/spl/internal/recursivecachingiterator.inc @@ -0,0 +1,99 @@ +<?php + +/** @file recursivecachingiterator.inc + * @ingroup SPL + * @brief class RecursiveCachingIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Cached recursive iteration over another Iterator + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.1 + * + * @see CachingIterator + */ +class RecursiveCachingIterator extends CachingIterator implements RecursiveIterator +{ + private $hasChildren; + private $getChildren; + + /** Construct from another iterator + * + * @param it Iterator to cache + * @param flags Bitmask: + * - CALL_TOSTRING (whether to call __toString() for every element) + * - CATCH_GET_CHILD (whether to catch exceptions when trying to get childs) + */ + function __construct(RecursiveIterator $it, $flags = self::CALL_TOSTRING) + { + parent::__construct($it, $flags); + } + + /** Rewind Iterator + */ + function rewind(); + { + $this->hasChildren = false; + $this->getChildren = NULL; + parent::rewind(); + } + + /** Forward to next element if necessary then an Iterator for the Children + * will be created. + */ + function next() + { + if ($this->hasChildren = $this->it->hasChildren()) + { + try + { + $child = $this->it->getChildren(); + if (!$this->ref) + { + $this->ref = new ReflectionClass($this); + } + $this->getChildren = $ref->newInstance($child, $this->flags); + } + catch(Exception $e) + { + if (!$this->flags & self::CATCH_GET_CHILD) + { + throw $e; + } + $this->hasChildren = false; + $this->getChildren = NULL; + } + } else + { + $this->getChildren = NULL; + } + parent::next(); + } + + private $ref; + + /** @return whether the current element has children + * @note The check whether the Iterator for the children can be created was + * already executed. Hence when flag CATCH_GET_CHILD was given in + * constructor this fucntion returns false so that getChildren does + * not try to access those children. + */ + function hasChildren() + { + return $this->hasChildren; + } + + /** @return An Iterator for the children + */ + function getChildren() + { + return $this->getChildren; + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursivefilteriterator.inc b/ext/spl/internal/recursivefilteriterator.inc new file mode 100644 index 0000000..b089919 --- /dev/null +++ b/ext/spl/internal/recursivefilteriterator.inc @@ -0,0 +1,62 @@ +<?php + +/** @file recursivefilteriterator.inc + * @ingroup SPL + * @brief class RecursiveFilterIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Iterator to filter recursive iterators + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.1 + * + * Passes the RecursiveIterator interface to the inner Iterator and provides + * the same functionality as FilterIterator. This allows you to skip parents + * and all their childs before loading them all. You need to care about + * function getChildren() because it may not always suit your needs. The + * builtin behavior uses reflection to return a new instance of the exact same + * class it is called from. That is you extend RecursiveFilterIterator and + * getChildren() will create instance of that class. The problem is that doing + * this does not transport any state or control information of your accept() + * implementation to the new instance. To overcome this problem you might + * need to overwrite getChildren(), call this implementation and pass the + * control vaules manually. + */ +abstract class RecursiveFilterIterator extends FilterIterator implements RecursiveIterator +{ + /** @param $it the RecursiveIterator to filter + */ + function __construct(RecursiveIterator $it) + { + parent::__construct($it); + } + + /** @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/recursiveiterator.inc b/ext/spl/internal/recursiveiterator.inc new file mode 100644 index 0000000..1eab3d6 --- /dev/null +++ b/ext/spl/internal/recursiveiterator.inc @@ -0,0 +1,30 @@ +<?php + +/** @file recursiveiterator.inc + * @ingroup SPL + * @brief class RecursiveIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Interface for recursive iteration with RecursiveIteratorIterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.0 + */ +interface RecursiveIterator extends Iterator +{ + /** @return whether the current element has children + */ + function hasChildren(); + + /** @return the sub iterator for the current element + * @note The returned object must implement RecursiveIterator. + */ + function getChildren(); +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursiveiteratoriterator.inc b/ext/spl/internal/recursiveiteratoriterator.inc new file mode 100644 index 0000000..35fa801 --- /dev/null +++ b/ext/spl/internal/recursiveiteratoriterator.inc @@ -0,0 +1,237 @@ +<?php + +/** @file recursiveiteratoriterator.inc + * @ingroup SPL + * @brief class RecursiveIteratorIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Iterates through recursive iterators + * @author Marcus Boerger + * @version 1.2 + * @since PHP 5.0 + * + * The objects of this class are created by instances of RecursiveIterator. + * Elements of those iterators may be traversable themselves. If so these + * sub elements are recursed into. + */ +class RecursiveIteratorIterator implements OuterIterator +{ + /** Mode: Only show leaves */ + const LEAVES_ONLY = 0; + /** Mode: Show parents prior to their children */ + const SELF_FIRST = 1; + /** Mode: Show all children prior to their parent */ + const CHILD_FIRST = 2; + + /** Flag: Catches exceptions during getChildren() calls and simply jumps + * to the next element. */ + const CATCH_GET_CHILD = 0x00000002; + + private $ait = array(); + private $count = 0; + private $mode = self::LEAVES_ONLY; + private $flags = 0; + + /** Construct from RecursiveIterator + * + * @param it RecursiveIterator to iterate + * @param mode Operation mode (one of): + * - LEAVES_ONLY only show leaves + * - SELF_FIRST show parents prior to their childs + * - CHILD_FIRST show all children prior to their parent + * @param flags Control flags, zero or any combination of the following + * (since PHP 5.1). + * - CATCH_GET_CHILD which catches exceptions during + * getChildren() calls and simply jumps to the next + * element. + */ + function __construct(RecursiveIterator $it, $mode = self::LEAVES_ONLY, $flags = 0) + { + $this->ait[0] = $it; + $this->mode = $mode; + $this->flags = $flags; + } + + /** Rewind to top iterator as set in constructor + */ + function rewind() + { + while ($this->count) { + unset($this->ait[$this->count--]); + $this->endChildren(); + } + $this->ait[0]->rewind(); + $this->ait[0]->recursed = false; + callNextElement(true); + } + + /** @return whether iterator is valid + */ + function valid() + { + $count = $this->count; + while ($count) { + $it = $this->ait[$count]; + if ($it->valid()) { + return true; + } + $count--; + $this->endChildren(); + } + return false; + } + + /** @return current key + */ + function key() + { + $it = $this->ait[$this->count]; + return $it->key(); + } + + /** @return current element + */ + function current() + { + $it = $this->ait[$this->count]; + return $it->current(); + } + + /** Forward to next element + */ + function next() + { + while ($this->count) { + $it = $this->ait[$this->count]; + if ($it->valid()) { + if (!$it->recursed && callHasChildren()) { + $it->recursed = true; + try + { + $sub = callGetChildren(); + } + catch (Exception $e) + { + if (!($this->flags & self::CATCH_GET_CHILD)) + { + throw $e; + } + $it->next(); + continue; + } + $sub->recursed = false; + $sub->rewind(); + if ($sub->valid()) { + $this->ait[++$this->count] = $sub; + if (!$sub instanceof RecursiveIterator) { + throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator'); + } + $this->beginChildren(); + return; + } + unset($sub); + } + $it->next(); + $it->recursed = false; + if ($it->valid()) { + return; + } + $it->recursed = false; + } + if ($this->count) { + unset($this->ait[$this->count--]); + $it = $this->ait[$this->count]; + $this->endChildren(); + callNextElement(false); + } + } + callNextElement(true); + } + + /** @return Sub Iterator at given level or if unspecified the current sub + * Iterator + */ + function getSubIterator($level = NULL) + { + if (is_null($level)) { + $level = $this->count; + } + return @$this->ait[$level]; + } + + /** + * @return The inner iterator + */ + function getInnerIterator() + { + return $this->it; + } + + /** @return Current Depth (Number of parents) + */ + function getDepth() + { + return $this->level; + } + + /** @return whether current sub iterators current element has children + * @since PHP 5.1 + */ + function callHasChildren() + { + return $this->ait[$this->count]->hasChildren(); + } + + /** @return current sub iterators current children + * @since PHP 5.1 + */ + function callGetChildren() + { + return $this->ait[$this->count]->getChildren(); + } + + /** Called right after calling getChildren() and its rewind(). + * @since PHP 5.1 + */ + function beginChildren() + { + } + + /** Called after current child iterator is invalid and right before it + * gets destructed. + * @since PHP 5.1 + */ + function endChildren() + { + } + + private function callNextElement($after_move) + { + if ($this->valid()) + { + if ($after_move) + { + if (($this->mode == self::SELF_FIRST && $this->callHasChildren()) + || $this->mode == self::LEAVES_ONLY) + $this->nextElement(); + } + else + { + $this->nextElement(); + } + } + } + + /** Called when the next element is available + */ + function nextElement() + { + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/recursiveregexiterator.inc b/ext/spl/internal/recursiveregexiterator.inc new file mode 100644 index 0000000..ffcff0c --- /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 - 2009 + * + * 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/recursivetreeiterator.inc b/ext/spl/internal/recursivetreeiterator.inc new file mode 100644 index 0000000..dfcdc05 --- /dev/null +++ b/ext/spl/internal/recursivetreeiterator.inc @@ -0,0 +1,132 @@ +<?php + +/** @file recursivetreeiterator.inc + * @ingroup SPL + * @brief class RecursiveTreeIterator + * @author Marcus Boerger, Johannes Schlueter + * @date 2005 - 2009 + * + * SPL - Standard PHP Library + */ + + +/** @ingroup SPL + * @brief RecursiveIteratorIterator to generate ASCII graphic trees for the + * entries in a RecursiveIterator + * @author Marcus Boerger, Johannes Schlueter + * @version 1.1 + * @since PHP 5.3 + */ +class RecursiveTreeIterator extends RecursiveIteratorIterator +{ + const BYPASS_CURRENT = 0x00000004; + const BYPASS_KEY = 0x00000008; + + private $rit_flags; + + /** + * @param it iterator to use as inner iterator + * @param rit_flags flags passed to RecursiveIteratoIterator (parent) + * @param cit_flags flags passed to RecursiveCachingIterator (for hasNext) + * @param mode mode passed to RecursiveIteratoIterator (parent) + */ + function __construct(RecursiveIterator $it, $rit_flags = self::BYPASS_KEY, $cit_flags = CachingIterator::CATCH_GET_CHILD, $mode = self::SELF_FIRST) + { + parent::__construct(new RecursiveCachingIterator($it, $cit_flags), $mode, $rit_flags); + $this->rit_flags = $rit_flags; + } + + private $prefix = array(0=>'', 1=>'| ', 2=>' ', 3=>'|-', 4=>'\-', 5=>''); + + /** Prefix used to start elements. */ + const PREFIX_LEFT = 0; + /** Prefix used if $level < depth and hasNext($level) == true. */ + const PREFIX_MID_HAS_NEXT = 1; + /** Prefix used if $level < depth and hasNext($level) == false. */ + const PREFIX_MID_LAST = 2; + /** Prefix used if $level == depth and hasNext($level) == true. */ + const PREFIX_END_HAS_NEXT = 3; + /** Prefix used if $level == depth and hasNext($level) == false. */ + const PREFIX_END_LAST = 4; + /** Prefix used right in front of the current element. */ + const PREFIX_RIGHT = 5; + + /** + * Set prefix part as used in getPrefix() and stored in $prefix. + * @param $part any PREFIX_* const. + * @param $value new prefix string for specified part. + * @throws OutOfRangeException if 0 > $part or $part > 5. + */ + function setPrefixPart($part, $value) + { + if (0 > $part || $part > 5) { + throw new OutOfRangeException(); + } + $this->prefix[$part] = (string)$value; + } + + /** @return string to place in front of current element + */ + function getPrefix() + { + $tree = ''; + for ($level = 0; $level < $this->getDepth(); $level++) + { + $tree .= $this->getSubIterator($level)->hasNext() ? $this->prefix[1] : $this->prefix[2]; + } + $tree .= $this->getSubIterator($level)->hasNext() ? $this->prefix[3] : $this->prefix[4]; + + return $this->prefix[0] . $tree . $this->prefix[5]; + } + + /** @return string presentation build for current element + */ + function getEntry() + { + return @(string)parent::current(); + } + + /** @return string to place after the current element + */ + function getPostfix() + { + return ''; + } + + /** @return the current element prefixed and postfixed + */ + function current() + { + if ($this->rit_flags & self::BYPASS_CURRENT) + { + return parent::current(); + } + else + { + return $this->getPrefix() . $this->getEntry() . $this->getPostfix(); + } + } + + /** @return the current key prefixed and postfixed + */ + function key() + { + if ($this->rit_flags & self::BYPASS_KEY) + { + return parent::key(); + } + else + { + return $this->getPrefix() . parent::key() . $this->getPostfix(); + } + } + + /** Aggregates the inner iterator + */ + function __call($func, $params) + { + return call_user_func_array(array($this->getSubIterator(), $func), $params); + } +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/regexiterator.inc b/ext/spl/internal/regexiterator.inc new file mode 100644 index 0000000..c6addb9 --- /dev/null +++ b/ext/spl/internal/regexiterator.inc @@ -0,0 +1,170 @@ +<?php + +/** @file regexiterator.inc + * @ingroup SPL + * @brief class RegexIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * 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 extends FilterIterator +{ + const USE_KEY = 0x00000001; /**< If present in $flags 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; + } + + /** @return current regular expression + */ + function getRegex() + { + return $this->regex; + } +} + +?> diff --git a/ext/spl/internal/seekableiterator.inc b/ext/spl/internal/seekableiterator.inc new file mode 100644 index 0000000..b4f66bd --- /dev/null +++ b/ext/spl/internal/seekableiterator.inc @@ -0,0 +1,48 @@ +<?php + +/** @file seekableiterator.inc + * @ingroup SPL + * @brief class SeekableIterator + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @brief seekable iterator + * @author Marcus Boerger + * @version 1.0 + * @since PHP 5.0 + * + * Turns a normal iterator ino a seekable iterator. When there is a way + * to seek on an iterator LimitIterator can use this to efficiently rewind + * to offset. + */ +interface SeekableIterator extends Iterator +{ + /** Seek to an absolute position + * + * \param $index position to seek to + * \return void + * + * The method should throw an exception if it is not possible to seek to + * the given position. Typically this exception should be of type + * OutOfBoundsException. + \code + function seek($index); + $this->rewind(); + $position = 0; + while($position < $index && $this->valid()) { + $this->next(); + $position++; + } + if (!$this->valid()) { + throw new OutOfBoundsException('Invalid seek position'); + } + } + \endcode + */ + function seek($index); +} + +?>
\ No newline at end of file diff --git a/ext/spl/internal/spldoublylinkedlist.inc b/ext/spl/internal/spldoublylinkedlist.inc new file mode 100644 index 0000000..e87e4b1 --- /dev/null +++ b/ext/spl/internal/spldoublylinkedlist.inc @@ -0,0 +1,277 @@ +<?php +/** @file spldoublylinkedlist.inc + * @ingroup SPL + * @brief class SplDoublyLinkedList + * @author Etienne Kneuss + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Doubly Linked List + * @since PHP 5.3 + * + * The SplDoublyLinkedList class provides the main functionalities of a + * doubly linked list (DLL). + * @note The following userland implementation of Iterator is a bit different + * from the internal one. Internally, iterators generated by nested + * foreachs are independent, while they share the same traverse pointer + * in userland. + */ +class SplDoublyLinkedList implements Iterator, ArrayAccess, Countable +{ + protected $_llist = array(); + protected $_it_mode = 0; + protected $_it_pos = 0; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_LIFO = 0x00000002; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_FIFO = 0x00000000; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_KEEP = 0x00000000; + + /** Iterator mode + * @see setIteratorMode + */ + const IT_MODE_DELETE = 0x00000001; + + /** @return the element popped from the end of the DLL. + * @throw RuntimeException If the datastructure is empty. + */ + public function pop() + { + if (count($this->_llist) == 0) { + throw new RuntimeException("Can't pop from an empty datastructure"); + } + return array_pop($this->_llist); + } + + /** @return the element shifted from the beginning of the DLL. + * @throw RuntimeException If the datastructure is empty. + */ + public function shift() + { + if (count($this->_llist) == 0) { + throw new RuntimeException("Can't shift from an empty datastructure"); + } + return array_shift($this->_llist); + } + + /** Pushes an element to the end of the DLL. + * @param $data variable to add to the DLL. + */ + public function push($data) + { + array_push($this->_llist, $data); + return true; + } + + /** Adds an element to the beginning of the DLL. + * @param $data variable to add to the DLL. + */ + public function unshift($data) + { + array_unshift($this->_llist, $data); + return true; + } + + /** @return the element at the beginning of the DLL. + */ + public function top() + { + return end($this->_llist); + } + + /** @return the element at the end of the DLL. + */ + public function bottom() + { + return reset($this->_llist); + } + + /** @return number elements in the DLL. + */ + public function count() + { + return count($this->_llist); + } + + /** @return whether the DLL is empty. + */ + public function isEmpty() + { + return ($this->count() == 0); + } + + /** Changes the iteration mode. There are two orthogonal sets of modes that + * can be set: + * - The direction of the iteration (either one or the other) + * - SplDoublyLnkedList::IT_MODE_LIFO (Stack style) + * - SplDoublyLnkedList::IT_MODE_FIFO (Queue style) + * + * - The behavior of the iterator (either one or the other) + * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator) + * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator) + * + * The default mode is 0 : SplDoublyLnkedList::IT_MODE_FIFO | SplDoublyLnkedList::IT_MODE_KEEP + * + * @param $mode new mode of iteration + */ + public function setIteratorMode($mode) + { + $this->_it_mode = $mode; + } + + /** @return the current iteration mode + * @see setIteratorMode + */ + public function getIteratorMode() + { + return $this->_it_mode; + } + + /** Rewind to top iterator as set in constructor + */ + public function rewind() + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + $this->_it_pos = count($this->_llist)-1; + } else { + $this->_it_pos = 0; + } + } + + /** @return whether iterator is valid + */ + public function valid() + { + return array_key_exists($this->_it_pos, $this->_llist); + } + + /** @return current key + */ + public function key() + { + return $this->_it_pos; + } + + /** @return current object + */ + public function current() + { + return $this->_llist[$this->_it_pos]; + } + + /** Forward to next element + */ + public function next() + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + if ($this->_it_mode & self::IT_MODE_DELETE) { + $this->pop(); + } + $this->_it_pos--; + } else { + if ($this->_it_mode & self::IT_MODE_DELETE) { + $this->shift(); + } else { + $this->_it_pos++; + } + } + } + + /** @return whether a certain offset exists in the DLL + * + * @param $offset The offset + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetExists($offset) + { + if (!is_numeric($offset)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + return array_key_exists($offset, $this->_llist); + } + } + + /** @return the data at a certain offset in the DLL + * + * @param $offset The offset + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetGet($offset) + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + $realOffset = count($this->_llist)-$offset; + } else { + $realOffset = $offset; + } + + if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + return $this->_llist[$realOffset]; + } + } + + /** Defines the data at a certain offset in the DLL + * + * @param $offset The offset + * @param $value New value + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetSet($offset, $value) + { + if ($offset === null) { + return $this->push($value); + } + + if ($this->_it_mode & self::IT_MODE_LIFO) { + $realOffset = count($this->_llist)-$offset; + } else { + $realOffset = $offset; + } + + if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + $this->_llist[$realOffset] = $value; + } + } + + /** Unsets the element at a certain offset in the DLL + * + * @param $offset The offset + * @throw OutOfRangeException If the offset is either invalid or out of + * range. + */ + public function offsetUnset($offset) + { + if ($this->_it_mode & self::IT_MODE_LIFO) { + $realOffset = count($this->_llist)-$offset; + } else { + $realOffset = $offset; + } + + if (!is_numeric($offset) || !array_key_exists($realOffset, $this->_llist)) { + throw new OutOfRangeException("Offset invalid or out of range"); + } else { + array_splice($this->_llist, $realOffset, 1); + } + } +} + +?> diff --git a/ext/spl/internal/splfileobject.inc b/ext/spl/internal/splfileobject.inc new file mode 100644 index 0000000..46b941f --- /dev/null +++ b/ext/spl/internal/splfileobject.inc @@ -0,0 +1,377 @@ +<?php + +/** @file splfileobject.inc + * @ingroup SPL + * @brief class FileObject + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Object representation for any stream + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1 + */ +class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator +{ + /** Flag: wheter to suppress new lines */ + const DROP_NEW_LINE = 0x00000001; + + private $fp; + private $fname; + private $line = NULL; + private $lnum = 0; + private $max_len = 0; + private $flags = 0; + private $delimiter= ','; + private $enclosure= '"'; + + /** + * Constructs a new file object + * + * @param $file_name The name of the stream to open + * @param $open_mode The file open mode + * @param $use_include_path Whether to search in include paths + * @param $context A stream context + * @throw RuntimeException If file cannot be opened (e.g. insufficient + * access rights). + */ + function __construct($file_name, $open_mode = 'r', $use_include_path = false, $context = NULL) + { + $this->fp = fopen($file_name, $open_mode, $use_include_path, $context); + if (!$this->fp) + { + throw new RuntimeException("Cannot open file $file_name"); + } + $this->fname = $file_name; + } + + /** + * @return whether the end of the stream is reached + */ + function eof() + { + return eof($this->fp); + } + + /** increase current line number + * @return next line from stream + */ + function fgets() + { + $this->freeLine(); + $this->lnum++; + $buf = fgets($this->fp, $this->max_len); + + return $buf; + } + + /** + * @param delimiter character used as field separator + * @param enclosure end of + * @return array containing read data + */ + 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 + */ + function flock($operation, &$wouldblock) + { + return flock($this->fp, $operation, $wouldblock); + } + + /** + * Flush current data + * @return success or failure + */ + function fflush() + { + return fflush($this->fp); + } + + /** + * @return current file position + */ + function ftell() + { + return ftell($this->fp); + } + + /** + * @param pos new file position + * @param whence seek method (SEEK_SET, SEEK_CUR, SEEK_END) + * @return Upon success, returns 0; otherwise, returns -1. Note that + * seeking past EOF is not considered an error. + */ + function fseek($pos, $whence = SEEK_SET) + { + return fseek($this->fp, $pos, $whence); + } + + /** + * @return next char from file + * @note a new line character does not increase $this->lnum + */ + function fgetc() + { + $this->freeLine(); + $c = fgetc($this->fp); + if ($c == '\n') { + $this->lnum++; + } + } + + /** Read and return remaining part of stream + * @return size of remaining part passed through + */ + function fpassthru() + { + return fpassthru($this->fp); + } + + /** Get a line from the file and strip HTML tags + * @param $allowable_tags tags to keep in the string + */ + function fgetss($allowable_tags = NULL) + { + return fgetss($this->fp, $allowable_tags); + } + + /** Scan the next line + * @param $format string specifying format to parse + */ + function fscanf($format /* , ... */) + { + $this->freeLine(); + $this->lnum++; + return fscanf($this->fp, $format /* , ... */); + } + + /** + * @param $str to write + * @param $length maximum line length to write + */ + function fwrite($str, $length = NULL) + { + return fwrite($this->fp, $length); + } + + /** + * @return array of file stat information + */ + function fstat() + { + return fstat($this->fp); + } + + /** + * @param $size new size to truncate file to + */ + function ftruncate($size) + { + return ftruncate($this->fp, $size); + } + + /** + * @param $flags new flag set + */ + function setFlags($flags) + { + $this->flags = $flags; + } + + /** + * @return current set of flags + */ + function getFlags() + { + return $this->flags; + } + + /** + * @param $max_len set the maximum line length read + */ + function setMaxLineLen($max_len) + { + $this->max_len = $max_len; + } + + /** + * @return current setting for max line + */ + function getMaxLineLen() + { + return $this->max_len; + } + + /** + * @return false + */ + function hasChildren() + { + return false; + } + + /** + * @return false + */ + function getChildren() + { + return NULL; + } + + /** + * Invalidate current line buffer and set line number to 0. + */ + function rewind() + { + $this->freeLine(); + $this->lnum = 0; + } + + /** + * @return whether more data can be read + */ + function valid() + { + return !$this->eof(); + } + + /** + * @note Fill current line buffer if not done yet. + * @return line buffer + */ + function current() + { + if (is_null($this->line)) + { + $this->line = getCurrentLine(); + } + return $this->line; + } + + /** + * @return line number + * @note fgetc() will increase the line number when reaing a new line char. + * This has the effect key() called on a read a new line will already + * return the increased line number. + * @note Line counting works as long as you only read the file and do not + * use fseek(). + */ + function key() + { + return $this->lnum; + } + + /** Invalidate current line buffer. + */ + function next() + { + $this->freeLine(); + } + + /** + * @return next line read from file and increase the line counter + */ + private function readLine() + { + if ($this->eof()) + { + $this->freeLine(); + throw new RuntimeException("Cannot read from file " . $this->fname); + } + if ($this->line) { + $this->lnum++; + } + $this->freeLine(); + $this->line = fgets($this->fp, $this->max_len); + return $this->line; + } + + /** + * Free the current line buffer and increment the line counter + */ + private function freeLine() + { + if ($this->line) { + $this->line = NULL; + } + } + + /* + * @note If you DO overload this function key() and current() will increment + * $this->lnum automatically. If not then function reaLine() will do + * that for you. + */ + function getCurrentLine() + { + $this->freeLine(); + if ($this->eof()) + { + throw new RuntimeException("Cannot read from file " . $this->fname); + } + $this->readLine(); + } + + /** + * @return current line + */ + function __toString() + { + return current(); + } + + /** + * @param $line_pos Seek to this line + */ + function seek($line_pos) + { + $this->rewind(); + while($this->lnum < $line_pos && !$this->eof()) + { + $this->getCurrentLine(); + } + } +} + +?> diff --git a/ext/spl/internal/splobjectstorage.inc b/ext/spl/internal/splobjectstorage.inc new file mode 100644 index 0000000..fa16406 --- /dev/null +++ b/ext/spl/internal/splobjectstorage.inc @@ -0,0 +1,188 @@ +<?php + +/** @file splobjectstorage.inc + * @ingroup SPL + * @brief class SplObjectStorage + * @author Marcus Boerger + * @date 2003 - 2009 + * + * SPL - Standard PHP Library + */ + +/** + * @brief Object storage + * @author Marcus Boerger + * @version 1.1 + * @since PHP 5.1.2 + * + * This container allows to store objects uniquly without the need to compare + * them one by one. This is only possible internally. The code represenation + * here therefore has a complexity of O(n) while the actual implementation has + * complexity O(1). + */ +class SplObjectStorage implements Iterator, Countable, ArrayAccess +{ + private $storage = array(); + private $index = 0; + + /** Rewind to top iterator as set in constructor + */ + function rewind() + { + rewind($this->storage); + } + + /** @return whether iterator is valid + */ + function valid() + { + return key($this->storage) !== false; + } + + /** @return current key + */ + function key() + { + return $this->index; + } + + /** @return current object + */ + function current() + { + $element = current($this->storage); + return $element ? $element[0] : NULL + } + + /** @return get current object's associated information + * @since 5.3.0 + */ + function getInfo() + { + $element = current($this->storage); + return $element ? $element[1] : NULL + } + + /** @return set current object's associated information + * @since 5.3.0 + */ + function setInfo($inf = NULL) + { + if ($this->valid()) { + $this->storage[$this->index][1] = $inf; + } + } + + /** Forward to next element + */ + function next() + { + next($this->storage); + $this->index++; + } + + /** @return number of objects in storage + */ + function count() + { + return count($this->storage); + } + + /** @param $obj object to look for + * @return whether $obj is contained in storage + */ + function contains($obj) + { + if (is_object($obj)) + { + foreach($this->storage as $element) + { + if ($object === $element[0]) + { + return true; + } + } + } + return false; + } + + /** @param $obj new object to attach to storage or object whose + * associative information is to be replaced + * @param $inf associative information stored along the object + */ + function attach($obj, $inf = NULL) + { + if (is_object($obj) && !$this->contains($obj)) + { + $this->storage[] = array($obj, $inf); + } + } + + /** @param $obj object to remove from storage + */ + function detach($obj) + { + if (is_object($obj)) + { + foreach($this->storage as $idx => $element) + { + if ($object === $element[0]) + { + unset($this->storage[$idx]); + $this->rewind(); + return; + } + } + } + } + + /** @param $obj new object to attach to storage or object whose + * associative information is to be replaced + * @param $inf associative information stored along the object + * @since 5.3.0 + */ + function offsetSet($obj, $inf) + { + $this->attach($obj, $inf); + } + + /** @param $obj Exising object to look for + * @return associative information stored with object + * @throw UnexpectedValueException if Object $obj is not contained in + * storage + * @since 5.3.0 + */ + function offsetGet($obj) + { + if (is_object($obj)) + { + foreach($this->storage as $idx => $element) + { + if ($object === $element[0]) + { + return $element[1]; + } + } + } + throw new UnexpectedValueException('Object not found'); + } + + /** @param $obj Exising object to look for + * @return associative information stored with object + * @since 5.3.0 + */ + function offsetUnset($obj) + { + $this->detach($obj); + } + + /** @param $obj object to look for + * @return whether $obj is contained in storage + */ + function offsetEsists($obj) + { + return $this->contains($obj); + } +} + +?> diff --git a/ext/spl/internal/splqueue.inc b/ext/spl/internal/splqueue.inc new file mode 100644 index 0000000..368a259 --- /dev/null +++ b/ext/spl/internal/splqueue.inc @@ -0,0 +1,71 @@ +<?php + +/** @file splqueue.inc + * @ingroup SPL + * @brief class SplQueue + * @author Etienne Kneuss + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Implementation of a Queue through a DoublyLinkedList. As SplQueue + * extends SplDoublyLinkedList, unshift() and pop() are still available + * even though they don't make much sense for a queue. For convenience, + * two aliases are available: + * - enqueue() is an alias of push() + * - dequeue() is an alias of shift() + * + * @since PHP 5.3 + * + * The SplQueue class provides the main functionalities of a + * queue implemented using a doubly linked list (DLL). + */ +class SplQueue extends SplDoublyLinkedList +{ + protected $_it_mode = parent::IT_MODE_FIFO; + + /** Changes the iteration mode. There are two orthogonal sets of modes that + * can be set: + * + * - The behavior of the iterator (either one or the other) + * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator) + * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator) + * + * The default mode is 0 : SplDoublyLnkedList::IT_MODE_LIFO | SplDoublyLnkedList::IT_MODE_KEEP + * + * @note The iteration's direction is not modifiable for queue instances + * @param $mode New mode of iteration + * @throw RuntimeException If the new mode affects the iteration's direction. + */ + public function setIteratorMode($mode) + { + if ($mode & parent::IT_MODE_LIFO === parent::IT_MODE_LIFO) { + throw new RuntimeException("Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen"); + } + + $this->_it_mode = $mode; + } + + /** @return the first element of the queue. + * @note dequeue is an alias of push() + * @see splDoublyLinkedList::push() + */ + public function dequeue() + { + return parent::shift(); + } + + /** Pushes an element at the end of the queue. + * @param $data variable to add to the queue. + * @note enqueue is an alias of shift() + * @see splDoublyLinkedList::shift() + */ + public function enqueue($data) + { + return parent::push($data); + } +} + +?> diff --git a/ext/spl/internal/splstack.inc b/ext/spl/internal/splstack.inc new file mode 100644 index 0000000..70b1443 --- /dev/null +++ b/ext/spl/internal/splstack.inc @@ -0,0 +1,48 @@ +<?php + +/** @file splstack.inc + * @ingroup SPL + * @brief class SplStack + * @author Etienne Kneuss + * @date 2008 - 2009 + * + * SPL - Standard PHP Library + */ + +/** @ingroup SPL + * @brief Implementation of a stack through a DoublyLinkedList. As SplStack + * extends SplDoublyLinkedList, shift() and unshift() are still available even + * though they don't make much sense for a stack. + * @since PHP 5.3 + * + * The SplStack class provides the main functionalities of a + * stack implemented using a doubly linked list (DLL). + */ +class SplStack extends SplDoublyLinkedList +{ + protected $_it_mode = parent::IT_MODE_LIFO; + + /** Changes the iteration mode. There are two orthogonal sets of modes that + * can be set: + * + * - The behavior of the iterator (either one or the other) + * - SplDoublyLnkedList::IT_MODE_DELETE (Elements are deleted by the iterator) + * - SplDoublyLnkedList::IT_MODE_KEEP (Elements are traversed by the iterator) + * + * The default mode is 0 : SplDoublyLnkedList::IT_MODE_LIFO | SplDoublyLnkedList::IT_MODE_KEEP + * + * @note The iteration's direction is not modifiable for stack instances + * @param $mode New mode of iteration + * @throw RuntimeException If the new mode affects the iteration's direction. + */ + public function setIteratorMode($mode) + { + if ($mode & parent::IT_MODE_LIFO !== parent::IT_MODE_LIFO) { + throw new RuntimeException("Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen"); + } + + $this->_it_mode = $mode; + } +} + +?> diff --git a/ext/spl/package.xml b/ext/spl/package.xml new file mode 100755 index 0000000..372aaec --- /dev/null +++ b/ext/spl/package.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE package SYSTEM "../pear/package.dtd"> +<package> + <name>SPL</name> + <summary>Standard PHP Library</summary> + <maintainers> + <maintainer> + <user>helly</user> + <name>Marcus Boerger</name> + <email>helly@php.net</email> + <role>lead</role> + </maintainer> + </maintainers> + <description> +SPL is a collection of interfaces and classes that are meant to solve +standard problems. + </description> + <license>PHP</license> + <release> + <state>stable</state> + <version>0.1-dev</version> + <date>TBA</date> + <filelist> + <file role="src" name="config.m4"/> + <file role="src" name="php_spl.c"/> + <file role="src" name="php_spl.h"/> + <file role="src" name="spl_array.c"/> + <file role="src" name="spl_array.h"/> + <file role="src" name="spl_directory.c"/> + <file role="src" name="spl_directory.h"/> + <file role="src" name="spl_engine.c"/> + <file role="src" name="spl_engine.h"/> + <file role="src" name="spl_functions.c"/> + <file role="src" name="spl_functions.h"/> + <file role="src" name="spl_iterators.c"/> + <file role="src" name="spl_iterators.h"/> + <file role="doc" name="CREDITS"/> + <file role="doc" name="README"/> + <file role="doc" name="TODO"/> + <file role="doc" name="spl.php"/> + <file role="test" name="tests/array_iterator.phpt"/> + <file role="test" name="tests/array_object.phpt"/> + <dir name="examples"> + <file role="doc" name="autoload.inc"/> + <file role="doc" name="cachingiterator.inc"/> + <file role="doc" name="cachingrecursiveiterator.inc"/> + <file role="doc" name="dba_array.php"/> + <file role="doc" name="dba_dump.php"/> + <file role="doc" name="dba_reader.inc"/> + <file role="doc" name="directoryfilterdots.inc"/> + <file role="doc" name="directorygraphiterator.inc"/> + <file role="doc" name="directorytree.inc"/> + <file role="doc" name="directorytree.php"/> + <file role="doc" name="directorytreeiterator.inc"/> + <file role="doc" name="findfile.php"/> + <file role="doc" name="filteriterator.inc"/> + <file role="doc" name="ini_groups.php"/> + <file role="doc" name="key_filter.inc"/> + <file role="doc" name="limititerator.inc"/> + <file role="doc" name="parentiterator.inc"/> + <file role="doc" name="recursiveiterator.inc"/> + <file role="doc" name="recursiveiteratoriterator.inc"/> + <file role="doc" name="searchiterator.inc"/> + <file role="doc" name="seekableiterator.inc"/> + <file role="doc" name="tree.php"/> + </dir> + </filelist> + <deps> + <dep type="php" rel="ge" version="5"/> + </deps> + </release> +</package> +<!-- +vim:et:ts=1:sw=1 +--> diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c new file mode 100644 index 0000000..35f4e50 --- /dev/null +++ b/ext/spl/php_spl.c @@ -0,0 +1,1001 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_main.h" +#include "ext/standard/info.h" +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_array.h" +#include "spl_directory.h" +#include "spl_iterators.h" +#include "spl_exceptions.h" +#include "spl_observer.h" +#include "spl_dllist.h" +#include "spl_fixedarray.h" +#include "spl_heap.h" +#include "zend_exceptions.h" +#include "zend_interfaces.h" +#include "ext/standard/php_rand.h" +#include "ext/standard/php_lcg.h" +#include "main/snprintf.h" + +#ifdef COMPILE_DL_SPL +ZEND_GET_MODULE(spl) +#endif + +ZEND_DECLARE_MODULE_GLOBALS(spl) + +#define SPL_DEFAULT_FILE_EXTENSIONS ".inc,.php" + +/* {{{ PHP_GINIT_FUNCTION + */ +static PHP_GINIT_FUNCTION(spl) +{ + spl_globals->autoload_extensions = NULL; + spl_globals->autoload_extensions_len = 0; + spl_globals->autoload_functions = NULL; + spl_globals->autoload_running = 0; +} +/* }}} */ + +static zend_class_entry * spl_find_ce_by_name(char *name, int len, zend_bool autoload TSRMLS_DC) +{ + zend_class_entry **ce; + int found; + + if (!autoload) { + char *lc_name; + ALLOCA_FLAG(use_heap) + + lc_name = do_alloca(len + 1, use_heap); + zend_str_tolower_copy(lc_name, name, len); + + found = zend_hash_find(EG(class_table), lc_name, len +1, (void **) &ce); + free_alloca(lc_name, use_heap); + } else { + found = zend_lookup_class(name, len, &ce TSRMLS_CC); + } + if (found != SUCCESS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s does not exist%s", name, autoload ? " and could not be loaded" : ""); + return NULL; + } + + return *ce; +} + +/* {{{ proto array class_parents(object instance [, boolean autoload = true]) + Return an array containing the names of all parent classes */ +PHP_FUNCTION(class_parents) +{ + zval *obj; + zend_class_entry *parent_class, *ce; + zend_bool autoload = 1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) { + RETURN_FALSE; + } + + if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected"); + RETURN_FALSE; + } + + if (Z_TYPE_P(obj) == IS_STRING) { + if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) { + RETURN_FALSE; + } + } else { + ce = Z_OBJCE_P(obj); + } + + array_init(return_value); + parent_class = ce->parent; + while (parent_class) { + spl_add_class_name(return_value, parent_class, 0, 0 TSRMLS_CC); + parent_class = parent_class->parent; + } +} +/* }}} */ + +/* {{{ proto array class_implements(mixed what [, bool autoload ]) + Return all classes and interfaces implemented by SPL */ +PHP_FUNCTION(class_implements) +{ + zval *obj; + zend_bool autoload = 1; + zend_class_entry *ce; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) { + RETURN_FALSE; + } + if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected"); + RETURN_FALSE; + } + + if (Z_TYPE_P(obj) == IS_STRING) { + if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) { + RETURN_FALSE; + } + } else { + ce = Z_OBJCE_P(obj); + } + + array_init(return_value); + spl_add_interfaces(return_value, ce, 1, ZEND_ACC_INTERFACE TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto array class_uses(mixed what [, bool autoload ]) + Return all traits used by a class. */ +PHP_FUNCTION(class_uses) +{ + zval *obj; + zend_bool autoload = 1; + zend_class_entry *ce; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &obj, &autoload) == FAILURE) { + RETURN_FALSE; + } + if (Z_TYPE_P(obj) != IS_OBJECT && Z_TYPE_P(obj) != IS_STRING) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "object or string expected"); + RETURN_FALSE; + } + + if (Z_TYPE_P(obj) == IS_STRING) { + if (NULL == (ce = spl_find_ce_by_name(Z_STRVAL_P(obj), Z_STRLEN_P(obj), autoload TSRMLS_CC))) { + RETURN_FALSE; + } + } else { + ce = Z_OBJCE_P(obj); + } + + array_init(return_value); + spl_add_traits(return_value, ce, 1, ZEND_ACC_TRAIT TSRMLS_CC); +} +/* }}} */ + +#define SPL_ADD_CLASS(class_name, z_list, sub, allow, ce_flags) \ + spl_add_classes(spl_ce_ ## class_name, z_list, sub, allow, ce_flags TSRMLS_CC) + +#define SPL_LIST_CLASSES(z_list, sub, allow, ce_flags) \ + SPL_ADD_CLASS(AppendIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(ArrayIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(ArrayObject, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(BadFunctionCallException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(BadMethodCallException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(CachingIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(CallbackFilterIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(Countable, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(DirectoryIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(DomainException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(EmptyIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(FilesystemIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(FilterIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(GlobIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(InfiniteIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(InvalidArgumentException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(IteratorIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(LengthException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(LimitIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(LogicException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(MultipleIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(NoRewindIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(OuterIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(OutOfBoundsException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(OutOfRangeException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(OverflowException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(ParentIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RangeException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RecursiveArrayIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RecursiveCachingIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RecursiveCallbackFilterIterator, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(RecursiveDirectoryIterator, z_list, sub, allow, ce_flags); \ + 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(RecursiveTreeIterator, 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(SplDoublyLinkedList, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplFileInfo, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplFileObject, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplFixedArray, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplHeap, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplMinHeap, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplMaxHeap, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplObjectStorage, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplObserver, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplPriorityQueue, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplQueue, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplStack, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplSubject, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \ + SPL_ADD_CLASS(UnexpectedValueException, z_list, sub, allow, ce_flags); \ + +/* {{{ proto array spl_classes() + Return an array containing the names of all clsses and interfaces defined in SPL */ +PHP_FUNCTION(spl_classes) +{ + array_init(return_value); + + SPL_LIST_CLASSES(return_value, 0, 0, 0) +} +/* }}} */ + +static int spl_autoload(const char *class_name, const char * lc_name, int class_name_len, const char * file_extension TSRMLS_DC) /* {{{ */ +{ + char *class_file; + int class_file_len; + int dummy = 1; + zend_file_handle file_handle; + zend_op_array *new_op_array; + zval *result = NULL; + int ret; + + class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension); + +#if DEFAULT_SLASH != '\\' + { + char *ptr = class_file; + char *end = ptr + class_file_len; + + while ((ptr = memchr(ptr, '\\', (end - ptr))) != NULL) { + *ptr = DEFAULT_SLASH; + } + } +#endif + + ret = php_stream_open_for_zend_ex(class_file, &file_handle, USE_PATH|STREAM_OPEN_FOR_INCLUDE TSRMLS_CC); + + if (ret == SUCCESS) { + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(class_file, class_file_len); + } + if (zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) { + new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC); + zend_destroy_file_handle(&file_handle TSRMLS_CC); + } else { + new_op_array = NULL; + zend_file_handle_dtor(&file_handle TSRMLS_CC); + } + if (new_op_array) { + EG(return_value_ptr_ptr) = &result; + EG(active_op_array) = new_op_array; + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + } + + zend_execute(new_op_array TSRMLS_CC); + + destroy_op_array(new_op_array TSRMLS_CC); + efree(new_op_array); + if (!EG(exception)) { + if (EG(return_value_ptr_ptr)) { + zval_ptr_dtor(EG(return_value_ptr_ptr)); + } + } + + efree(class_file); + return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1); + } + } + efree(class_file); + return 0; +} /* }}} */ + +/* {{{ proto void spl_autoload(string class_name [, string file_extensions]) + Default implementation for __autoload() */ +PHP_FUNCTION(spl_autoload) +{ + char *class_name, *lc_name, *file_exts = SPL_G(autoload_extensions); + int class_name_len, file_exts_len = SPL_G(autoload_extensions_len), found = 0; + char *copy, *pos1, *pos2; + zval **original_return_value = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + zend_op_array *original_active_op_array = EG(active_op_array); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &class_name, &class_name_len, &file_exts, &file_exts_len) == FAILURE) { + RETURN_FALSE; + } + + if (file_exts == NULL) { /* autoload_extensions is not intialzed, set to defaults */ + copy = pos1 = estrndup(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS)-1); + } else { + copy = pos1 = estrndup(file_exts, file_exts_len); + } + lc_name = zend_str_tolower_dup(class_name, class_name_len); + while(pos1 && *pos1 && !EG(exception)) { + EG(return_value_ptr_ptr) = original_return_value; + EG(opline_ptr) = original_opline_ptr; + EG(active_op_array) = original_active_op_array; + pos2 = strchr(pos1, ','); + if (pos2) *pos2 = '\0'; + if (spl_autoload(class_name, lc_name, class_name_len, pos1 TSRMLS_CC)) { + found = 1; + break; /* loaded */ + } + pos1 = pos2 ? pos2 + 1 : NULL; + } + efree(lc_name); + if (copy) { + efree(copy); + } + + EG(return_value_ptr_ptr) = original_return_value; + EG(opline_ptr) = original_opline_ptr; + EG(active_op_array) = original_active_op_array; + + if (!found && !SPL_G(autoload_running)) { + /* For internal errors, we generate E_ERROR, for direct calls an exception is thrown. + * The "scope" is determined by an opcode, if it is ZEND_FETCH_CLASS we know function was called indirectly by + * the Zend engine. + */ + if (active_opline->opcode != ZEND_FETCH_CLASS) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Class %s could not be loaded", class_name); + } else { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s could not be loaded", class_name); + } + } +} /* }}} */ + +/* {{{ proto string spl_autoload_extensions([string file_extensions]) + Register and return default file extensions for spl_autoload */ +PHP_FUNCTION(spl_autoload_extensions) +{ + char *file_exts = NULL; + int file_exts_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &file_exts, &file_exts_len) == FAILURE) { + return; + } + if (file_exts) { + if (SPL_G(autoload_extensions)) { + efree(SPL_G(autoload_extensions)); + } + SPL_G(autoload_extensions) = estrndup(file_exts, file_exts_len); + SPL_G(autoload_extensions_len) = file_exts_len; + } + + if (SPL_G(autoload_extensions) == NULL) { + RETURN_STRINGL(SPL_DEFAULT_FILE_EXTENSIONS, sizeof(SPL_DEFAULT_FILE_EXTENSIONS) - 1, 1); + } else { + RETURN_STRINGL(SPL_G(autoload_extensions), SPL_G(autoload_extensions_len), 1); + } +} /* }}} */ + +typedef struct { + zend_function *func_ptr; + zval *obj; + zval *closure; + zend_class_entry *ce; +} autoload_func_info; + +static void autoload_func_info_dtor(autoload_func_info *alfi) +{ + if (alfi->obj) { + zval_ptr_dtor(&alfi->obj); + } + if (alfi->closure) { + zval_ptr_dtor(&alfi->closure); + } +} + +/* {{{ proto void spl_autoload_call(string class_name) + Try all registerd autoload function to load the requested class */ +PHP_FUNCTION(spl_autoload_call) +{ + zval *class_name, *retval = NULL; + int class_name_len; + char *func_name, *lc_name; + uint func_name_len; + ulong dummy; + HashPosition function_pos; + autoload_func_info *alfi; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE || Z_TYPE_P(class_name) != IS_STRING) { + return; + } + + if (SPL_G(autoload_functions)) { + int l_autoload_running = SPL_G(autoload_running); + SPL_G(autoload_running) = 1; + class_name_len = Z_STRLEN_P(class_name); + lc_name = zend_str_tolower_dup(Z_STRVAL_P(class_name), class_name_len); + zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos); + while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) { + zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &func_name_len, &dummy, 0, &function_pos); + zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos); + zend_call_method(alfi->obj ? &alfi->obj : NULL, alfi->ce, &alfi->func_ptr, func_name, func_name_len, &retval, 1, class_name, NULL TSRMLS_CC); + zend_exception_save(TSRMLS_C); + if (retval) { + zval_ptr_dtor(&retval); + retval = NULL; + } + if (zend_hash_exists(EG(class_table), lc_name, class_name_len + 1)) { + break; + } + zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos); + } + zend_exception_restore(TSRMLS_C); + efree(lc_name); + SPL_G(autoload_running) = l_autoload_running; + } else { + /* do not use or overwrite &EG(autoload_func) here */ + zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload", NULL, class_name); + } +} /* }}} */ + +#define HT_MOVE_TAIL_TO_HEAD(ht) \ + (ht)->pListTail->pListNext = (ht)->pListHead; \ + (ht)->pListHead = (ht)->pListTail; \ + (ht)->pListTail = (ht)->pListHead->pListLast; \ + (ht)->pListHead->pListNext->pListLast = (ht)->pListHead;\ + (ht)->pListTail->pListNext = NULL; \ + (ht)->pListHead->pListLast = NULL; + +/* {{{ proto bool spl_autoload_register([mixed autoload_function = "spl_autoload" [, throw = true [, prepend]]]) + Register given function as __autoload() implementation */ +PHP_FUNCTION(spl_autoload_register) +{ + char *func_name, *error = NULL; + int func_name_len; + char *lc_name = NULL; + zval *zcallable = NULL; + zend_bool do_throw = 1; + zend_bool prepend = 0; + zend_function *spl_func_ptr; + autoload_func_info alfi; + zval *obj_ptr; + zend_fcall_info_cache fcc; + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|zbb", &zcallable, &do_throw, &prepend) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS()) { + if (Z_TYPE_P(zcallable) == IS_STRING) { + if (Z_STRLEN_P(zcallable) == sizeof("spl_autoload_call") - 1) { + if (!zend_binary_strcasecmp(Z_STRVAL_P(zcallable), sizeof("spl_autoload_call"), "spl_autoload_call", sizeof("spl_autoload_call"))) { + if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function spl_autoload_call() cannot be registered"); + } + RETURN_FALSE; + } + } + } + + if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_STRICT, &func_name, &func_name_len, &fcc, &error TSRMLS_CC)) { + alfi.ce = fcc.calling_scope; + alfi.func_ptr = fcc.function_handler; + obj_ptr = fcc.object_ptr; + if (Z_TYPE_P(zcallable) == IS_ARRAY) { + if (!obj_ptr && alfi.func_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) { + if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array specifies a non static method but no object (%s)", error); + } + if (error) { + efree(error); + } + efree(func_name); + RETURN_FALSE; + } + else if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Passed array does not specify %s %smethod (%s)", alfi.func_ptr ? "a callable" : "an existing", !obj_ptr ? "static " : "", error); + } + if (error) { + efree(error); + } + efree(func_name); + RETURN_FALSE; + } else if (Z_TYPE_P(zcallable) == IS_STRING) { + if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Function '%s' not %s (%s)", func_name, alfi.func_ptr ? "callable" : "found", error); + } + if (error) { + efree(error); + } + efree(func_name); + RETURN_FALSE; + } else { + if (do_throw) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Illegal value passed (%s)", error); + } + if (error) { + efree(error); + } + efree(func_name); + RETURN_FALSE; + } + } + alfi.closure = NULL; + alfi.ce = fcc.calling_scope; + alfi.func_ptr = fcc.function_handler; + obj_ptr = fcc.object_ptr; + if (error) { + efree(error); + } + + lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1); + zend_str_tolower_copy(lc_name, func_name, func_name_len); + efree(func_name); + + if (Z_TYPE_P(zcallable) == IS_OBJECT) { + alfi.closure = zcallable; + Z_ADDREF_P(zcallable); + + lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); + memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable), + sizeof(zend_object_handle)); + func_name_len += sizeof(zend_object_handle); + lc_name[func_name_len] = '\0'; + } + + if (SPL_G(autoload_functions) && zend_hash_exists(SPL_G(autoload_functions), (char*)lc_name, func_name_len+1)) { + if (alfi.closure) { + Z_DELREF_P(zcallable); + } + goto skip; + } + + if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) { + /* add object id to the hash to ensure uniqueness, for more reference look at bug #40091 */ + lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); + memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle)); + func_name_len += sizeof(zend_object_handle); + lc_name[func_name_len] = '\0'; + alfi.obj = obj_ptr; + Z_ADDREF_P(alfi.obj); + } else { + alfi.obj = NULL; + } + + if (!SPL_G(autoload_functions)) { + ALLOC_HASHTABLE(SPL_G(autoload_functions)); + zend_hash_init(SPL_G(autoload_functions), 1, NULL, (dtor_func_t) autoload_func_info_dtor, 0); + } + + zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr); + + if (EG(autoload_func) == spl_func_ptr) { /* registered already, so we insert that first */ + autoload_func_info spl_alfi; + + spl_alfi.func_ptr = spl_func_ptr; + spl_alfi.obj = NULL; + spl_alfi.ce = NULL; + spl_alfi.closure = NULL; + zend_hash_add(SPL_G(autoload_functions), "spl_autoload", sizeof("spl_autoload"), &spl_alfi, sizeof(autoload_func_info), NULL); + if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) { + /* Move the newly created element to the head of the hashtable */ + HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions)); + } + } + + if (zend_hash_add(SPL_G(autoload_functions), lc_name, func_name_len+1, &alfi.func_ptr, sizeof(autoload_func_info), NULL) == FAILURE) { + if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) { + Z_DELREF_P(alfi.obj); + } + if (alfi.closure) { + Z_DELREF_P(alfi.closure); + } + } + if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) { + /* Move the newly created element to the head of the hashtable */ + HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions)); + } +skip: + efree(lc_name); + } + + if (SPL_G(autoload_functions)) { + zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &EG(autoload_func)); + } else { + zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &EG(autoload_func)); + } + RETURN_TRUE; +} /* }}} */ + +/* {{{ proto bool spl_autoload_unregister(mixed autoload_function) + Unregister given function as __autoload() implementation */ +PHP_FUNCTION(spl_autoload_unregister) +{ + char *func_name, *error = NULL; + int func_name_len; + char *lc_name = NULL; + zval *zcallable; + int success = FAILURE; + zend_function *spl_func_ptr; + zval *obj_ptr; + zend_fcall_info_cache fcc; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zcallable) == FAILURE) { + return; + } + + if (!zend_is_callable_ex(zcallable, NULL, IS_CALLABLE_CHECK_SYNTAX_ONLY, &func_name, &func_name_len, &fcc, &error TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Unable to unregister invalid function (%s)", error); + if (error) { + efree(error); + } + if (func_name) { + efree(func_name); + } + RETURN_FALSE; + } + obj_ptr = fcc.object_ptr; + if (error) { + efree(error); + } + + lc_name = safe_emalloc(func_name_len, 1, sizeof(long) + 1); + zend_str_tolower_copy(lc_name, func_name, func_name_len); + efree(func_name); + + if (Z_TYPE_P(zcallable) == IS_OBJECT) { + lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); + memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(zcallable), + sizeof(zend_object_handle)); + func_name_len += sizeof(zend_object_handle); + lc_name[func_name_len] = '\0'; + } + + if (SPL_G(autoload_functions)) { + if (func_name_len == sizeof("spl_autoload_call")-1 && !strcmp(lc_name, "spl_autoload_call")) { + /* remove all */ + zend_hash_destroy(SPL_G(autoload_functions)); + FREE_HASHTABLE(SPL_G(autoload_functions)); + SPL_G(autoload_functions) = NULL; + EG(autoload_func) = NULL; + success = SUCCESS; + } else { + /* remove specific */ + success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1); + if (success != SUCCESS && obj_ptr) { + lc_name = erealloc(lc_name, func_name_len + 2 + sizeof(zend_object_handle)); + memcpy(lc_name + func_name_len, &Z_OBJ_HANDLE_P(obj_ptr), sizeof(zend_object_handle)); + func_name_len += sizeof(zend_object_handle); + lc_name[func_name_len] = '\0'; + success = zend_hash_del(SPL_G(autoload_functions), lc_name, func_name_len+1); + } + } + } else if (func_name_len == sizeof("spl_autoload")-1 && !strcmp(lc_name, "spl_autoload")) { + /* register single spl_autoload() */ + zend_hash_find(EG(function_table), "spl_autoload", sizeof("spl_autoload"), (void **) &spl_func_ptr); + + if (EG(autoload_func) == spl_func_ptr) { + success = SUCCESS; + EG(autoload_func) = NULL; + } + } + + efree(lc_name); + RETURN_BOOL(success == SUCCESS); +} /* }}} */ + +/* {{{ proto false|array spl_autoload_functions() + Return all registered __autoload() functionns */ +PHP_FUNCTION(spl_autoload_functions) +{ + zend_function *fptr; + HashPosition function_pos; + autoload_func_info *alfi; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (!EG(autoload_func)) { + if (zend_hash_find(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME), (void **) &fptr) == SUCCESS) { + array_init(return_value); + add_next_index_stringl(return_value, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 1); + return; + } + RETURN_FALSE; + } + + zend_hash_find(EG(function_table), "spl_autoload_call", sizeof("spl_autoload_call"), (void **) &fptr); + + if (EG(autoload_func) == fptr) { + array_init(return_value); + zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &function_pos); + while(zend_hash_has_more_elements_ex(SPL_G(autoload_functions), &function_pos) == SUCCESS) { + zend_hash_get_current_data_ex(SPL_G(autoload_functions), (void **) &alfi, &function_pos); + if (alfi->closure) { + Z_ADDREF_P(alfi->closure); + add_next_index_zval(return_value, alfi->closure); + } else if (alfi->func_ptr->common.scope) { + zval *tmp; + MAKE_STD_ZVAL(tmp); + array_init(tmp); + + if (alfi->obj) { + Z_ADDREF_P(alfi->obj); + add_next_index_zval(tmp, alfi->obj); + } else { + add_next_index_string(tmp, alfi->ce->name, 1); + } + add_next_index_string(tmp, alfi->func_ptr->common.function_name, 1); + add_next_index_zval(return_value, tmp); + } else + add_next_index_string(return_value, alfi->func_ptr->common.function_name, 1); + + zend_hash_move_forward_ex(SPL_G(autoload_functions), &function_pos); + } + return; + } + + array_init(return_value); + 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; + char* hash; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + hash = emalloc(33); + php_spl_object_hash(obj, hash TSRMLS_CC); + + RETVAL_STRING(hash, 0); +} +/* }}} */ + +PHPAPI void php_spl_object_hash(zval *obj, char *result TSRMLS_DC) /* {{{*/ +{ + intptr_t hash_handle, hash_handlers; + char *hex; + + if (!SPL_G(hash_mask_init)) { + if (!BG(mt_rand_is_seeded)) { + php_mt_srand(GENERATE_SEED() TSRMLS_CC); + } + + SPL_G(hash_mask_handle) = (intptr_t)(php_mt_rand(TSRMLS_C) >> 1); + SPL_G(hash_mask_handlers) = (intptr_t)(php_mt_rand(TSRMLS_C) >> 1); + SPL_G(hash_mask_init) = 1; + } + + hash_handle = SPL_G(hash_mask_handle)^(intptr_t)Z_OBJ_HANDLE_P(obj); + hash_handlers = SPL_G(hash_mask_handlers)^(intptr_t)Z_OBJ_HT_P(obj); + + spprintf(&hex, 32, "%016x%016x", hash_handle, hash_handlers); + + strlcpy(result, hex, 33); + efree(hex); +} +/* }}} */ + +int spl_build_class_list_string(zval **entry, char **list TSRMLS_DC) /* {{{ */ +{ + char *res; + + spprintf(&res, 0, "%s, %s", *list, Z_STRVAL_PP(entry)); + efree(*list); + *list = res; + return ZEND_HASH_APPLY_KEEP; +} /* }}} */ + +/* {{{ PHP_MINFO(spl) + */ +PHP_MINFO_FUNCTION(spl) +{ + zval list; + char *strg; + + php_info_print_table_start(); + php_info_print_table_header(2, "SPL support", "enabled"); + + INIT_PZVAL(&list); + array_init(&list); + SPL_LIST_CLASSES(&list, 0, 1, ZEND_ACC_INTERFACE) + strg = estrdup(""); + zend_hash_apply_with_argument(Z_ARRVAL_P(&list), (apply_func_arg_t)spl_build_class_list_string, &strg TSRMLS_CC); + zval_dtor(&list); + php_info_print_table_row(2, "Interfaces", strg + 2); + efree(strg); + + INIT_PZVAL(&list); + array_init(&list); + SPL_LIST_CLASSES(&list, 0, -1, ZEND_ACC_INTERFACE) + strg = estrdup(""); + zend_hash_apply_with_argument(Z_ARRVAL_P(&list), (apply_func_arg_t)spl_build_class_list_string, &strg TSRMLS_CC); + zval_dtor(&list); + php_info_print_table_row(2, "Classes", strg + 2); + efree(strg); + + php_info_print_table_end(); +} +/* }}} */ + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_iterator_to_array, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) + ZEND_ARG_INFO(0, use_keys) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_iterator, 0) + ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) +ZEND_END_ARG_INFO(); + +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(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_parents, 0, 0, 1) + ZEND_ARG_INFO(0, instance) + ZEND_ARG_INFO(0, autoload) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_implements, 0, 0, 1) + ZEND_ARG_INFO(0, what) + ZEND_ARG_INFO(0, autoload) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_uses, 0, 0, 1) + ZEND_ARG_INFO(0, what) + ZEND_ARG_INFO(0, autoload) +ZEND_END_ARG_INFO() + + +ZEND_BEGIN_ARG_INFO(arginfo_spl_classes, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_spl_autoload_functions, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload, 0, 0, 1) + ZEND_ARG_INFO(0, class_name) + ZEND_ARG_INFO(0, file_extensions) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_extensions, 0, 0, 0) + ZEND_ARG_INFO(0, file_extensions) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_call, 0, 0, 1) + ZEND_ARG_INFO(0, class_name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_register, 0, 0, 0) + ZEND_ARG_INFO(0, autoload_function) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_autoload_unregister, 0, 0, 1) + ZEND_ARG_INFO(0, autoload_function) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_object_hash, 0, 0, 1) + ZEND_ARG_INFO(0, obj) +ZEND_END_ARG_INFO() +/* }}} */ + +/* {{{ spl_functions + */ +const zend_function_entry spl_functions[] = { + PHP_FE(spl_classes, arginfo_spl_classes) + PHP_FE(spl_autoload, arginfo_spl_autoload) + PHP_FE(spl_autoload_extensions, arginfo_spl_autoload_extensions) + PHP_FE(spl_autoload_register, arginfo_spl_autoload_register) + PHP_FE(spl_autoload_unregister, arginfo_spl_autoload_unregister) + PHP_FE(spl_autoload_functions, arginfo_spl_autoload_functions) + PHP_FE(spl_autoload_call, arginfo_spl_autoload_call) + PHP_FE(class_parents, arginfo_class_parents) + PHP_FE(class_implements, arginfo_class_implements) + PHP_FE(class_uses, arginfo_class_uses) + PHP_FE(spl_object_hash, arginfo_spl_object_hash) +#ifdef SPL_ITERATORS_H + PHP_FE(iterator_to_array, arginfo_iterator_to_array) + PHP_FE(iterator_count, arginfo_iterator) + PHP_FE(iterator_apply, arginfo_iterator_apply) +#endif /* SPL_ITERATORS_H */ + PHP_FE_END +}; +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION(spl) + */ +PHP_MINIT_FUNCTION(spl) +{ + PHP_MINIT(spl_exceptions)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_directory)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_dllist)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_heap)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_fixedarray)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU); + + return SUCCESS; +} +/* }}} */ + +PHP_RINIT_FUNCTION(spl) /* {{{ */ +{ + SPL_G(autoload_extensions) = NULL; + SPL_G(autoload_extensions_len) = 0; + SPL_G(autoload_functions) = NULL; + SPL_G(hash_mask_init) = 0; + return SUCCESS; +} /* }}} */ + +PHP_RSHUTDOWN_FUNCTION(spl) /* {{{ */ +{ + if (SPL_G(autoload_extensions)) { + efree(SPL_G(autoload_extensions)); + SPL_G(autoload_extensions) = NULL; + SPL_G(autoload_extensions_len) = 0; + } + if (SPL_G(autoload_functions)) { + zend_hash_destroy(SPL_G(autoload_functions)); + FREE_HASHTABLE(SPL_G(autoload_functions)); + SPL_G(autoload_functions) = NULL; + } + if (SPL_G(hash_mask_init)) { + SPL_G(hash_mask_init) = 0; + } + return SUCCESS; +} /* }}} */ + +/* {{{ spl_module_entry + */ +zend_module_entry spl_module_entry = { + STANDARD_MODULE_HEADER, + "SPL", + spl_functions, + PHP_MINIT(spl), + NULL, + PHP_RINIT(spl), + PHP_RSHUTDOWN(spl), + PHP_MINFO(spl), + "0.2", + PHP_MODULE_GLOBALS(spl), + PHP_GINIT(spl), + NULL, + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/php_spl.h b/ext/spl/php_spl.h new file mode 100644 index 0000000..4794f12 --- /dev/null +++ b/ext/spl/php_spl.h @@ -0,0 +1,99 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifndef PHP_SPL_H +#define PHP_SPL_H + +#include "php.h" +#if defined(PHP_WIN32) +# include "win32/php_stdint.h" +#elif defined(HAVE_STDINT_H) +# include <stdint.h> +#endif +#include <stdarg.h> + +#if 0 +#define SPL_DEBUG(x) x +#else +#define SPL_DEBUG(x) +#endif + +extern zend_module_entry spl_module_entry; +#define phpext_spl_ptr &spl_module_entry + +#ifdef PHP_WIN32 +# ifdef SPL_EXPORTS +# define SPL_API __declspec(dllexport) +# elif defined(COMPILE_DL_SPL) +# define SPL_API __declspec(dllimport) +# else +# define SPL_API /* nothing */ +# endif +#elif defined(__GNUC__) && __GNUC__ >= 4 +# define SPL_API __attribute__ ((visibility("default"))) +#else +# define SPL_API +#endif + +#if defined(PHP_WIN32) && !defined(COMPILE_DL_SPL) +#undef phpext_spl +#define phpext_spl NULL +#endif + +PHP_MINIT_FUNCTION(spl); +PHP_MSHUTDOWN_FUNCTION(spl); +PHP_RINIT_FUNCTION(spl); +PHP_RSHUTDOWN_FUNCTION(spl); +PHP_MINFO_FUNCTION(spl); + + +ZEND_BEGIN_MODULE_GLOBALS(spl) + char * autoload_extensions; + HashTable * autoload_functions; + int autoload_running; + int autoload_extensions_len; + intptr_t hash_mask_handle; + intptr_t hash_mask_handlers; + int hash_mask_init; +ZEND_END_MODULE_GLOBALS(spl) + +#ifdef ZTS +# define SPL_G(v) TSRMG(spl_globals_id, zend_spl_globals *, v) +extern int spl_globals_id; +#else +# define SPL_G(v) (spl_globals.v) +extern zend_spl_globals spl_globals; +#endif + +PHP_FUNCTION(spl_classes); +PHP_FUNCTION(class_parents); +PHP_FUNCTION(class_implements); +PHP_FUNCTION(class_uses); + +PHPAPI void php_spl_object_hash(zval *obj, char* md5str TSRMLS_DC); + +#endif /* PHP_SPL_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl.php b/ext/spl/spl.php new file mode 100755 index 0000000..fdffda3 --- /dev/null +++ b/ext/spl/spl.php @@ -0,0 +1,1163 @@ +<?php + +/** @file spl.php + * @ingroup SPL + * @brief Documentation of internal classes and interfaces + * + * SPL - Standard PHP Library + * + * (c) Marcus Boerger, 2003 - 2008 + */ + +/** @mainpage SPL - Standard PHP Library + * + * SPL - Standard PHP Library + * + * SPL is a collection of interfaces and classes that are meant to solve + * standard problems and implements some efficient data access interfaces + * and classes. You'll find the classes documented using php code in the + * file spl.php or in corresponding .inc files in subdirectories examples + * and internal. Based on the internal implementations or the files in the + * examples subdirectory there are also some .php files to experiment with. + * + * The .inc files are not included automatically because they are sooner or + * later integrated into the extension. That means that you either need to + * put the code of examples/autoload.inc into your autoprepend file or that + * you have to point your ini setting auto_prepend_file to that file. + * + * Below is a list of interfaces/classes already availabel natively through + * the SPL extension grouped by category. + * + * 1) Iterators + * + * SPL offers some advanced iterator algorithms: + * + * - interface RecursiveIterator extends Iterator + * - interface OuterIterator extends Iterator + * - class RecursiveIteratorIterator implements OuterIterator + * - class RecursiveTreeIterator extends RecursiveIteratorIterator + * - abstract class FilterIterator implements OuterIterator + * - class ParentIterator extends FilterIterator implements RecursiveIterator + * - interface SeekableIterator extends Iterator + * - class LimitIterator implements OuterIterator + * - class CachingIterator implements OuterIterator + * - class RecursiveCachingIterator extends CachingIterator implements RecursiveIterator + * - class IteratorIterator implements OuterIterator + * - class NoRewindIterator implements OuterIterator + * - class EmptyIterator implements Iterator + * - class InfiniteIterator extends IteratorIterator + * - class AppendIterator implements OuterIterator + * - class RegexIterator extends FilterIterator + * - class RecursiveRegexIterator extends RegexIterator implements RecursiveIterator + * - class MultipleIterator extends Iterator + * + * 2) Directories and Files + * + * SPL offers two advanced directory and file handling classes: + * + * - class SplFileInfo + * - class DirectoryIterator extends SplFileInfo implements Iterator + * - class FilesystemIterator extends DirectoryIterator + * - class RecursiveDirectoryIterator extends FilesystemIterator implements RecursiveIterator + * - class GlobIterator extends FilesystemIterator implements Countable + * - class SplFileObject extends SplFileInfo implements RecursiveIterator, SeekableIterator + * - class SplTempFileObject extends SplFileObject + * + * 3) XML + * + * SPL offers an advanced XML handling class: + * + * - class SimpleXMLIterator extends simplexml_element implements RecursiveIterator + * + * 4) Array Overloading + * + * SPL offers advanced Array overloading: + * + * - class ArrayObject implements IteratorAggregate, ArrayAccess, Countable + * - class ArrayIterator implements Iterator, ArrayAccess, Countable, SeekableIterator + * - class RecursiveArrayIterator extends ArrayIterator implements RecursiveIterator + * - class SplFixedArray implements Iterator, ArrayAccess, Countable + * + * As the above suggest an ArrayObject creates an ArrayIterator when it comes to + * iteration (e.g. ArrayObject instance used inside foreach). + * + * 5) Counting + * + * - interface Countable allows to hook into the standard array function count(). + * + * 6) Exception%s + * + * SPL provides a set of standard Exception classes each meant to indicate a + * certain problem type. + * + * - class LogicException extends Exception + * - class BadFunctionCallException extends LogicException + * - class BadMethodCallException extends BadFunctionCallException + * - class DomainException extends LogicException + * - class InvalidArgumentException extends LogicException + * - class LengthException extends LogicException + * - class OutOfRangeException extends LogicException + * - class RuntimeException extends Exception + * - class OutOfBoundsException extends RuntimeException + * - class OverflowException extends RuntimeException + * - class RangeException extends RuntimeException + * - class UnderflowException extends RuntimeException + * + * 7) Observer + * + * SPL suggests a standard way of implementing the observer pattern. + * + * - interface SplObserver + * - interface SplSubject + * - class SplObjectStorage + * + * 8) Datastructures + * + * SPL proposes a set of datastructures implemented internally. + * + * - class SplDoublyLinkedList + * - class SplStack extends SplDoublyLinkedList + * - class SplQueue extends SplDoublyLinkedList + * + * 9) @ref Examples + * + * The classes and interfaces in this group are contained as PHP code in the + * examples subdirectory of ext/SPL. Sooner or later they will be moved to + * c-code. + * + * 10) 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> + * - <a href="http://www.devshed.com/c/a/PHP/The-Standard-PHP-Library-Part-1/">The Standard PHP Library, Part 1</a> + * - <a href="http://www.devshed.com/c/a/PHP/The-Standard-PHP-Library-Part-2/">The Standard PHP Library, Part 2</a> + * - <a href="http://www.professionelle-softwareentwicklung-mit-php5.de/erste_auflage/oop.iterators.spl.html">Die Standard PHP Library (SPL) [german]</a> + * + * 11) Talks on SPL: + * - SPL Update <a href="http://talks.somabo.de/200702_vancouver_spl_update.pps">[pps]</a>, <a href="http://talks.somabo.de/200702_vancouver_spl_update.pdf">[pdf]</a> + * - Happy SPLing <a href="http://talks.somabo.de/200509_toronto_happy_spling.pps">[pps]</a>, <a href="http://talks.somabo.de/200509_toronto_happy_spling.pdf">[pdf]</a> + * - From engine overloading to SPL <a href="http://talks.somabo.de/200505_cancun_from_engine_overloading_to_spl.pps">[pps]</a>, <a href="http://talks.somabo.de/200505_cancun_from_engine_overloading_to_spl.pdf">[pdf]</a> + * - SPL for the masses <a href="http://talks.somabo.de/200504_php_quebec_spl_for_the_masses.pps">[pps]</a>, <a href="http://talks.somabo.de/200504_php_quebec_spl_for_the_masses.pdf">[pdf]</a> + * + * 12) Debug sessions: + * - Debug session 1 <a href="200407_oscon_introduction_to_iterators_debug.pps">[pps]</a>, <a href="200407_oscon_introduction_to_iterators_debug.pdf">[pdf]</a> + * - Debug session 2 <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_1.pps">[pps]</a>, <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_1.pdf">[pdf]</a>, <a href="http://taks.somabo.de/200411_php_conference_frankfrurt_iterator_debug_session.swf">[swf]</a> + * - Debug session 3 <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_2.pps">[pps]</a>, <a href="http://talks.somabo.de/200509_toronto_iterator_debug_session_2.pdf">[pdf]</a> + * + * 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 - 2007 + */ + +/** @defgroup ZendEngine Zend engine classes + * + * The classes and interfaces in this group are contained in the c-code of + * PHP's Zend engine. + */ + +/** @defgroup SPL Internal classes + * + * The classes and interfaces in this group are contained in the c-code of + * ext/SPL. + */ + +/** @defgroup Examples Example classes + * + * The classes and interfaces in this group are contained as PHP code in the + * examples subdirectory of ext/SPL. Sooner or later they will be moved to + * c-code. + */ + +/** @ingroup SPL + * @brief Default implementation for __autoload() + * @since PHP 5.1 + * + * @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) {/**/}; + +/** @ingroup SPL + * @brief Manual invocation of all registerd autoload functions + * @since PHP 5.1 + * + * @param class_name name of class to load + */ +function spl_autoload_call(string $class_name) {/**/}; + +/** @ingroup SPL + * @brief Register and return default file extensions for spl_autoload + * @since PHP 5.1 + * + * @param file_extensions optional comma separated list of extensions to use in + * default autoload function. If not given just return the current list. + * @return comma separated list of file extensions to use in default autoload + * function. + */ +function spl_autoload_extensions($file_extensions) {/**/}; + +/** @ingroup SPL + * @brief Return all registered autoload functionns + * @since PHP 5.1 + * + * @return array of all registered autoload functions or false + */ +function spl_autoload_functions() {/**/}; + +/** @ingroup SPL + * @brief Register given function as autoload implementation + * @since PHP 5.1 + * + * @param autoload_function name of function or array of object/class and + * 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) {/**/}; + +/** @ingroup SPL + * @brief Unregister given function as autoload implementation + * @since PHP 5.1 + * + * @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") {/**/}; + +/** @ingroup SPL + * @brief Return an array of classes and interfaces in SPL + * + * @return array containing the names of all clsses and interfaces defined in + * extension SPL + */ +function spl_classes() {/**/}; + +/** @ingroup SPL + * @brief Count the elements in an iterator + * @since PHP 5.1 + * + * @return number of elements in an iterator + */ +function iterator_count(Traversable $it) {/**/}; + +/** @ingroup SPL + * @brief Copy iterator elements into an array + * @since PHP 5.1 + * + * @param it iterator to copy + * @param use_keys whether touse the keys + * @return array with elements copied from the iterator + */ +function iterator_to_array(Traversable $it, $use_keys = true) {/**/}; + +/** @ingroup ZendEngine + * @brief Basic Exception class. + * @since PHP 5.0 + */ +class Exception +{ + /** The exception message */ + protected $message; + + /** The string represenations as generated during construction */ + private $string; + + /** The code passed to the constructor */ + protected $code; + + /** The file name where the exception was instantiated */ + protected $file; + + /** The line number where the exception was instantiated */ + protected $line; + + /** The stack trace */ + private $trace; + + /** Prevent clone + */ + final private function __clone() {} + + /** Construct an exception + * + * @param $message Some text describing the exception + * @param $code Some code describing the exception + */ + function __construct($message = NULL, $code = 0) { + if (func_num_args()) { + $this->message = $message; + } + $this->code = $code; + $this->file = __FILE__; // of throw clause + $this->line = __LINE__; // of throw clause + $this->trace = debug_backtrace(); + $this->string = StringFormat($this); + } + + /** @return the message passed to the constructor + */ + final public function getMessage() + { + return $this->message; + } + + /** @return the code passed to the constructor + */ + final public function getCode() + { + return $this->code; + } + + /** @return the name of the file where the exception was thrown + */ + final public function getFile() + { + return $this->file; + } + + /** @return the line number where the exception was thrown + */ + final public function getLine() + { + return $this->line; + } + + /** @return the stack trace as array + */ + final public function getTrace() + { + return $this->trace; + } + + /** @return the stack trace as string + */ + final public function getTraceAsString() + { + } + + /** @return string represenation of exception + */ + public function __toString() + { + return $this->string; + } +} + +/** @ingroup SPL + * @brief Exception that represents error in the program logic. + * @since PHP 5.1 + * + * This kind of exceptions should directly leed to a fix in your code. + */ +class LogicException extends Exception +{ +} + +/** @ingroup SPL + * @brief Exception thrown when a function call was illegal. + * @since PHP 5.1 + */ +class BadFunctionCallException extends LogicException +{ +} + +/** @ingroup SPL + * @brief Exception thrown when a method call was illegal. + * @since PHP 5.1 + */ +class BadMethodCallException extends BadFunctionCallException +{ +} + +/** @ingroup SPL + * @brief Exception that denotes a value not in the valid domain was used. + * @since PHP 5.1 + * + * This kind of exception should be used to inform about domain erors in + * mathematical sense. + * + * @see RangeException + */ +class DomainException extends LogicException +{ +} + +/** @ingroup SPL + * @brief Exception that denotes invalid arguments were passed. + * @since PHP 5.1 + * + * @see UnexpectedValueException + */ +class InvalidArgumentException extends LogicException +{ +} + +/** @ingroup SPL + * @brief Exception thrown when a parameter exceeds the allowed length. + * @since PHP 5.1 + * + * This can be used for strings length, array size, file size, number of + * elements read from an Iterator and so on. + */ +class LengthException extends LogicException +{ +} + +/** @ingroup SPL + * @brief Exception thrown when an illegal index was requested. + * @since PHP 5.1 + * + * This represents errors that should be detected at compile time. + * + * @see OutOfBoundsException + */ +class OutOfRangeException extends LogicException +{ +} + +/** @ingroup SPL + * @brief Exception thrown for errors that are only detectable at runtime. + * @since PHP 5.1 + */ +class RuntimeException extends Exception +{ +} + +/** @ingroup SPL + * @brief Exception thrown when an illegal index was requested. + * @since PHP 5.1 + * + * This represents errors that cannot be detected at compile time. + * + * @see OutOfRangeException + */ +class OutOfBoundsException extends RuntimeException +{ +} + +/** @ingroup SPL + * @brief Exception thrown to indicate arithmetic/buffer overflow. + * @since PHP 5.1 + */ +class OverflowException extends RuntimeException +{ +} + +/** @ingroup SPL + * @brief Exception thrown to indicate range errors during program execution. + * @since PHP 5.1 + * + * Normally this means there was an arithmetic error other than under/overflow. + * This is the runtime version of DomainException. + * + * @see DomainException + */ +class RangeException extends RuntimeException +{ +} + +/** @ingroup SPL + * @brief Exception thrown to indicate arithmetic/buffer underflow. + * @since PHP 5.1 + */ +class UnderflowException extends RuntimeException +{ +} + +/** @ingroup SPL + * @brief Exception thrown to indicate an unexpected value. + * @since PHP 5.1 + * + * Typically this happens when a function calls another function and espects + * the return value to be of a certain type or value not including arithmetic + * or buffer related errors. + * + * @see InvalidArgumentException + */ +class UnexpectedValueException extends RuntimeException +{ +} + +/** @ingroup ZendEngine + * @brief Interface to override array access of objects. + * @since PHP 5.0 + */ +interface ArrayAccess +{ + /** @param $offset to modify + * @param $value new value + */ + function offsetSet($offset, $value); + + /** @param $offset to retrieve + * @return value at given offset + */ + function offsetGet($offset); + + /** @param $offset to delete + */ + function offsetUnset($offset); + + /** @param $offset to check + * @return whether the offset exists. + */ + function offsetExists($offset); +} + +/** @ingroup ZendEngine + * @brief Interface to detect a class is traversable using foreach. + * @since PHP 5.0 + * + * Abstract base interface that cannot be implemented alone. Instead it + * must be implemented by either IteratorAggregate or Iterator. + * + * @note Internal classes that implement this interface can be used in a + * foreach construct and do not need to implement IteratorAggregate or + * Iterator. + * + * @note This is an engine internal interface which cannot be implemented + * in PHP scripts. Either IteratorAggregate or Iterator must be used + * instead. + */ +interface Traversable +{ +} + +/** @ingroup ZendEngine + * @brief Interface to create an external Iterator. + * @since PHP 5.0 + * + * @note This is an engine internal interface. + */ +interface IteratorAggregate extends Traversable +{ + /** @return an Iterator for the implementing object. + */ + function getIterator(); +} + +/** @ingroup ZendEngine + * @brief Basic iterator + * @since PHP 5.0 + * + * Interface for external iterators or objects that can be iterated + * themselves internally. + * + * @note This is an engine internal interface. + */ +interface Iterator extends Traversable +{ + /** Rewind the Iterator to the first element. + */ + function rewind(); + + /** Return the current element. + */ + function current(); + + /** Return the key of the current element. + */ + function key(); + + /** Move forward to next element. + */ + function next(); + + /** Check if there is a current element after calls to rewind() or next(). + */ + function valid(); +} + +/** @ingroup SPL + * @brief This Interface allows to hook into the global count() function. + * @since PHP 5.1 + */ +interface Countable +{ + /** @return the number the global function count() should show + */ + function count(); +} + +/** @ingroup ZendEngine + * @brief Interface for customized serializing + * @since 5.1 + * + * Classes that implement this interface no longer support __sleep() and + * __wakeup(). The method serialized is called whenever an instance needs to + * be serialized. This does not invoke __destruct() or has any other side + * effect unless programmed inside the method. When the data is unserialized + * the class is known and the appropriate unserialize() method is called as a + * constructor instead of calling __construct(). If you need to execute the + * standard constructor you may do so in the method. + */ +interface Serializable +{ + /** + * @return string representation of the instance + */ + function serialize(); + + /** + * @note This is a constructor + * + * @param $serialized data read from stream to construct the instance + */ + function unserialize($serialized); +} + +/** @ingroup SPL + * @brief An Array wrapper + * @since PHP 5.0 + * @version 1.2 + * + * This array wrapper allows to recursively iterate over Arrays and public + * Object properties. + * + * @see ArrayIterator + */ +class ArrayObject implements IteratorAggregate, ArrayAccess, Countable +{ + /** Properties of the object have their normal functionality + * when accessed as list (var_dump, foreach, etc.) */ + const STD_PROP_LIST = 0x00000001; + /** Array indices can be accessed as properties in read/write */ + const ARRAY_AS_PROPS = 0x00000002; + + /** Construct a new array iterator from anything that has a hash table. + * That is any Array or Object. + * + * @param $array the array to use. + * @param $flags see setFlags(). + * @param $iterator_class class used in getIterator() + */ + function __construct($array, $flags = 0, $iterator_class = "ArrayIterator") {/**/} + + /** Set behavior flags. + * + * @param $flags bitmask as follows: + * 0 set: properties of the object have their normal functionality + * when accessed as list (var_dump, foreach, etc.) + * 1 set: array indices can be accessed as properties in read/write + */ + function setFlags($flags) {/**/} + + /** @return current flags + */ + 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 $array new array or object + */ + function exchangeArray($array) {/**/} + + /** @return the iterator which is an ArrayIterator object connected to + * this object. + */ + function getIterator() {/**/} + + /** @param $index offset to inspect + * @return whetehr offset $index esists + */ + function offsetExists($index) {/**/} + + /** @param $index offset to return value for + * @return value at offset $index + */ + function offsetGet($index) {/**/} + + /** @param $index index to set + * @param $newval new value to store at offset $index + */ + function offsetSet($index, $newval) {/**/} + + /** @param $index offset to unset + */ + 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) {/**/} + + /** @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() {/**/} + + /** @return the number of elements in the array or the number of public + * properties in the object. + */ + function count() {/**/} + + /* @param $iterator_class new class used in getIterator() + */ + function setIteratorClass($itertor_class) {/**/} + + /* @return class used in getIterator() + */ + function getIteratorClass() {/**/} +} + +/** @ingroup SPL + * @brief An Array iterator + * @since PHP 5.0 + * @version 1.2 + * + * This iterator allows to unset and modify values and keys while iterating + * over Arrays and Objects. + * + * When you want to iterate over the same array multiple times you need to + * instanciate ArrayObject and let it create ArrayIterator instances that + * refer to it either by using foreach or by calling its getIterator() + * method manually. + */ +class ArrayIterator implements SeekableIterator, ArrayAccess, Countable +{ + /** Properties of the object have their normal functionality + * when accessed as list (var_dump, foreach, etc.) */ + const STD_PROP_LIST = 0x00000001; + /** Array indices can be accessed as properties in read/write */ + const ARRAY_AS_PROPS = 0x00000002; + + /** Construct a new array iterator from anything that has a hash table. + * That is any Array or Object. + * + * @param $array the array to use. + * @param $flags see setFlags(). + */ + function __construct($array, $flags = 0) {/**/} + + /** Set behavior flags. + * + * @param $flags bitmask as follows: + * 0 set: properties of the object have their normal functionality + * when accessed as list (var_dump, foreach, etc.) + * 1 set: array indices can be accessed as properties in read/write + */ + function setFlags($flags) {/**/} + + /** + * @return current flags + */ + 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) {/**/} + + /** @param $index offset to return value for + * @return value at offset $index + */ + function offsetGet($index) {/**/} + + /** @param $index index to set + * @param $newval new value to store at offset $index + */ + function offsetSet($index, $newval) {/**/} + + /** @param $index offset to unset + */ + 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) {/**/} + + /** @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() {/**/} + + /** @param $position offset to seek to + * @throw OutOfBoundsException if $position is invalid + */ + function seek($position) {/**/} + + /** @return the number of elements in the array or the number of public + * properties in the object. + */ + 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 + * @brief File info class + * @since PHP 5.1.3 + */ +class SplFileInfo +{ + /** Construct a file info object + * + * @param $file_name path or file name + */ + function __construct($file_name) {/**/} + + /** @return the path part only. + */ + function getPath() {/**/} + + /** @return the filename only. + */ + 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) {/**/} + + /** @return The current entries path and file name. + */ + 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) {/**/} + + /** @return The current entry's permissions. + */ + function getPerms() {/**/} + + /** @return The current entry's inode. + */ + function getInode() {/**/} + + /** @return The current entry's size in bytes . + */ + function getSize() {/**/} + + /** @return The current entry's owner name. + */ + function getOwner() {/**/} + + /** @return The current entry's group name. + */ + function getGroup() {/**/} + + /** @return The current entry's last access time. + */ + function getATime() {/**/} + + /** @return The current entry's last modification time. + */ + function getMTime() {/**/} + + /** @return The current entry's last change time. + */ + function getCTime() {/**/} + + /** @return The current entry's file type. + */ + function getType() {/**/} + + /** @return Whether the current entry is writeable. + */ + function isWritable() {/**/} + + /** @return Whether the current entry is readable. + */ + function isReadable() {/**/} + + /** @return Whether the current entry is executable. + */ + function isExecutable() {/**/} + + /** @return Whether the current entry is . + */ + function isFile() {/**/} + + /** @return Whether the current entry is a directory. + */ + function isDir() {/**/} + + /** @return whether the current entry is a link. + */ + function isLink() {/**/} + + /** @return target of link. + */ + function getLinkTarget() {/**/} + + /** @return The resolved path + */ + function getRealPath() {/**/} + + /** @return getPathname() + */ + function __toString() {/**/} + + /** Open the current file as a SplFileObject instance + * + * @param mode open mode + * @param use_include_path whether to search include paths (don't use) + * @param context resource context to pased to open function + * @throw RuntimeException if file cannot be opened (e.g. insufficient + * access rights). + * @return The opened file as a SplFileObject instance + * + * @see SplFileObject + * @see SplFileInfo::setFileClass() + * @see file() + */ + 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") {/**/} + + /** @param class_name name of class used with getFileInfo(), getPathInfo(). + * Must be derived from SplFileInfo. + */ + function setInfoClass(string class_name = "SplFileInfo") {/**/} +} + +/** @ingroup SPL + * @brief Directory iterator + * @version 1.1 + * @since PHP 5.0 + */ +class DirectoryIterator extends SplFileInfo implements Iterator +{ + /** Construct a directory iterator from a path-string. + * + * @param $path directory to iterate. + */ + function __construct($path) {/**/} + + /** @copydoc Iterator::rewind */ + function rewind() {/**/} + + /** @copydoc Iterator::valid */ + function valid() {/**/} + + /** @return index of entry + */ + function key() {/**/} + + /** @return $this + */ + function current() {/**/} + + /** @copydoc Iterator::next */ + function next() {/**/} + + /** @return Whether the current entry is either '.' or '..'. + */ + function isDot() {/**/} + + /** @return whether the current entry is a link. + */ + function isLink() {/**/} + + /** @return getFilename() + */ + function __toString() {/**/} +} + +/** @ingroup SPL + * @brief recursive directory iterator + * @version 1.1 + * @since PHP 5.0 + */ +class RecursiveDirectoryIterator extends DirectoryIterator implements RecursiveIterator +{ + const CURRENT_AS_FILEINFO 0x00000000; /* make RecursiveDirectoryTree::current() return SplFileInfo */ + const CURRENT_AS_SELF 0x00000010; /* make RecursiveDirectoryTree::current() return getSelf() */ + const CURRENT_AS_PATHNAME 0x00000020; /* make RecursiveDirectoryTree::current() return getPathname() */ + + const KEY_AS_PATHNAME 0x00000000; /* make RecursiveDirectoryTree::key() return getPathname() */ + const KEY_AS_FILENAME 0x00000100; /* make RecursiveDirectoryTree::key() return getFilename() */ + + const NEW_CURRENT_AND_KEY 0x00000100; /* CURRENT_AS_FILEINFO + KEY_AS_FILENAME */ + + /** Construct a directory iterator from a path-string. + * + * @param $path directory to iterate. + * @param $flags open flags + * - CURRENT_AS_FILEINFO + * - CURRENT_AS_SELF + * - CURRENT_AS_PATHNAME + * - KEY_AS_PATHNAME + * - KEY_AS_FILENAME + * - NEW_CURRENT_AND_KEY + */ + function __construct($path, $flags = 0) {/**/} + + /** @return getPathname() or getFilename() depending on flags + */ + function key() {/**/} + + /** @return getFilename() or getFileInfo() depending on flags + */ + function current() {/**/} + + /** @return whether the current is a directory (not '.' or '..'). + */ + function hasChildren() {/**/} + + /** @return a RecursiveDirectoryIterator for the current entry. + */ + function getChildren() {/**/} + + /** @return sub path only (without main path) + */ + function getSubPath() {/**/} + + /** @return the current sub path + */ + function getSubPathname() {/**/} +} + +/** @ingroup SPL + * @brief recursive SimpleXML_Element iterator + * @since PHP 5.0 + * + * The SimpleXMLIterator implements the RecursiveIterator interface. This + * allows iteration over all elements using foreach or an appropriate while + * construct, just like SimpleXMLElement does. When using the foreach construct, + * you will also iterate over the subelements. For every element which + * 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, Countable +{ + /** @return whether the current node has sub nodes. + */ + function hasChildren() {/**/} + + /** @return a SimpleXMLIterator for the current node. + */ + 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 + * @brief Observer of the observer pattern + * @since PHP 5.1 + * + * For a detailed explanation see Observer pattern in + * <em> + * Gamma, Helm, Johnson, Vlissides<br /> + * Design Patterns + * </em> + */ +interface SplObserver +{ + /** Called from the subject (i.e. when it's value has changed). + * @param $subject the callee + */ + function update(SplSubject $subject); +} + +/** @ingroup SPL + * @brief Subject to the observer pattern + * @since PHP 5.1 + * @see Observer + */ +interface SplSubject +{ + /** @param $observer new observer to attach + */ + function attach(SplObserver $observer); + + /** @param $observer existing observer to detach + * @note a non attached observer shouldn't result in a warning or similar + */ + function detach(SplObserver $observer); + + /** Notify all observers + */ + function notify(); +} + +?> diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c new file mode 100644 index 0000000..2c2c87d --- /dev/null +++ b/ext/spl/spl_array.c @@ -0,0 +1,1995 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "ext/standard/php_var.h" +#include "ext/standard/php_smart_str.h" +#include "zend_interfaces.h" +#include "zend_exceptions.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_iterators.h" +#include "spl_array.h" +#include "spl_exceptions.h" + +zend_object_handlers spl_handler_ArrayObject; +PHPAPI zend_class_entry *spl_ce_ArrayObject; + +zend_object_handlers spl_handler_ArrayIterator; +PHPAPI zend_class_entry *spl_ce_ArrayIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator; + +#define SPL_ARRAY_STD_PROP_LIST 0x00000001 +#define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002 +#define SPL_ARRAY_CHILD_ARRAYS_ONLY 0x00000004 +#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 0xFFFF0000 +#define SPL_ARRAY_CLONE_MASK 0x0300FFFF + +#define SPL_ARRAY_METHOD_NO_ARG 0 +#define SPL_ARRAY_METHOD_USE_ARG 1 +#define SPL_ARRAY_METHOD_MAY_USER_ARG 2 + +typedef struct _spl_array_object { + zend_object std; + zval *array; + zval *retval; + HashPosition pos; + ulong pos_h; + int ar_flags; + int is_self; + zend_function *fptr_offset_get; + zend_function *fptr_offset_set; + zend_function *fptr_offset_has; + zend_function *fptr_offset_del; + zend_function *fptr_count; + zend_class_entry* ce_get_iterator; + HashTable *debug_info; + unsigned char nApplyCount; +} spl_array_object; + +static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */ + if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) { + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + return intern->std.properties; + } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) { + spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC); + return spl_array_get_hash_table(other, check_std_props TSRMLS_CC); + } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) { + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + return intern->std.properties; + } else { + return HASH_OF(intern->array); + } +} /* }}} */ + +static void spl_array_rewind(spl_array_object *intern TSRMLS_DC); + +static void spl_array_update_pos(spl_array_object* intern) /* {{{ */ +{ + Bucket *pos = intern->pos; + if (pos != NULL) { + intern->pos_h = pos->h; + } +} /* }}} */ + +static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */ +{ + intern->pos = pos; + spl_array_update_pos(intern); +} /* }}} */ + +SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */ +{ + Bucket *p; + +/* IS_CONSISTENT(ht);*/ + +/* HASH_PROTECT_RECURSION(ht);*/ + p = ht->arBuckets[intern->pos_h & ht->nTableMask]; + while (p != NULL) { + if (p == intern->pos) { + return SUCCESS; + } + p = p->pNext; + } +/* HASH_UNPROTECT_RECURSION(ht); */ + spl_array_rewind(intern TSRMLS_CC); + return FAILURE; + +} /* }}} */ + +SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */ +{ + HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_array_object_free_storage */ +static void spl_array_object_free_storage(void *object TSRMLS_DC) +{ + spl_array_object *intern = (spl_array_object *)object; + + zend_object_std_dtor(&intern->std TSRMLS_CC); + + zval_ptr_dtor(&intern->array); + zval_ptr_dtor(&intern->retval); + + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + + efree(object); +} +/* }}} */ + +zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); + +/* {{{ spl_array_object_new_ex */ +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) +{ + zend_object_value retval; + spl_array_object *intern; + zval *tmp; + zend_class_entry * parent = class_type; + int inherited = 0; + + intern = emalloc(sizeof(spl_array_object)); + memset(intern, 0, sizeof(spl_array_object)); + *obj = intern; + ALLOC_INIT_ZVAL(intern->retval); + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + intern->ar_flags = 0; + intern->debug_info = NULL; + intern->ce_get_iterator = spl_ce_ArrayIterator; + if (orig) { + spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC); + + intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK; + intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK); + intern->ce_get_iterator = other->ce_get_iterator; + if (clone_orig) { + intern->array = other->array; + if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) { + MAKE_STD_ZVAL(intern->array); + array_init(intern->array); + zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*)); + } + if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) { + Z_ADDREF_P(other->array); + } + } else { + intern->array = orig; + Z_ADDREF_P(intern->array); + intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER; + } + } else { + MAKE_STD_ZVAL(intern->array); + array_init(intern->array); + intern->ar_flags &= ~SPL_ARRAY_IS_REF; + } + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC); + 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; + break; + } + parent = parent->parent; + inherited = 1; + } + if (!parent) { /* this must never happen */ + php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator"); + } + if (inherited) { + zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get); + if (intern->fptr_offset_get->common.scope == parent) { + intern->fptr_offset_get = NULL; + } + zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set); + if (intern->fptr_offset_set->common.scope == parent) { + intern->fptr_offset_set = NULL; + } + zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has); + if (intern->fptr_offset_has->common.scope == parent) { + intern->fptr_offset_has = NULL; + } + zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del); + if (intern->fptr_offset_del->common.scope == parent) { + intern->fptr_offset_del = NULL; + } + zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count); + if (intern->fptr_count->common.scope == parent) { + intern->fptr_count = NULL; + } + } + /* 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; + } + } + + spl_array_rewind(intern TSRMLS_CC); + return retval; +} +/* }}} */ + +/* {{{ spl_array_object_new */ +static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC) +{ + spl_array_object *tmp; + return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_array_object_clone */ +static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC) +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_array_object *intern; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC); + new_object = &intern->std; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + return new_obj_val; +} +/* }}} */ + +static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + zval **retval; + long index; + HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (!offset) { + return &EG(uninitialized_zval_ptr); + } + + if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return &EG(error_zval_ptr);; + } + + switch(Z_TYPE_P(offset)) { + case IS_NULL: + Z_STRVAL_P(offset) = ""; + Z_STRLEN_P(offset) = 0; + case IS_STRING: + if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) { + switch (type) { + case BP_VAR_R: + zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(offset)); + case BP_VAR_UNSET: + case BP_VAR_IS: + retval = &EG(uninitialized_zval_ptr); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset)); + case BP_VAR_W: { + zval *value; + ALLOC_INIT_ZVAL(value); + zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), (void **)&retval); + } + } + } + return retval; + case IS_RESOURCE: + zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(offset), Z_LVAL_P(offset)); + case IS_DOUBLE: + case IS_BOOL: + case IS_LONG: + if (offset->type == IS_DOUBLE) { + index = (long)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) { + switch (type) { + case BP_VAR_R: + zend_error(E_NOTICE, "Undefined offset: %ld", index); + case BP_VAR_UNSET: + case BP_VAR_IS: + retval = &EG(uninitialized_zval_ptr); + break; + case BP_VAR_RW: + zend_error(E_NOTICE, "Undefined offset: %ld", index); + case BP_VAR_W: { + zval *value; + ALLOC_INIT_ZVAL(value); + zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), (void **)&retval); + } + } + } + return retval; + default: + zend_error(E_WARNING, "Illegal offset type"); + return (type == BP_VAR_W || type == BP_VAR_RW) ? + &EG(error_zval_ptr) : &EG(uninitialized_zval_ptr); + } +} /* }}} */ + +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) { + zval *rv; + if (!offset) { + ALLOC_INIT_ZVAL(offset); + } else { + SEPARATE_ARG_IF_REF(offset); + } + zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset); + zval_ptr_dtor(&offset); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + return intern->retval; + } + return EG(uninitialized_zval_ptr); + } + } + 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 || type == BP_VAR_UNSET) && !Z_ISREF_PP(ret)) { + if (Z_REFCOUNT_PP(ret) > 1) { + zval *newval; + + /* Separate */ + MAKE_STD_ZVAL(newval); + *newval = **ret; + zval_copy_ctor(newval); + Z_SET_REFCOUNT_P(newval, 1); + + /* Replace */ + Z_DELREF_PP(ret); + *ret = newval; + } + + Z_SET_ISREF_PP(ret); + } + + return *ret; +} /* }}} */ + +static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */ +{ + return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC); +} /* }}} */ + +static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + long index; + HashTable *ht; + + if (check_inherited && intern->fptr_offset_set) { + if (!offset) { + ALLOC_INIT_ZVAL(offset); + } else { + SEPARATE_ARG_IF_REF(offset); + } + zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value); + zval_ptr_dtor(&offset); + return; + } + + if (!offset) { + ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (ht->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + Z_ADDREF_P(value); + zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL); + return; + } + switch(Z_TYPE_P(offset)) { + case IS_STRING: + ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (ht->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + Z_ADDREF_P(value); + zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL); + return; + case IS_DOUBLE: + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (ht->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + if (offset->type == IS_DOUBLE) { + index = (long)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + Z_ADDREF_P(value); + zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL); + return; + case IS_NULL: + ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (ht->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + Z_ADDREF_P(value); + zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL); + return; + default: + zend_error(E_WARNING, "Illegal offset type"); + return; + } +} /* }}} */ + +static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */ +{ + spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC); +} /* }}} */ + +static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + long index; + HashTable *ht; + + if (check_inherited && intern->fptr_offset_del) { + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset); + zval_ptr_dtor(&offset); + return; + } + + switch(Z_TYPE_P(offset)) { + case IS_STRING: + ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (ht->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + if (ht == &EG(symbol_table)) { + if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) { + zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset)); + } + } else { + if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) { + zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset)); + } else { + spl_array_object *obj = intern; + + while (1) { + if ((obj->ar_flags & SPL_ARRAY_IS_SELF) != 0) { + break; + } else if (Z_TYPE_P(obj->array) == IS_OBJECT) { + if ((obj->ar_flags & SPL_ARRAY_USE_OTHER) == 0) { + obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC); + break; + } else { + obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC); + } + } else { + obj = NULL; + break; + } + } + if (obj) { + zend_property_info *property_info = zend_get_property_info(obj->std.ce, offset, 1 TSRMLS_CC); + + if (property_info && + (property_info->flags & ZEND_ACC_STATIC) == 0 && + property_info->offset >= 0) { + obj->std.properties_table[property_info->offset] = NULL; + } + } + } + } + break; + case IS_DOUBLE: + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + if (offset->type == IS_DOUBLE) { + index = (long)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (ht->nApplyCount > 0) { + zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited"); + return; + } + if (zend_hash_index_del(ht, index) == FAILURE) { + zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset)); + } + break; + default: + zend_error(E_WARNING, "Illegal offset type"); + return; + } + spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */ +} /* }}} */ + +static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */ +{ + spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC); +} /* }}} */ + +static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + long index; + zval *rv, **tmp; + + if (check_inherited && intern->fptr_offset_has) { + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset); + zval_ptr_dtor(&offset); + if (rv && zend_is_true(rv)) { + zval_ptr_dtor(&rv); + return 1; + } + if (rv) { + zval_ptr_dtor(&rv); + } + return 0; + } + + switch(Z_TYPE_P(offset)) { + case IS_STRING: + { + HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE) { + switch (check_empty) { + case 0: + return Z_TYPE_PP(tmp) != IS_NULL; + case 2: + return 1; + default: + return zend_is_true(*tmp); + } + } + } + return 0; + case IS_DOUBLE: + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + { + HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + if (offset->type == IS_DOUBLE) { + index = (long)Z_DVAL_P(offset); + } else { + index = Z_LVAL_P(offset); + } + if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) { + switch (check_empty) { + case 0: + return Z_TYPE_PP(tmp) != IS_NULL; + case 2: + return 1; + default: + return zend_is_true(*tmp); + } + } + return 0; + } + default: + zend_error(E_WARNING, "Illegal offset type"); + } + return 0; +} /* }}} */ + +static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ +{ + return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC); +} /* }}} */ + +/* {{{ spl_array_object_verify_pos_ex */ +static inline int spl_array_object_verify_pos_ex(spl_array_object *object, HashTable *ht, const char *msg_prefix TSRMLS_DC) +{ + if (!ht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and is no longer an array", msg_prefix); + return FAILURE; + } + + if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, ht TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and internal position is no longer valid", msg_prefix); + return FAILURE; + } + + return SUCCESS; +} /* }}} */ + +/* {{{ spl_array_object_verify_pos */ +static inline int spl_array_object_verify_pos(spl_array_object *object, HashTable *ht TSRMLS_DC) +{ + return spl_array_object_verify_pos_ex(object, ht, "" TSRMLS_CC); +} /* }}} */ + +/* {{{ proto bool ArrayObject::offsetExists(mixed $index) + proto bool ArrayIterator::offsetExists(mixed $index) + Returns whether the requested $index exists. */ +SPL_METHOD(Array, offsetExists) +{ + zval *index; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) { + return; + } + RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 2 TSRMLS_CC)); +} /* }}} */ + +/* {{{ proto mixed ArrayObject::offsetGet(mixed $index) + proto mixed ArrayIterator::offsetGet(mixed $index) + Returns the value at the specified $index. */ +SPL_METHOD(Array, offsetGet) +{ + zval *index, *value; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) { + return; + } + value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC); + RETURN_ZVAL(value, 1, 0); +} /* }}} */ + +/* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval) + proto void ArrayIterator::offsetSet(mixed $index, mixed $newval) + Sets the value at the specified $index to $newval. */ +SPL_METHOD(Array, offsetSet) +{ + zval *index, *value; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) { + return; + } + spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC); +} /* }}} */ + +void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + if (Z_TYPE_P(intern->array) == IS_OBJECT) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name); + return; + } + + spl_array_write_dimension(object, NULL, append_value TSRMLS_CC); + if (!intern->pos) { + spl_array_set_pos(intern, aht->pListTail); + } +} /* }}} */ + +/* {{{ proto void ArrayObject::append(mixed $newval) + proto void ArrayIterator::append(mixed $newval) + Appends the value (cannot be called for objects). */ +SPL_METHOD(Array, append) +{ + zval *value; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) { + return; + } + spl_array_iterator_append(getThis(), value TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void ArrayObject::offsetUnset(mixed $index) + proto void ArrayIterator::offsetUnset(mixed $index) + Unsets the value at the specified $index. */ +SPL_METHOD(Array, offsetUnset) +{ + zval *index; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) { + return; + } + spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC); +} /* }}} */ + +/* {{{ proto array ArrayObject::getArrayCopy() + proto array ArrayIterator::getArrayCopy() + Return a copy of the contained array */ +SPL_METHOD(Array, getArrayCopy) +{ + zval *object = getThis(), *tmp; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + array_init(return_value); + zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*)); +} /* }}} */ + +static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *result; + + if (intern->nApplyCount > 1) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?"); + } + + intern->nApplyCount++; + result = spl_array_get_hash_table(intern, 1 TSRMLS_CC); + intern->nApplyCount--; + return result; +} /* }}} */ + +static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC); + zval *tmp, *storage; + int name_len; + char *zname; + zend_class_entry *base; + + *is_temp = 0; + + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + + if (HASH_OF(intern->array) == intern->std.properties) { + return intern->std.properties; + } else { + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); + } + + if (intern->debug_info->nApplyCount == 0) { + zend_hash_clean(intern->debug_info); + zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + storage = intern->array; + zval_add_ref(&storage); + + base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject; + zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC); + zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL); + efree(zname); + } + + return intern->debug_info; + } +} +/* }}} */ + +static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { + return spl_array_read_dimension(object, member, type TSRMLS_CC); + } + return std_object_handlers.read_property(object, member, type, key TSRMLS_CC); +} /* }}} */ + +static void spl_array_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { + spl_array_write_dimension(object, member, value TSRMLS_CC); + return; + } + std_object_handlers.write_property(object, member, value, key TSRMLS_CC); +} /* }}} */ + +static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { + return spl_array_get_dimension_ptr_ptr(1, object, member, BP_VAR_RW TSRMLS_CC); + } + return std_object_handlers.get_property_ptr_ptr(object, member, key TSRMLS_CC); +} /* }}} */ + +static int spl_array_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { + return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC); + } + return std_object_handlers.has_property(object, member, has_set_exists, key TSRMLS_CC); +} /* }}} */ + +static void spl_array_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { + spl_array_unset_dimension(object, member TSRMLS_CC); + spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */ + return; + } + std_object_handlers.unset_property(object, member, key TSRMLS_CC); +} /* }}} */ + +static int spl_array_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ +{ + HashTable *ht1, + *ht2; + spl_array_object *intern1, + *intern2; + int result = 0; + zval temp_zv; + + intern1 = (spl_array_object*)zend_object_store_get_object(o1 TSRMLS_CC); + intern2 = (spl_array_object*)zend_object_store_get_object(o2 TSRMLS_CC); + ht1 = spl_array_get_hash_table(intern1, 0 TSRMLS_CC); + ht2 = spl_array_get_hash_table(intern2, 0 TSRMLS_CC); + + zend_compare_symbol_tables(&temp_zv, ht1, ht2 TSRMLS_CC); + result = (int)Z_LVAL(temp_zv); + /* if we just compared std.properties, don't do it again */ + if (result == 0 && + !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) { + result = std_object_handlers.compare_objects(o1, o2 TSRMLS_CC); + } + return result; +} /* }}} */ + +static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */ +{ + char *string_key; + uint string_length; + ulong num_key; + + if (Z_TYPE_P(intern->array) == IS_OBJECT) { + do { + if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) { + if (!string_length || string_key[0]) { + return SUCCESS; + } + } else { + return SUCCESS; + } + if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) { + return FAILURE; + } + zend_hash_move_forward_ex(aht, &intern->pos); + spl_array_update_pos(intern); + } while (1); + } + return FAILURE; +} /* }}} */ + +static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */ +{ + zend_hash_move_forward_ex(aht, &intern->pos); + spl_array_update_pos(intern); + if (Z_TYPE_P(intern->array) == IS_OBJECT) { + return spl_array_skip_protected(intern, aht TSRMLS_CC); + } else { + return zend_hash_has_more_elements_ex(aht, &intern->pos); + } +} /* }}} */ + +static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */ +{ + if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid"); + return FAILURE; + } + + return spl_array_next_no_verify(intern, aht TSRMLS_CC); +} /* }}} */ + +static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */ +{ + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + return spl_array_next_ex(intern, aht TSRMLS_CC); + +} /* }}} */ + +/* define an overloaded iterator structure */ +typedef struct { + zend_user_iterator intern; + spl_array_object *object; +} spl_array_it; + +static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_array_it *iterator = (spl_array_it *)iter; + + zend_user_it_invalidate_current(iter TSRMLS_CC); + zval_ptr_dtor((zval**)&iterator->intern.it.data); + + efree(iterator); +} +/* }}} */ + +static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + 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 (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) { + return zend_user_it_valid(iter TSRMLS_CC); + } else { + if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::valid(): " TSRMLS_CC) == FAILURE) { + return FAILURE; + } + + return zend_hash_has_more_elements_ex(aht, &object->pos); + } +} +/* }}} */ + +static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ +{ + 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 (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; + } + } +} +/* }}} */ + +static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +{ + 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 (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 (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::current(): " TSRMLS_CC) == FAILURE) { + return HASH_KEY_NON_EXISTANT; + } + + return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos); + } +} +/* }}} */ + +static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + 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 (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) { + zend_user_it_move_forward(iter TSRMLS_CC); + } else { + 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_ex(object, aht 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_no_verify(object, aht TSRMLS_CC); + } + } +} +/* }}} */ + +static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */ +{ + + zend_hash_internal_pointer_reset_ex(aht, &intern->pos); + spl_array_update_pos(intern); + spl_array_skip_protected(intern, aht TSRMLS_CC); + +} /* }}} */ + +static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */ +{ + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array"); + return; + } + + spl_array_rewind_ex(intern, aht TSRMLS_CC); +} +/* }}} */ + +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; + + 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); + } +} +/* }}} */ + +/* {{{ spl_array_set_array */ +static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) { + + if (Z_TYPE_PP(array) == IS_ARRAY) { + SEPARATE_ZVAL_IF_NOT_REF(array); + } + + if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) { + zval_ptr_dtor(&intern->array); + if (just_array) { + spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC); + ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK; + } + ar_flags |= SPL_ARRAY_USE_OTHER; + intern->array = *array; + } else { + if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) { + zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC); + return; + } + zval_ptr_dtor(&intern->array); + intern->array = *array; + } + if (object == *array) { + intern->ar_flags |= SPL_ARRAY_IS_SELF; + intern->ar_flags &= ~SPL_ARRAY_USE_OTHER; + } else { + intern->ar_flags &= ~SPL_ARRAY_IS_SELF; + } + intern->ar_flags |= ar_flags; + Z_ADDREF_P(intern->array); + if (Z_TYPE_PP(array) == IS_OBJECT) { + zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties); + if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties) + || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_PP(array)->name, intern->std.ce->name); + } + } + + spl_array_rewind(intern TSRMLS_CC); +} +/* }}} */ + +/* iterator handler table */ +zend_object_iterator_funcs spl_array_it_funcs = { + spl_array_it_dtor, + spl_array_it_valid, + spl_array_it_get_current_data, + spl_array_it_get_current_key, + spl_array_it_move_forward, + spl_array_it_rewind +}; + +zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ +{ + 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)); + + Z_ADDREF_P(object); + 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; +} +/* }}} */ + +/* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]]) + proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0]) + Constructs a new array iterator from a path. */ +SPL_METHOD(Array, __construct) +{ + zval *object = getThis(); + spl_array_object *intern; + zval **array; + long ar_flags = 0; + zend_class_entry *ce_get_iterator = spl_ce_Iterator; + zend_error_handling error_handling; + + if (ZEND_NUM_ARGS() == 0) { + return; /* nothing to do */ + } + + zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC); + + intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + if (ZEND_NUM_ARGS() > 2) { + intern->ce_get_iterator = ce_get_iterator; + } + + ar_flags &= ~SPL_ARRAY_INT_MASK; + + spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC); + + zend_restore_error_handling(&error_handling TSRMLS_CC); + +} + /* }}} */ + +/* {{{ proto void ArrayObject::setIteratorClass(string iterator_class) + Set the class used in getIterator. */ +SPL_METHOD(Array, setIteratorClass) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + zend_class_entry * ce_get_iterator = spl_ce_Iterator; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) { + return; + } + + intern->ce_get_iterator = ce_get_iterator; +} +/* }}} */ + +/* {{{ proto string ArrayObject::getIteratorClass() + Get the class used in getIterator. */ +SPL_METHOD(Array, getIteratorClass) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_STRING(intern->ce_get_iterator->name, 1); +} +/* }}} */ + +/* {{{ proto int ArrayObject::getFlags() + Get flags */ +SPL_METHOD(Array, getFlags) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK); +} +/* }}} */ + +/* {{{ proto void ArrayObject::setFlags(int flags) + Set flags */ +SPL_METHOD(Array, setFlags) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + long ar_flags = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) { + return; + } + + intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK); +} +/* }}} */ + +/* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array()) + Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */ +SPL_METHOD(Array, exchangeArray) +{ + zval *object = getThis(), *tmp, **array; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + array_init(return_value); + zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*)); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) { + return; + } + + spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC); + +} +/* }}} */ + +/* {{{ proto ArrayIterator ArrayObject::getIterator() + Create a new iterator from a ArrayObject instance */ +SPL_METHOD(Array, getIterator) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + spl_array_object *iterator; + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + return_value->type = IS_OBJECT; + return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC); + Z_SET_REFCOUNT_P(return_value, 1); + Z_SET_ISREF_P(return_value); +} +/* }}} */ + +/* {{{ proto void ArrayIterator::rewind() + Rewind array back to the start */ +SPL_METHOD(Array, rewind) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_array_rewind(intern TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void ArrayIterator::seek(int $position) + Seek to position. */ +SPL_METHOD(Array, seek) +{ + long opos, position; + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + int result; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) { + return; + } + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + opos = position; + + if (position >= 0) { /* negative values are not supported */ + spl_array_rewind(intern TSRMLS_CC); + result = SUCCESS; + + while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS); + + if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) { + return; /* ok */ + } + } + zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos); +} /* }}} */ + +int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */ +{ + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + HashPosition pos; + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + *count = 0; + return FAILURE; + } + + if (Z_TYPE_P(intern->array) == IS_OBJECT) { + /* We need to store the 'pos' since we'll modify it in the functions + * we're going to call and which do not support 'pos' as parameter. */ + pos = intern->pos; + *count = 0; + spl_array_rewind(intern TSRMLS_CC); + while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) { + (*count)++; + } + spl_array_set_pos(intern, pos); + return SUCCESS; + } else { + *count = zend_hash_num_elements(aht); + return SUCCESS; + } +} /* }}} */ + +int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_count) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + convert_to_long(intern->retval); + *count = (long) Z_LVAL_P(intern->retval); + return SUCCESS; + } + *count = 0; + return FAILURE; + } + return spl_array_object_count_elements_helper(intern, count TSRMLS_CC); +} /* }}} */ + +/* {{{ proto int ArrayObject::count() + proto int ArrayIterator::count() + Return the number of elements in the Iterator. */ +SPL_METHOD(Array, count) +{ + long count; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_array_object_count_elements_helper(intern, &count TSRMLS_CC); + + 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 = NULL; + zval *retval_ptr = NULL; + + MAKE_STD_ZVAL(tmp); + Z_TYPE_P(tmp) = IS_ARRAY; + Z_ARRVAL_P(tmp) = aht; + + if (!use_arg) { + aht->nApplyCount++; + zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC); + aht->nApplyCount--; + } else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|z", &arg) == FAILURE) { + Z_TYPE_P(tmp) = IS_NULL; + zval_ptr_dtor(&tmp); + zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0 TSRMLS_CC); + return; + } + aht->nApplyCount++; + zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, arg? 2 : 1, tmp, arg TSRMLS_CC); + aht->nApplyCount--; + } else { + if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) { + Z_TYPE_P(tmp) = IS_NULL; + zval_ptr_dtor(&tmp); + zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC); + return; + } + aht->nApplyCount++; + zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC); + aht->nApplyCount--; + } + Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */ + zval_ptr_dtor(&tmp); + if (retval_ptr) { + COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr); + } +} /* }}} */ + +#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([int $sort_flags = SORT_REGULAR ]) + proto int ArrayIterator::asort([int $sort_flags = SORT_REGULAR ]) + Sort the entries by values. */ +SPL_ARRAY_METHOD(Array, asort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */ + +/* {{{ proto int ArrayObject::ksort([int $sort_flags = SORT_REGULAR ]) + proto int ArrayIterator::ksort([int $sort_flags = SORT_REGULAR ]) + Sort the entries by key. */ +SPL_ARRAY_METHOD(Array, ksort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */ + +/* {{{ 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, SPL_ARRAY_METHOD_USE_ARG) /* }}} */ + +/* {{{ 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, SPL_ARRAY_METHOD_USE_ARG) /* }}} */ + +/* {{{ proto int ArrayObject::natsort() + proto int ArrayIterator::natsort() + Sort the entries by values using "natural order" algorithm. */ +SPL_ARRAY_METHOD(Array, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */ + +/* {{{ proto int ArrayObject::natcasesort() + proto int ArrayIterator::natcasesort() + Sort the entries by key using case insensitive "natural order" algorithm. */ +SPL_ARRAY_METHOD(Array, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */ + +/* {{{ proto mixed|NULL ArrayIterator::current() + Return current array entry */ +SPL_METHOD(Array, current) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + zval **entry; + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) { + return; + } + + if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { + return; + } + RETVAL_ZVAL(*entry, 1, 0); +} +/* }}} */ + +/* {{{ proto mixed|NULL ArrayIterator::key() + Return current array key */ +SPL_METHOD(Array, key) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + 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; + ulong num_key; + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) { + return; + } + + switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) { + case HASH_KEY_IS_STRING: + RETVAL_STRINGL(string_key, string_length - 1, 0); + break; + case HASH_KEY_IS_LONG: + RETVAL_LONG(num_key); + break; + case HASH_KEY_NON_EXISTANT: + return; + } +} +/* }}} */ + +/* {{{ proto void ArrayIterator::next() + Move to next entry */ +SPL_METHOD(Array, next) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) { + return; + } + + spl_array_next_no_verify(intern, aht TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto bool ArrayIterator::valid() + Check whether array contains more entries */ +SPL_METHOD(Array, valid) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) { + RETURN_FALSE; + } else { + RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS); + } +} +/* }}} */ + +/* {{{ proto bool RecursiveArrayIterator::hasChildren() + Check whether current element has children (e.g. is an array) */ +SPL_METHOD(Array, hasChildren) +{ + zval *object = getThis(), **entry; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) { + RETURN_FALSE; + } + + if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { + RETURN_FALSE; + } + + RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0)); +} +/* }}} */ + +/* {{{ proto object RecursiveArrayIterator::getChildren() + Create a sub iterator for the current element (same class as $this) */ +SPL_METHOD(Array, getChildren) +{ + zval *object = getThis(), **entry, *flags; + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) { + return; + } + + if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) { + return; + } + + if (Z_TYPE_PP(entry) == IS_OBJECT) { + if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) { + return; + } + if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) { + RETURN_ZVAL(*entry, 0, 0); + } + } + + MAKE_STD_ZVAL(flags); + ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags); + spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC); + zval_ptr_dtor(&flags); +} +/* }}} */ + +/* {{{ proto string ArrayObject::serialize() + Serialize the object */ +SPL_METHOD(Array, serialize) +{ + zval *object = getThis(); + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC); + zval members, *pmembers; + php_serialize_data_t var_hash; + smart_str buf = {0}; + zval *flags; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (!aht) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array"); + return; + } + + PHP_VAR_SERIALIZE_INIT(var_hash); + + MAKE_STD_ZVAL(flags); + ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK)); + + /* storage */ + smart_str_appendl(&buf, "x:", 2); + php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC); + zval_ptr_dtor(&flags); + + if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) { + php_var_serialize(&buf, &intern->array, &var_hash TSRMLS_CC); + smart_str_appendc(&buf, ';'); + } + + /* members */ + smart_str_appendl(&buf, "m:", 2); + INIT_PZVAL(&members); + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + Z_ARRVAL(members) = intern->std.properties; + Z_TYPE(members) = IS_ARRAY; + pmembers = &members; + php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */ + + /* done */ + PHP_VAR_SERIALIZE_DESTROY(var_hash); + + if (buf.c) { + RETURN_STRINGL(buf.c, buf.len, 0); + } + + RETURN_NULL(); +} /* }}} */ + +/* {{{ proto void ArrayObject::unserialize(string serialized) + * unserialize the object + */ +SPL_METHOD(Array, unserialize) +{ + spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + char *buf; + int buf_len; + const unsigned char *p, *s; + php_unserialize_data_t var_hash; + zval *pmembers, *pflags = NULL; + long flags; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { + return; + } + + if (buf_len == 0) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty"); + return; + } + + /* storage */ + s = p = (const unsigned char*)buf; + PHP_VAR_UNSERIALIZE_INIT(var_hash); + + if (*p!= 'x' || *++p != ':') { + goto outexcept; + } + ++p; + + ALLOC_INIT_ZVAL(pflags); + if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) { + zval_ptr_dtor(&pflags); + goto outexcept; + } + + --p; /* for ';' */ + flags = Z_LVAL_P(pflags); + zval_ptr_dtor(&pflags); + /* flags needs to be verified and we also need to verify whether the next + * thing we get is ';'. After that we require an 'm' or somethign else + * where 'm' stands for members and anything else should be an array. If + * neither 'a' or 'm' follows we have an error. */ + + if (*p != ';') { + goto outexcept; + } + ++p; + + if (*p!='m') { + if (*p!='a' && *p!='O' && *p!='C') { + goto outexcept; + } + intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK; + intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK; + zval_ptr_dtor(&intern->array); + ALLOC_INIT_ZVAL(intern->array); + if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash TSRMLS_CC)) { + goto outexcept; + } + } + if (*p != ';') { + goto outexcept; + } + ++p; + + /* members */ + if (*p!= 'm' || *++p != ':') { + goto outexcept; + } + ++p; + + ALLOC_INIT_ZVAL(pmembers); + if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&pmembers); + goto outexcept; + } + + /* copy members */ + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *)); + zval_ptr_dtor(&pmembers); + + /* done reading $serialized */ + + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return; + +outexcept: + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len); + return; + +} /* }}} */ + +/* {{{ arginfo and function tbale */ +ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0) + ZEND_ARG_INFO(0, array) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0) + ZEND_ARG_INFO(0, position) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0) + ZEND_ARG_INFO(0, array) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0) + ZEND_ARG_INFO(0, iteratorClass) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0) + ZEND_ARG_INFO(0, cmp_function) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0) +ZEND_END_ARG_INFO() + +static const 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, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC) + SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, ksort, arginfo_array_void, 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, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC) + SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC) + /* ArrayObject specific */ + SPL_ME(Array, getIterator, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC) + SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC) + SPL_ME(Array, getIteratorClass, arginfo_array_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static const 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, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC) + SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, ksort, arginfo_array_void, 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, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC) + SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC) + /* ArrayIterator specific */ + SPL_ME(Array, rewind, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, current, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, key, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, next, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, valid, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = { + SPL_ME(Array, hasChildren, arginfo_array_void, ZEND_ACC_PUBLIC) + SPL_ME(Array, getChildren, arginfo_array_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION(spl_array) */ +PHP_MINIT_FUNCTION(spl_array) +{ + REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject); + REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate); + REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess); + REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable); + REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable); + memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_ArrayObject.clone_obj = spl_array_object_clone; + spl_handler_ArrayObject.read_dimension = spl_array_read_dimension; + spl_handler_ArrayObject.write_dimension = spl_array_write_dimension; + spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension; + spl_handler_ArrayObject.has_dimension = spl_array_has_dimension; + spl_handler_ArrayObject.count_elements = spl_array_object_count_elements; + + spl_handler_ArrayObject.get_properties = spl_array_get_properties; + spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info; + spl_handler_ArrayObject.read_property = spl_array_read_property; + spl_handler_ArrayObject.write_property = spl_array_write_property; + spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr; + spl_handler_ArrayObject.has_property = spl_array_has_property; + spl_handler_ArrayObject.unset_property = spl_array_unset_property; + + spl_handler_ArrayObject.compare_objects = spl_array_compare_objects; + + REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator); + REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator); + REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess); + REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator); + REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable); + REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable); + memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers)); + spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator; + + 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_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST); + REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS); + + REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST); + REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS); + + REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY); + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h new file mode 100644 index 0000000..0423d89 --- /dev/null +++ b/ext/spl/spl_array.h @@ -0,0 +1,46 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_ARRAY_H +#define SPL_ARRAY_H + +#include "php.h" +#include "php_spl.h" +#include "spl_iterators.h" + +extern PHPAPI zend_class_entry *spl_ce_ArrayObject; +extern PHPAPI zend_class_entry *spl_ce_ArrayIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator; + +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 */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c new file mode 100644 index 0000000..f43a370 --- /dev/null +++ b/ext/spl/spl_directory.c @@ -0,0 +1,3068 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "ext/standard/file.h" +#include "ext/standard/php_string.h" +#include "zend_compile.h" +#include "zend_exceptions.h" +#include "zend_interfaces.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_iterators.h" +#include "spl_directory.h" +#include "spl_exceptions.h" + +#include "php.h" +#include "fopen_wrappers.h" + +#include "ext/standard/basic_functions.h" +#include "ext/standard/php_filestat.h" + +#define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0) + +/* declare the class handlers */ +static zend_object_handlers spl_filesystem_object_handlers; +/* includes handler to validate object state when retrieving methods */ +static zend_object_handlers spl_filesystem_object_check_handlers; + +/* decalre the class entry */ +PHPAPI zend_class_entry *spl_ce_SplFileInfo; +PHPAPI zend_class_entry *spl_ce_DirectoryIterator; +PHPAPI zend_class_entry *spl_ce_FilesystemIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator; +PHPAPI zend_class_entry *spl_ce_GlobIterator; +PHPAPI zend_class_entry *spl_ce_SplFileObject; +PHPAPI zend_class_entry *spl_ce_SplTempFileObject; + +static void spl_filesystem_file_free_line(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */ +{ + if (intern->u.file.current_line) { + efree(intern->u.file.current_line); + intern->u.file.current_line = NULL; + } + if (intern->u.file.current_zval) { + zval_ptr_dtor(&intern->u.file.current_zval); + intern->u.file.current_zval = NULL; + } +} /* }}} */ + +static void spl_filesystem_object_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + spl_filesystem_object *intern = (spl_filesystem_object*)object; + + if (intern->oth_handler && intern->oth_handler->dtor) { + intern->oth_handler->dtor(intern TSRMLS_CC); + } + + zend_object_std_dtor(&intern->std TSRMLS_CC); + + if (intern->_path) { + efree(intern->_path); + } + if (intern->file_name) { + efree(intern->file_name); + } + switch(intern->type) { + case SPL_FS_INFO: + break; + case SPL_FS_DIR: + if (intern->u.dir.dirp) { + php_stream_close(intern->u.dir.dirp); + intern->u.dir.dirp = NULL; + } + if (intern->u.dir.sub_path) { + efree(intern->u.dir.sub_path); + } + break; + case SPL_FS_FILE: + if (intern->u.file.stream) { + if (intern->u.file.zcontext) { +/* zend_list_delref(Z_RESVAL_P(intern->zcontext));*/ + } + if (!intern->u.file.stream->is_persistent) { + php_stream_free(intern->u.file.stream, PHP_STREAM_FREE_CLOSE); + } else { + php_stream_free(intern->u.file.stream, PHP_STREAM_FREE_CLOSE_PERSISTENT); + } + if (intern->u.file.open_mode) { + efree(intern->u.file.open_mode); + } + if (intern->orig_path) { + efree(intern->orig_path); + } + } + spl_filesystem_file_free_line(intern TSRMLS_CC); + break; + } + + { + zend_object_iterator *iterator; + iterator = (zend_object_iterator*) + spl_filesystem_object_to_iterator(intern); + if (iterator->data != NULL) { + iterator->data = NULL; + iterator->funcs->dtor(iterator TSRMLS_CC); + } + } + efree(object); +} /* }}} */ + +/* {{{ spl_ce_dir_object_new */ +/* creates the object by + - allocating memory + - initializing the object members + - storing the object + - setting it's handlers + + called from + - clone + - new + */ +static zend_object_value spl_filesystem_object_new_ex(zend_class_entry *class_type, spl_filesystem_object **obj TSRMLS_DC) +{ + zend_object_value retval; + spl_filesystem_object *intern; + + intern = emalloc(sizeof(spl_filesystem_object)); + memset(intern, 0, sizeof(spl_filesystem_object)); + /* intern->type = SPL_FS_INFO; done by set 0 */ + intern->file_class = spl_ce_SplFileObject; + intern->info_class = spl_ce_SplFileInfo; + if (obj) *obj = intern; + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_filesystem_object_free_storage, NULL TSRMLS_CC); + retval.handlers = &spl_filesystem_object_handlers; + return retval; +} +/* }}} */ + +/* {{{ spl_filesystem_object_new */ +/* See spl_filesystem_object_new_ex */ +static zend_object_value spl_filesystem_object_new(zend_class_entry *class_type TSRMLS_DC) +{ + return spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_filesystem_object_new_ex */ +static zend_object_value spl_filesystem_object_new_check(zend_class_entry *class_type TSRMLS_DC) +{ + zend_object_value ret = spl_filesystem_object_new_ex(class_type, NULL TSRMLS_CC); + ret.handlers = &spl_filesystem_object_check_handlers; + return ret; +} +/* }}} */ + + +PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, int *len TSRMLS_DC) /* {{{ */ +{ +#ifdef HAVE_GLOB + if (intern->type == SPL_FS_DIR) { + if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { + return php_glob_stream_get_path(intern->u.dir.dirp, 0, len); + } + } +#endif + if (len) { + *len = intern->_path_len; + } + return intern->_path; +} /* }}} */ + +static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */ +{ + char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH; + + if (!intern->file_name) { + switch (intern->type) { + case SPL_FS_INFO: + case SPL_FS_FILE: + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Object not initialized"); + break; + case SPL_FS_DIR: + intern->file_name_len = spprintf(&intern->file_name, 0, "%s%c%s", + spl_filesystem_object_get_path(intern, NULL TSRMLS_CC), + slash, intern->u.dir.entry.d_name); + break; + } + } +} /* }}} */ + +static int spl_filesystem_dir_read(spl_filesystem_object *intern TSRMLS_DC) /* {{{ */ +{ + if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) { + intern->u.dir.entry.d_name[0] = '\0'; + return 0; + } else { + return 1; + } +} +/* }}} */ + +#define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos])) + +static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */ +{ + return !strcmp(d_name, ".") || !strcmp(d_name, ".."); +} +/* }}} */ + +/* {{{ spl_filesystem_dir_open */ +/* open a directory resource */ +static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path TSRMLS_DC) +{ + int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS); + + intern->type = SPL_FS_DIR; + intern->_path_len = strlen(path); + intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context)); + + if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) { + intern->_path = estrndup(path, --intern->_path_len); + } else { + intern->_path = estrndup(path, intern->_path_len); + } + intern->u.dir.index = 0; + + if (EG(exception) || intern->u.dir.dirp == NULL) { + intern->u.dir.entry.d_name[0] = '\0'; + if (!EG(exception)) { + /* open failed w/out notice (turned to exception due to EH_THROW) */ + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 + TSRMLS_CC, "Failed to open directory \"%s\"", path); + } + } else { + do { + spl_filesystem_dir_read(intern TSRMLS_CC); + } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name)); + } +} +/* }}} */ + +static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_include_path, int silent TSRMLS_DC) /* {{{ */ +{ + zval tmp; + + intern->type = SPL_FS_FILE; + + php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, &tmp TSRMLS_CC); + if (Z_LVAL(tmp)) { + intern->u.file.open_mode = NULL; + intern->file_name = NULL; + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Cannot use SplFileObject with directories"); + return FAILURE; + } + + 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) | REPORT_ERRORS, NULL, intern->u.file.context); + + 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_len ? intern->file_name : ""); + } + intern->file_name = NULL; /* until here it is not a copy */ + intern->u.file.open_mode = NULL; + return FAILURE; + } + + if (intern->u.file.zcontext) { + zend_list_addref(Z_RESVAL_P(intern->u.file.zcontext)); + } + + if (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) { + intern->file_name_len--; + } + + intern->orig_path = estrndup(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path)); + + 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)); + Z_SET_REFCOUNT(intern->u.file.zresource, 1); + + intern->u.file.delimiter = ','; + intern->u.file.enclosure = '"'; + intern->u.file.escape = '\\'; + + zend_hash_find(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline"), (void **) &intern->u.file.func_getCurr); + + return SUCCESS; +} /* }}} */ + +/* {{{ spl_filesystem_object_clone */ +/* Local zend_object_value creation (on stack) + Load the 'other' object + Create a new empty object (See spl_filesystem_object_new_ex) + Open the directory + Clone other members (properties) + */ +static zend_object_value spl_filesystem_object_clone(zval *zobject TSRMLS_DC) +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_filesystem_object *intern; + spl_filesystem_object *source; + int index, skip_dots; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + source = (spl_filesystem_object*)old_object; + + new_obj_val = spl_filesystem_object_new_ex(old_object->ce, &intern TSRMLS_CC); + new_object = &intern->std; + + intern->flags = source->flags; + + switch (source->type) { + case SPL_FS_INFO: + 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; + case SPL_FS_DIR: + spl_filesystem_dir_open(intern, source->_path TSRMLS_CC); + /* read until we hit the position in which we were before */ + skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS); + for(index = 0; index < source->u.dir.index; ++index) { + do { + spl_filesystem_dir_read(intern TSRMLS_CC); + } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name)); + } + intern->u.dir.index = index; + break; + case SPL_FS_FILE: + php_error_docref(NULL TSRMLS_CC, E_ERROR, "An object of class %s cannot be cloned", old_object->ce->name); + break; + } + + intern->file_class = source->file_class; + intern->info_class = source->info_class; + intern->oth = source->oth; + intern->oth_handler = source->oth_handler; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + if (intern->oth_handler && intern->oth_handler->clone) { + intern->oth_handler->clone(source, intern TSRMLS_CC); + } + + return new_obj_val; +} +/* }}} */ + +void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path, int len, int use_copy TSRMLS_DC) /* {{{ */ +{ + char *p1, *p2; + + if (intern->file_name) { + efree(intern->file_name); + } + + intern->file_name = use_copy ? estrndup(path, len) : path; + intern->file_name_len = len; + + while(IS_SLASH_AT(intern->file_name, intern->file_name_len-1) && intern->file_name_len > 1) { + intern->file_name[intern->file_name_len-1] = 0; + intern->file_name_len--; + } + + p1 = strrchr(intern->file_name, '/'); +#if defined(PHP_WIN32) || defined(NETWARE) + p2 = strrchr(intern->file_name, '\\'); +#else + p2 = 0; +#endif + if (p1 || p2) { + intern->_path_len = (p1 > p2 ? p1 : p2) - intern->file_name; + } else { + intern->_path_len = 0; + } + + if (intern->_path) { + efree(intern->_path); + } + intern->_path = estrndup(path, intern->_path_len); +} /* }}} */ + +static spl_filesystem_object * spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, int file_path_len, int use_copy, zend_class_entry *ce, zval *return_value TSRMLS_DC) /* {{{ */ +{ + spl_filesystem_object *intern; + zval *arg1; + zend_error_handling error_handling; + + if (!file_path || !file_path_len) { +#if defined(PHP_WIN32) + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Cannot create SplFileInfo for empty path"); + if (file_path && !use_copy) { + efree(file_path); + } +#else + if (file_path && !use_copy) { + efree(file_path); + } + file_path_len = 1; + file_path = "/"; +#endif + return NULL; + } + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + + ce = ce ? ce : source->info_class; + + zend_update_class_constants(ce TSRMLS_CC); + + return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC); + Z_TYPE_P(return_value) = IS_OBJECT; + + if (ce->constructor->common.scope != spl_ce_SplFileInfo) { + MAKE_STD_ZVAL(arg1); + ZVAL_STRINGL(arg1, file_path, file_path_len, use_copy); + zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1); + zval_ptr_dtor(&arg1); + } else { + spl_filesystem_info_set_filename(intern, file_path, file_path_len, use_copy TSRMLS_CC); + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); + return intern; +} /* }}} */ + +static spl_filesystem_object * spl_filesystem_object_create_type(int ht, spl_filesystem_object *source, int type, zend_class_entry *ce, zval *return_value TSRMLS_DC) /* {{{ */ +{ + spl_filesystem_object *intern; + zend_bool use_include_path = 0; + zval *arg1, *arg2; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + + switch (source->type) { + case SPL_FS_INFO: + case SPL_FS_FILE: + break; + case SPL_FS_DIR: + if (!source->u.dir.entry.d_name[0]) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Could not open file"); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + } + + switch (type) { + case SPL_FS_INFO: + ce = ce ? ce : source->info_class; + + zend_update_class_constants(ce TSRMLS_CC); + + return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC); + Z_TYPE_P(return_value) = IS_OBJECT; + + spl_filesystem_object_get_file_name(source TSRMLS_CC); + if (ce->constructor->common.scope != spl_ce_SplFileInfo) { + MAKE_STD_ZVAL(arg1); + ZVAL_STRINGL(arg1, source->file_name, source->file_name_len, 1); + zend_call_method_with_1_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1); + zval_ptr_dtor(&arg1); + } else { + intern->file_name = estrndup(source->file_name, source->file_name_len); + intern->file_name_len = source->file_name_len; + intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len TSRMLS_CC); + intern->_path = estrndup(intern->_path, intern->_path_len); + } + break; + case SPL_FS_FILE: + ce = ce ? ce : source->file_class; + + zend_update_class_constants(ce TSRMLS_CC); + + return_value->value.obj = spl_filesystem_object_new_ex(ce, &intern TSRMLS_CC); + Z_TYPE_P(return_value) = IS_OBJECT; + + spl_filesystem_object_get_file_name(source TSRMLS_CC); + + if (ce->constructor->common.scope != spl_ce_SplFileObject) { + MAKE_STD_ZVAL(arg1); + MAKE_STD_ZVAL(arg2); + ZVAL_STRINGL(arg1, source->file_name, source->file_name_len, 1); + ZVAL_STRINGL(arg2, "r", 1, 1); + zend_call_method_with_2_params(&return_value, ce, &ce->constructor, "__construct", NULL, arg1, arg2); + zval_ptr_dtor(&arg1); + zval_ptr_dtor(&arg2); + } else { + intern->file_name = source->file_name; + intern->file_name_len = source->file_name_len; + intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len TSRMLS_CC); + intern->_path = estrndup(intern->_path, intern->_path_len); + + intern->u.file.open_mode = "r"; + intern->u.file.open_mode_len = 1; + + if (ht && zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sbr", + &intern->u.file.open_mode, &intern->u.file.open_mode_len, + &use_include_path, &intern->u.file.zcontext) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + intern->u.file.open_mode = NULL; + intern->file_name = NULL; + zval_dtor(return_value); + Z_TYPE_P(return_value) = IS_NULL; + return NULL; + } + + if (spl_filesystem_file_open(intern, use_include_path, 0 TSRMLS_CC) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + zval_dtor(return_value); + Z_TYPE_P(return_value) = IS_NULL; + return NULL; + } + } + break; + case SPL_FS_DIR: + zend_restore_error_handling(&error_handling TSRMLS_CC); + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Operation not supported"); + return NULL; + } + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; +} /* }}} */ + +static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */ +{ + return d_name[0] == '\0' || spl_filesystem_is_dot(d_name); +} +/* }}} */ + +static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, int *len TSRMLS_DC) { /* {{{ */ + switch (intern->type) { + case SPL_FS_INFO: + case SPL_FS_FILE: + *len = intern->file_name_len; + return intern->file_name; + case SPL_FS_DIR: + if (intern->u.dir.entry.d_name[0]) { + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + *len = intern->file_name_len; + return intern->file_name; + } + } + *len = 0; + return NULL; +} +/* }}} */ + +static HashTable* spl_filesystem_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */ +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(obj TSRMLS_CC); + HashTable *rv; + zval *tmp, zrv; + char *pnstr, *path; + int pnlen, path_len; + char stmp[2]; + + *is_temp = 1; + + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + + ALLOC_HASHTABLE(rv); + ZEND_INIT_SYMTABLE_EX(rv, zend_hash_num_elements(intern->std.properties) + 3, 0); + + INIT_PZVAL(&zrv); + Z_ARRVAL(zrv) = rv; + + zend_hash_copy(rv, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1, &pnlen TSRMLS_CC); + path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC); + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, path, path_len, 1); + efree(pnstr); + + if (intern->file_name) { + pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1, &pnlen TSRMLS_CC); + spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC); + + if (path_len && path_len < intern->file_name_len) { + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1), 1); + } else { + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->file_name, intern->file_name_len, 1); + } + efree(pnstr); + } + if (intern->type == SPL_FS_DIR) { +#ifdef HAVE_GLOB + pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1, &pnlen TSRMLS_CC); + if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->_path, intern->_path_len, 1); + } else { + add_assoc_bool_ex(&zrv, pnstr, pnlen+1, 0); + } + efree(pnstr); +#endif + pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1, &pnlen TSRMLS_CC); + if (intern->u.dir.sub_path) { + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->u.dir.sub_path, intern->u.dir.sub_path_len, 1); + } else { + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, "", 0, 1); + } + efree(pnstr); + } + if (intern->type == SPL_FS_FILE) { + pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1, &pnlen TSRMLS_CC); + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, intern->u.file.open_mode, intern->u.file.open_mode_len, 1); + efree(pnstr); + stmp[1] = '\0'; + stmp[0] = intern->u.file.delimiter; + pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1, &pnlen TSRMLS_CC); + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, stmp, 1, 1); + efree(pnstr); + stmp[0] = intern->u.file.enclosure; + pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1, &pnlen TSRMLS_CC); + add_assoc_stringl_ex(&zrv, pnstr, pnlen+1, stmp, 1, 1); + efree(pnstr); + } + + return rv; +} +/* }}} */ + +zend_function *spl_filesystem_object_get_method_check(zval **object_ptr, char *method, int method_len, const struct _zend_literal *key TSRMLS_DC) /* {{{ */ +{ + spl_filesystem_object *fsobj = zend_object_store_get_object(*object_ptr TSRMLS_CC); + + if (fsobj->u.dir.entry.d_name[0] == '\0' && fsobj->orig_path == NULL) { + method = "_bad_state_ex"; + method_len = sizeof("_bad_state_ex") - 1; + key = NULL; + } + + return zend_get_std_object_handlers()->get_method(object_ptr, method, method_len, key TSRMLS_CC); +} +/* }}} */ + +#define DIT_CTOR_FLAGS 0x00000001 +#define DIT_CTOR_GLOB 0x00000002 + +void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, long ctor_flags) /* {{{ */ +{ + spl_filesystem_object *intern; + char *path; + int parsed, len; + long flags; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC); + + if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) { + flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO; + parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &len, &flags); + } else { + flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF; + parsed = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len); + } + if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) { + flags |= SPL_FILE_DIR_SKIPDOTS; + } + if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_UNIXPATHS)) { + flags |= SPL_FILE_DIR_UNIXPATHS; + } + if (parsed == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + if (!len) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Directory name must not be empty."); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + intern->flags = flags; +#ifdef HAVE_GLOB + if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && strstr(path, "glob://") != path) { + spprintf(&path, 0, "glob://%s", path); + spl_filesystem_dir_open(intern, path TSRMLS_CC); + efree(path); + } else +#endif + { + spl_filesystem_dir_open(intern, path TSRMLS_CC); + + } + + intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator TSRMLS_CC) ? 1 : 0; + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void DirectoryIterator::__construct(string path) + Cronstructs a new dir iterator from a path. */ +SPL_METHOD(DirectoryIterator, __construct) +{ + spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto void DirectoryIterator::rewind() + Rewind dir back to the start */ +SPL_METHOD(DirectoryIterator, rewind) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + intern->u.dir.index = 0; + if (intern->u.dir.dirp) { + php_stream_rewinddir(intern->u.dir.dirp); + } + spl_filesystem_dir_read(intern TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto string DirectoryIterator::key() + Return current dir entry */ +SPL_METHOD(DirectoryIterator, key) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (intern->u.dir.dirp) { + RETURN_LONG(intern->u.dir.index); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto DirectoryIterator DirectoryIterator::current() + Return this (needed for Iterator interface) */ +SPL_METHOD(DirectoryIterator, current) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + RETURN_ZVAL(getThis(), 1, 0); +} +/* }}} */ + +/* {{{ proto void DirectoryIterator::next() + Move to next entry */ +SPL_METHOD(DirectoryIterator, next) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + intern->u.dir.index++; + do { + spl_filesystem_dir_read(intern TSRMLS_CC); + } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name)); + if (intern->file_name) { + efree(intern->file_name); + intern->file_name = NULL; + } +} +/* }}} */ + +/* {{{ proto void DirectoryIterator::seek(int position) + Seek to the given position */ +SPL_METHOD(DirectoryIterator, seek) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval *retval = NULL; + long pos; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) { + return; + } + + if (intern->u.dir.index > pos) { + /* we first rewind */ + zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_rewind, "rewind", &retval); + if (retval) { + zval_ptr_dtor(&retval); + } + } + + while (intern->u.dir.index < pos) { + int valid = 0; + zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_valid, "valid", &retval); + if (retval) { + valid = zend_is_true(retval); + zval_ptr_dtor(&retval); + } + if (!valid) { + break; + } + zend_call_method_with_0_params(&this_ptr, Z_OBJCE_P(getThis()), &intern->u.dir.func_next, "next", &retval); + if (retval) { + zval_ptr_dtor(&retval); + } + } +} /* }}} */ + +/* {{{ proto string DirectoryIterator::valid() + Check whether dir contains more entries */ +SPL_METHOD(DirectoryIterator, valid) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0'); +} +/* }}} */ + +/* {{{ proto string SplFileInfo::getPath() + Return the path */ +SPL_METHOD(SplFileInfo, getPath) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *path; + int path_len; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + path = spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC); + RETURN_STRINGL(path, path_len, 1); +} +/* }}} */ + +/* {{{ proto string SplFileInfo::getFilename() + Return filename only */ +SPL_METHOD(SplFileInfo, getFilename) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + int path_len; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC); + + if (path_len && path_len < intern->file_name_len) { + RETURN_STRINGL(intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1), 1); + } else { + RETURN_STRINGL(intern->file_name, intern->file_name_len, 1); + } +} +/* }}} */ + +/* {{{ proto string DirectoryIterator::getFilename() + Return filename of current dir entry */ +SPL_METHOD(DirectoryIterator, getFilename) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_STRING(intern->u.dir.entry.d_name, 1); +} +/* }}} */ + +/* {{{ proto string SplFileInfo::getExtension() + Returns file extension component of path */ +SPL_METHOD(SplFileInfo, getExtension) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *fname = NULL; + const char *p; + size_t flen; + int path_len, idx; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC); + + if (path_len && path_len < intern->file_name_len) { + fname = intern->file_name + path_len + 1; + flen = intern->file_name_len - (path_len + 1); + } else { + fname = intern->file_name; + flen = intern->file_name_len; + } + + php_basename(fname, flen, NULL, 0, &fname, &flen TSRMLS_CC); + + p = zend_memrchr(fname, '.', flen); + if (p) { + idx = p - fname; + RETVAL_STRINGL(fname + idx + 1, flen - idx - 1, 1); + efree(fname); + return; + } else { + if (fname) { + efree(fname); + } + RETURN_EMPTY_STRING(); + } +} +/* }}}*/ + +/* {{{ proto string DirectoryIterator::getExtension() + Returns the file extension component of path */ +SPL_METHOD(DirectoryIterator, getExtension) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *fname = NULL; + const char *p; + size_t flen; + int idx; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0, &fname, &flen TSRMLS_CC); + + p = zend_memrchr(fname, '.', flen); + if (p) { + idx = p - fname; + RETVAL_STRINGL(fname + idx + 1, flen - idx - 1, 1); + efree(fname); + return; + } else { + if (fname) { + efree(fname); + } + RETURN_EMPTY_STRING(); + } +} +/* }}} */ + +/* {{{ proto string SplFileInfo::getBasename([string $suffix]) U + Returns filename component of path */ +SPL_METHOD(SplFileInfo, getBasename) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *fname, *suffix = 0; + size_t flen; + int slen = 0, path_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &suffix, &slen) == FAILURE) { + return; + } + + spl_filesystem_object_get_path(intern, &path_len TSRMLS_CC); + + if (path_len && path_len < intern->file_name_len) { + fname = intern->file_name + path_len + 1; + flen = intern->file_name_len - (path_len + 1); + } else { + fname = intern->file_name; + flen = intern->file_name_len; + } + + php_basename(fname, flen, suffix, slen, &fname, &flen TSRMLS_CC); + + RETURN_STRINGL(fname, flen, 0); +} +/* }}}*/ + +/* {{{ proto string DirectoryIterator::getBasename([string $suffix]) U + Returns filename component of current dir entry */ +SPL_METHOD(DirectoryIterator, getBasename) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *suffix = 0, *fname; + int slen = 0; + size_t flen; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &suffix, &slen) == FAILURE) { + return; + } + + php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen, &fname, &flen TSRMLS_CC); + + RETURN_STRINGL(fname, flen, 0); +} +/* }}} */ + +/* {{{ proto string SplFileInfo::getPathname() + Return path and filename */ +SPL_METHOD(SplFileInfo, getPathname) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *path; + int path_len; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC); + if (path != NULL) { + RETURN_STRINGL(path, path_len, 1); + } else { + RETURN_FALSE; + } +} +/* }}} */ + +/* {{{ proto string FilesystemIterator::key() + Return getPathname() or getFilename() depending on flags */ +SPL_METHOD(FilesystemIterator, key) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) { + RETURN_STRING(intern->u.dir.entry.d_name, 1); + } else { + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + RETURN_STRINGL(intern->file_name, intern->file_name_len, 1); + } +} +/* }}} */ + +/* {{{ proto string FilesystemIterator::current() + Return getFilename(), getFileInfo() or $this depending on flags */ +SPL_METHOD(FilesystemIterator, current) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) { + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + RETURN_STRINGL(intern->file_name, intern->file_name_len, 1); + } else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) { + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value TSRMLS_CC); + } else { + RETURN_ZVAL(getThis(), 1, 0); + /*RETURN_STRING(intern->u.dir.entry.d_name, 1);*/ + } +} +/* }}} */ + +/* {{{ proto bool DirectoryIterator::isDot() + Returns true if current entry is '.' or '..' */ +SPL_METHOD(DirectoryIterator, isDot) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name)); +} +/* }}} */ + +/* {{{ proto void SplFileInfo::__construct(string file_name) + Cronstructs a new SplFileInfo from a path. */ +/* zend_replace_error_handling() is used to throw exceptions in case + the constructor fails. Here we use this to ensure the object + has a valid directory resource. + + When the constructor gets called the object is already created + by the engine, so we must only call 'additional' initializations. + */ +SPL_METHOD(SplFileInfo, __construct) +{ + spl_filesystem_object *intern; + char *path; + int len; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &len) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_filesystem_info_set_filename(intern, path, len, 1 TSRMLS_CC); + + zend_restore_error_handling(&error_handling TSRMLS_CC); + + /* intern->type = SPL_FS_INFO; already set */ +} +/* }}} */ + +/* {{{ FileInfoFunction */ +#define FileInfoFunction(func_name, func_num) \ +SPL_METHOD(SplFileInfo, func_name) \ +{ \ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); \ + zend_error_handling error_handling; \ + if (zend_parse_parameters_none() == FAILURE) { \ + return; \ + } \ + \ + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC);\ + spl_filesystem_object_get_file_name(intern TSRMLS_CC); \ + php_stat(intern->file_name, intern->file_name_len, func_num, return_value TSRMLS_CC); \ + zend_restore_error_handling(&error_handling TSRMLS_CC); \ +} +/* }}} */ + +/* {{{ proto int SplFileInfo::getPerms() + Get file permissions */ +FileInfoFunction(getPerms, FS_PERMS) +/* }}} */ + +/* {{{ proto int SplFileInfo::getInode() + Get file inode */ +FileInfoFunction(getInode, FS_INODE) +/* }}} */ + +/* {{{ proto int SplFileInfo::getSize() + Get file size */ +FileInfoFunction(getSize, FS_SIZE) +/* }}} */ + +/* {{{ proto int SplFileInfo::getOwner() + Get file owner */ +FileInfoFunction(getOwner, FS_OWNER) +/* }}} */ + +/* {{{ proto int SplFileInfo::getGroup() + Get file group */ +FileInfoFunction(getGroup, FS_GROUP) +/* }}} */ + +/* {{{ proto int SplFileInfo::getATime() + Get last access time of file */ +FileInfoFunction(getATime, FS_ATIME) +/* }}} */ + +/* {{{ proto int SplFileInfo::getMTime() + Get last modification time of file */ +FileInfoFunction(getMTime, FS_MTIME) +/* }}} */ + +/* {{{ proto int SplFileInfo::getCTime() + Get inode modification time of file */ +FileInfoFunction(getCTime, FS_CTIME) +/* }}} */ + +/* {{{ proto string SplFileInfo::getType() + Get file type */ +FileInfoFunction(getType, FS_TYPE) +/* }}} */ + +/* {{{ proto bool SplFileInfo::isWritable() + Returns true if file can be written */ +FileInfoFunction(isWritable, FS_IS_W) +/* }}} */ + +/* {{{ proto bool SplFileInfo::isReadable() + Returns true if file can be read */ +FileInfoFunction(isReadable, FS_IS_R) +/* }}} */ + +/* {{{ proto bool SplFileInfo::isExecutable() + Returns true if file is executable */ +FileInfoFunction(isExecutable, FS_IS_X) +/* }}} */ + +/* {{{ proto bool SplFileInfo::isFile() + Returns true if file is a regular file */ +FileInfoFunction(isFile, FS_IS_FILE) +/* }}} */ + +/* {{{ proto bool SplFileInfo::isDir() + Returns true if file is directory */ +FileInfoFunction(isDir, FS_IS_DIR) +/* }}} */ + +/* {{{ proto bool SplFileInfo::isLink() + Returns true if file is symbolic link */ +FileInfoFunction(isLink, FS_IS_LINK) +/* }}} */ + +/* {{{ proto string SplFileInfo::getLinkTarget() U + Return the target of a symbolic link */ +SPL_METHOD(SplFileInfo, getLinkTarget) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + int ret; + char buff[MAXPATHLEN]; + zend_error_handling error_handling; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + +#if defined(PHP_WIN32) || HAVE_SYMLINK + if (intern->file_name == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty filename"); + RETURN_FALSE; + } else if (!IS_ABSOLUTE_PATH(intern->file_name, intern->file_name_len)) { + char expanded_path[MAXPATHLEN]; + if (!expand_filepath_with_mode(intern->file_name, expanded_path, NULL, 0, CWD_EXPAND TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory"); + RETURN_FALSE; + } + ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1); + } else { + ret = php_sys_readlink(intern->file_name, buff, MAXPATHLEN-1); + } +#else + ret = -1; /* always fail if not implemented */ +#endif + + if (ret == -1) { + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Unable to read link %s, error: %s", intern->file_name, strerror(errno)); + RETVAL_FALSE; + } else { + /* Append NULL to the end of the string */ + buff[ret] = '\0'; + + RETVAL_STRINGL(buff, ret, 1); + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +#if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +/* {{{ proto string SplFileInfo::getRealPath() + Return the resolved path */ +SPL_METHOD(SplFileInfo, getRealPath) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char buff[MAXPATHLEN]; + char *filename; + zend_error_handling error_handling; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + + if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) { + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + } + + if (intern->orig_path) { + filename = intern->orig_path; + } else { + filename = intern->file_name; + } + + + if (filename && VCWD_REALPATH(filename, buff)) { +#ifdef ZTS + if (VCWD_ACCESS(buff, F_OK)) { + RETVAL_FALSE; + } else +#endif + RETVAL_STRING(buff, 1); + } else { + RETVAL_FALSE; + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ +#endif + +/* {{{ proto SplFileObject SplFileInfo::openFile([string mode = 'r' [, bool use_include_path [, resource context]]]) + Open the current file */ +SPL_METHOD(SplFileInfo, openFile) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_filesystem_object_create_type(ht, intern, SPL_FS_FILE, NULL, return_value TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void SplFileInfo::setFileClass([string class_name]) + Class to use in openFile() */ +SPL_METHOD(SplFileInfo, setFileClass) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_class_entry *ce = spl_ce_SplFileObject; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + intern->file_class = ce; + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void SplFileInfo::setInfoClass([string class_name]) + Class to use in getFileInfo(), getPathInfo() */ +SPL_METHOD(SplFileInfo, setInfoClass) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_class_entry *ce = spl_ce_SplFileInfo; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + intern->info_class = ce; + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto SplFileInfo SplFileInfo::getFileInfo([string $class_name]) + Get/copy file info */ +SPL_METHOD(SplFileInfo, getFileInfo) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_class_entry *ce = intern->info_class; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + spl_filesystem_object_create_type(ht, intern, SPL_FS_INFO, ce, return_value TSRMLS_CC); + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto SplFileInfo SplFileInfo::getPathInfo([string $class_name]) + Get/copy file info */ +SPL_METHOD(SplFileInfo, getPathInfo) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_class_entry *ce = intern->info_class; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|C", &ce) == SUCCESS) { + int path_len; + char *path = spl_filesystem_object_get_pathname(intern, &path_len TSRMLS_CC); + if (path) { + char *dpath = estrndup(path, path_len); + path_len = php_dirname(dpath, path_len); + spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value TSRMLS_CC); + efree(dpath); + } + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +/* {{{ */ +SPL_METHOD(SplFileInfo, _bad_state_ex) +{ + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, + "The parent constructor was not called: the object is in an " + "invalid state "); +} +/* }}} */ + +/* {{{ proto void FilesystemIterator::__construct(string path [, int flags]) + Cronstructs a new dir iterator from a path. */ +SPL_METHOD(FilesystemIterator, __construct) +{ + spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS); +} +/* }}} */ + +/* {{{ proto void FilesystemIterator::rewind() + Rewind dir back to the start */ +SPL_METHOD(FilesystemIterator, rewind) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + intern->u.dir.index = 0; + if (intern->u.dir.dirp) { + php_stream_rewinddir(intern->u.dir.dirp); + } + do { + spl_filesystem_dir_read(intern TSRMLS_CC); + } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name)); +} +/* }}} */ + +/* {{{ proto int FilesystemIterator::getFlags() + Get handling flags */ +SPL_METHOD(FilesystemIterator, getFlags) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK)); +} /* }}} */ + +/* {{{ proto void FilesystemIterator::setFlags(long $flags) + Set handling flags */ +SPL_METHOD(FilesystemIterator, setFlags) +{ + spl_filesystem_object *intern = (spl_filesystem_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->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK); + intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags); +} /* }}} */ + +/* {{{ proto bool RecursiveDirectoryIterator::hasChildren([bool $allow_links = false]) + Returns whether current entry is a directory and not '.' or '..' */ +SPL_METHOD(RecursiveDirectoryIterator, hasChildren) +{ + zend_bool allow_links = 0; + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &allow_links) == FAILURE) { + return; + } + if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) { + RETURN_FALSE; + } else { + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + if (!allow_links && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) { + php_stat(intern->file_name, intern->file_name_len, FS_IS_LINK, return_value TSRMLS_CC); + if (zend_is_true(return_value)) { + RETURN_FALSE; + } + } + php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, return_value TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ proto RecursiveDirectoryIterator DirectoryIterator::getChildren() + Returns an iterator for the current entry if it is a directory */ +SPL_METHOD(RecursiveDirectoryIterator, getChildren) +{ + zval zpath, zflags; + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_filesystem_object *subdir; + char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_filesystem_object_get_file_name(intern TSRMLS_CC); + + if (SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) { + RETURN_STRINGL(intern->file_name, intern->file_name_len, 1); + } else { + INIT_PZVAL(&zflags); + INIT_PZVAL(&zpath); + ZVAL_LONG(&zflags, intern->flags); + ZVAL_STRINGL(&zpath, intern->file_name, intern->file_name_len, 0); + spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, &zpath, &zflags TSRMLS_CC); + + subdir = (spl_filesystem_object*)zend_object_store_get_object(return_value TSRMLS_CC); + if (subdir) { + if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) { + subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name); + } else { + subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name); + subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len); + } + subdir->info_class = intern->info_class; + subdir->file_class = intern->file_class; + subdir->oth = intern->oth; + } + } +} +/* }}} */ + +/* {{{ proto void RecursiveDirectoryIterator::getSubPath() + Get sub path */ +SPL_METHOD(RecursiveDirectoryIterator, getSubPath) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (intern->u.dir.sub_path) { + RETURN_STRINGL(intern->u.dir.sub_path, intern->u.dir.sub_path_len, 1); + } else { + RETURN_STRINGL("", 0, 1); + } +} +/* }}} */ + +/* {{{ proto void RecursiveDirectoryIterator::getSubPathname() + Get sub path and file name */ +SPL_METHOD(RecursiveDirectoryIterator, getSubPathname) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *sub_name; + int len; + char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (intern->u.dir.sub_path) { + len = spprintf(&sub_name, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name); + RETURN_STRINGL(sub_name, len, 0); + } else { + RETURN_STRING(intern->u.dir.entry.d_name, 1); + } +} +/* }}} */ + +/* {{{ proto int RecursiveDirectoryIterator::__construct(string path [, int flags]) + Cronstructs a new dir iterator from a path. */ +SPL_METHOD(RecursiveDirectoryIterator, __construct) +{ + spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS); +} +/* }}} */ + +#ifdef HAVE_GLOB +/* {{{ proto int GlobIterator::__construct(string path [, int flags]) + Cronstructs a new dir iterator from a glob expression (no glob:// needed). */ +SPL_METHOD(GlobIterator, __construct) +{ + spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB); +} +/* }}} */ + +/* {{{ proto int GlobIterator::cont() + Return the number of directories and files found by globbing */ +SPL_METHOD(GlobIterator, count) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) { + RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL)); + } else { + /* should not happen */ + php_error_docref(NULL TSRMLS_CC, E_ERROR, "GlobIterator lost glob state"); + } +} +/* }}} */ +#endif /* HAVE_GLOB */ + +/* {{{ forward declarations to the iterator handlers */ +static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC); +static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC); +static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC); +static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); +static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC); +static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC); + +/* iterator handler table */ +zend_object_iterator_funcs spl_filesystem_dir_it_funcs = { + spl_filesystem_dir_it_dtor, + spl_filesystem_dir_it_valid, + spl_filesystem_dir_it_current_data, + spl_filesystem_dir_it_current_key, + spl_filesystem_dir_it_move_forward, + spl_filesystem_dir_it_rewind +}; +/* }}} */ + +/* {{{ spl_ce_dir_get_iterator */ +zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) +{ + spl_filesystem_iterator *iterator; + spl_filesystem_object *dir_object; + + if (by_ref) { + zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); + } + dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC); + iterator = spl_filesystem_object_to_iterator(dir_object); + + /* initialize iterator if it wasn't gotten before */ + if (iterator->intern.data == NULL) { + iterator->intern.data = object; + iterator->intern.funcs = &spl_filesystem_dir_it_funcs; + /* ->current must be initialized; rewind doesn't set it and valid + * doesn't check whether it's set */ + iterator->current = object; + } + zval_add_ref(&object); + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +/* {{{ spl_filesystem_dir_it_dtor */ +static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter; + + if (iterator->intern.data) { + zval *object = iterator->intern.data; + zval_ptr_dtor(&object); + } + /* Otherwise we were called from the owning object free storage handler as + * it sets + * iterator->intern.data to NULL. + * We don't even need to destroy iterator->current as we didn't add a + * reference to it in move_forward or get_iterator */ +} +/* }}} */ + +/* {{{ spl_filesystem_dir_it_valid */ +static int spl_filesystem_dir_it_valid(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); + + return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE; +} +/* }}} */ + +/* {{{ spl_filesystem_dir_it_current_data */ +static void spl_filesystem_dir_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter; + + *data = &iterator->current; +} +/* }}} */ + +/* {{{ spl_filesystem_dir_it_current_key */ +static int spl_filesystem_dir_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); + + *int_key = object->u.dir.index; + return HASH_KEY_IS_LONG; +} +/* }}} */ + +/* {{{ spl_filesystem_dir_it_move_forward */ +static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); + + object->u.dir.index++; + spl_filesystem_dir_read(object TSRMLS_CC); + if (object->file_name) { + efree(object->file_name); + object->file_name = NULL; + } +} +/* }}} */ + +/* {{{ spl_filesystem_dir_it_rewind */ +static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); + + object->u.dir.index = 0; + if (object->u.dir.dirp) { + php_stream_rewinddir(object->u.dir.dirp); + } + spl_filesystem_dir_read(object TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_filesystem_tree_it_dtor */ +static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter; + + if (iterator->intern.data) { + zval *object = iterator->intern.data; + zval_ptr_dtor(&object); + } else { + if (iterator->current) { + zval_ptr_dtor(&iterator->current); + } + } +} +/* }}} */ + +/* {{{ spl_filesystem_tree_it_current_data */ +static void spl_filesystem_tree_it_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter; + spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator); + + if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) { + if (!iterator->current) { + ALLOC_INIT_ZVAL(iterator->current); + spl_filesystem_object_get_file_name(object TSRMLS_CC); + ZVAL_STRINGL(iterator->current, object->file_name, object->file_name_len, 1); + } + *data = &iterator->current; + } else if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) { + if (!iterator->current) { + ALLOC_INIT_ZVAL(iterator->current); + spl_filesystem_object_get_file_name(object TSRMLS_CC); + spl_filesystem_object_create_type(0, object, SPL_FS_INFO, NULL, iterator->current TSRMLS_CC); + } + *data = &iterator->current; + } else { + *data = (zval**)&iterator->intern.data; + } +} +/* }}} */ + +/* {{{ spl_filesystem_tree_it_current_key */ +static int spl_filesystem_tree_it_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter); + + if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) { + *str_key_len = strlen(object->u.dir.entry.d_name) + 1; + *str_key = estrndup(object->u.dir.entry.d_name, *str_key_len - 1); + } else { + spl_filesystem_object_get_file_name(object TSRMLS_CC); + *str_key_len = object->file_name_len + 1; + *str_key = estrndup(object->file_name, object->file_name_len); + } + return HASH_KEY_IS_STRING; +} +/* }}} */ + +/* {{{ spl_filesystem_tree_it_move_forward */ +static void spl_filesystem_tree_it_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter; + spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator); + + object->u.dir.index++; + do { + spl_filesystem_dir_read(object TSRMLS_CC); + } while (spl_filesystem_is_dot(object->u.dir.entry.d_name)); + if (object->file_name) { + efree(object->file_name); + object->file_name = NULL; + } + if (iterator->current) { + zval_ptr_dtor(&iterator->current); + iterator->current = NULL; + } +} +/* }}} */ + +/* {{{ spl_filesystem_tree_it_rewind */ +static void spl_filesystem_tree_it_rewind(zend_object_iterator *iter TSRMLS_DC) +{ + spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter; + spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator); + + object->u.dir.index = 0; + if (object->u.dir.dirp) { + php_stream_rewinddir(object->u.dir.dirp); + } + do { + spl_filesystem_dir_read(object TSRMLS_CC); + } while (spl_filesystem_is_dot(object->u.dir.entry.d_name)); + if (iterator->current) { + zval_ptr_dtor(&iterator->current); + iterator->current = NULL; + } +} +/* }}} */ + +/* {{{ iterator handler table */ +zend_object_iterator_funcs spl_filesystem_tree_it_funcs = { + spl_filesystem_tree_it_dtor, + spl_filesystem_dir_it_valid, + spl_filesystem_tree_it_current_data, + spl_filesystem_tree_it_current_key, + spl_filesystem_tree_it_move_forward, + spl_filesystem_tree_it_rewind +}; +/* }}} */ + +/* {{{ spl_ce_dir_get_iterator */ +zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) +{ + spl_filesystem_iterator *iterator; + spl_filesystem_object *dir_object; + + if (by_ref) { + zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); + } + dir_object = (spl_filesystem_object*)zend_object_store_get_object(object TSRMLS_CC); + iterator = spl_filesystem_object_to_iterator(dir_object); + + /* initialize iterator if wasn't gotten before */ + if (iterator->intern.data == NULL) { + iterator->intern.data = object; + iterator->intern.funcs = &spl_filesystem_tree_it_funcs; + } + zval_add_ref(&object); + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +/* {{{ spl_filesystem_object_cast */ +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 (type == IS_STRING) { + if (Z_OBJCE_P(readobj)->__tostring) { + return std_object_handlers.cast_object(readobj, writeobj, type TSRMLS_CC); + } + + switch (intern->type) { + case SPL_FS_INFO: + case SPL_FS_FILE: + if (readobj == writeobj) { + zval retval; + zval *retval_ptr = &retval; + + ZVAL_STRINGL(retval_ptr, intern->file_name, intern->file_name_len, 1); + zval_dtor(readobj); + ZVAL_ZVAL(writeobj, retval_ptr, 0, 0); + } else { + ZVAL_STRINGL(writeobj, intern->file_name, intern->file_name_len, 1); + } + return SUCCESS; + case SPL_FS_DIR: + if (readobj == writeobj) { + zval retval; + zval *retval_ptr = &retval; + + ZVAL_STRING(retval_ptr, intern->u.dir.entry.d_name, 1); + zval_dtor(readobj); + ZVAL_ZVAL(writeobj, retval_ptr, 0, 0); + } else { + ZVAL_STRING(writeobj, intern->u.dir.entry.d_name, 1); + } + return SUCCESS; + } + } + if (readobj == writeobj) { + zval_dtor(readobj); + } + ZVAL_NULL(writeobj); + return FAILURE; +} +/* }}} */ + +/* {{{ declare method parameters */ +/* supply a name and default to call by parameter */ +ZEND_BEGIN_ARG_INFO(arginfo_info___construct, 0) + ZEND_ARG_INFO(0, file_name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_info_openFile, 0, 0, 0) + ZEND_ARG_INFO(0, open_mode) + ZEND_ARG_INFO(0, use_include_path) + ZEND_ARG_INFO(0, context) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_info_optinalFileClass, 0, 0, 0) + ZEND_ARG_INFO(0, class_name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_optinalSuffix, 0, 0, 0) + ZEND_ARG_INFO(0, suffix) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_splfileinfo_void, 0) +ZEND_END_ARG_INFO() + +/* the method table */ +/* each method can have its own parameters and visibility */ +static const zend_function_entry spl_SplFileInfo_functions[] = { + SPL_ME(SplFileInfo, __construct, arginfo_info___construct, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getPath, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getExtension, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getBasename, arginfo_optinalSuffix, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getPerms, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getInode, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getSize, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getOwner, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getGroup, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getATime, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getMTime, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getCTime, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getType, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, isWritable, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, isReadable, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, isExecutable, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, isFile, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, isDir, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, isLink, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getLinkTarget, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) +#if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + SPL_ME(SplFileInfo, getRealPath, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) +#endif + SPL_ME(SplFileInfo, getFileInfo, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, getPathInfo, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, openFile, arginfo_info_openFile, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, setFileClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, setInfoClass, arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC) + SPL_ME(SplFileInfo, _bad_state_ex, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + SPL_MA(SplFileInfo, __toString, SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0) + ZEND_ARG_INFO(0, path) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_dir_it_seek, 0) + ZEND_ARG_INFO(0, position) +ZEND_END_ARG_INFO(); + +/* the method table */ +/* each method can have its own parameters and visibility */ +static const zend_function_entry spl_DirectoryIterator_functions[] = { + SPL_ME(DirectoryIterator, __construct, arginfo_dir___construct, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, getExtension, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, getBasename, arginfo_optinalSuffix, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, isDot, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, rewind, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, valid, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, key, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, next, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, seek, arginfo_dir_it_seek, ZEND_ACC_PUBLIC) + SPL_MA(DirectoryIterator, __toString, DirectoryIterator, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir___construct, 0, 0, 1) + ZEND_ARG_INFO(0, path) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_hasChildren, 0, 0, 0) + ZEND_ARG_INFO(0, allow_links) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_setFlags, 0, 0, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() + +static const zend_function_entry spl_FilesystemIterator_functions[] = { + SPL_ME(FilesystemIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC) + SPL_ME(FilesystemIterator, rewind, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(DirectoryIterator, next, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(FilesystemIterator, key, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(FilesystemIterator, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(FilesystemIterator, getFlags, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(FilesystemIterator, setFlags, arginfo_r_dir_setFlags, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static const zend_function_entry spl_RecursiveDirectoryIterator_functions[] = { + SPL_ME(RecursiveDirectoryIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveDirectoryIterator, hasChildren, arginfo_r_dir_hasChildren, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveDirectoryIterator, getChildren, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveDirectoryIterator, getSubPath, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveDirectoryIterator, getSubPathname,arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +#ifdef HAVE_GLOB +static const zend_function_entry spl_GlobIterator_functions[] = { + SPL_ME(GlobIterator, __construct, arginfo_r_dir___construct, ZEND_ACC_PUBLIC) + SPL_ME(GlobIterator, count, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +#endif +/* }}} */ + +static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent TSRMLS_DC) /* {{{ */ +{ + char *buf; + size_t line_len = 0; + long line_add = (intern->u.file.current_line || intern->u.file.current_zval) ? 1 : 0; + + spl_filesystem_file_free_line(intern TSRMLS_CC); + + 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; + } + + if (intern->u.file.max_line_len > 0) { + buf = safe_emalloc((intern->u.file.max_line_len + 1), sizeof(char), 0); + if (php_stream_get_line(intern->u.file.stream, buf, intern->u.file.max_line_len, &line_len) == NULL) { + efree(buf); + buf = NULL; + } else { + buf[line_len] = '\0'; + } + } else { + buf = php_stream_get_line(intern->u.file.stream, NULL, 0, &line_len); + } + + if (!buf) { + intern->u.file.current_line = estrdup(""); + intern->u.file.current_line_len = 0; + } else { + if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) { + line_len = strcspn(buf, "\r\n"); + buf[line_len] = '\0'; + } + + intern->u.file.current_line = buf; + intern->u.file.current_line_len = line_len; + } + intern->u.file.current_line_num += line_add; + + return SUCCESS; +} /* }}} */ + +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_ptr = 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.called_scope = NULL; + fcic.object_ptr = NULL; + + result = zend_call_function(&fci, &fcic TSRMLS_CC); + + if (result == FAILURE) { + RETVAL_FALSE; + } else { + ZVAL_ZVAL(return_value, retval, 1, 1); + } + + efree(params); + return result; +} /* }}} */ + +#define FileFunctionCall(func_name, pass_num_args, arg2) /* {{{ */ \ +{ \ + zend_function *func_ptr; \ + int ret; \ + ret = zend_hash_find(EG(function_table), #func_name, sizeof(#func_name), (void **) &func_ptr); \ + if (ret != SUCCESS) { \ + zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Internal error, function '%s' not found. Please report", #func_name); \ + return; \ + } \ + 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, char escape, 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 && SPL_HAS_FLAG(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, escape, 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; + + /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */ + if (SPL_HAS_FLAG(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; + } + if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) { + return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, 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++; + } + spl_filesystem_file_free_line(intern TSRMLS_CC); + if (Z_TYPE_P(retval) == IS_STRING) { + intern->u.file.current_line = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); + intern->u.file.current_line_len = Z_STRLEN_P(retval); + } else { + MAKE_STD_ZVAL(intern->u.file.current_zval); + ZVAL_ZVAL(intern->u.file.current_zval, retval, 1, 0); + } + zval_ptr_dtor(&retval); + return SUCCESS; + } else { + return FAILURE; + } + } else { + return spl_filesystem_file_read(intern, silent TSRMLS_CC); + } +} /* }}} */ + +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 (SPL_HAS_FLAG(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 (SPL_HAS_FLAG(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); + } else { + spl_filesystem_file_free_line(intern TSRMLS_CC); + intern->u.file.current_line_num = 0; + } + if (SPL_HAS_FLAG(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]]]]) + Construct a new file object */ +SPL_METHOD(SplFileObject, __construct) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_bool use_include_path = 0; + char *p1, *p2; + char *tmp_path; + int tmp_path_len; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + + intern->u.file.open_mode = NULL; + intern->u.file.open_mode_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|sbr", + &intern->file_name, &intern->file_name_len, + &intern->u.file.open_mode, &intern->u.file.open_mode_len, + &use_include_path, &intern->u.file.zcontext) == FAILURE) { + intern->u.file.open_mode = NULL; + intern->file_name = NULL; + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + if (intern->u.file.open_mode == NULL) { + intern->u.file.open_mode = "r"; + intern->u.file.open_mode_len = 1; + } + + if (spl_filesystem_file_open(intern, use_include_path, 0 TSRMLS_CC) == SUCCESS) { + tmp_path_len = strlen(intern->u.file.stream->orig_path); + + if (tmp_path_len > 1 && IS_SLASH_AT(intern->u.file.stream->orig_path, tmp_path_len-1)) { + tmp_path_len--; + } + + tmp_path = estrndup(intern->u.file.stream->orig_path, tmp_path_len); + + p1 = strrchr(tmp_path, '/'); +#if defined(PHP_WIN32) || defined(NETWARE) + p2 = strrchr(tmp_path, '\\'); +#else + p2 = 0; +#endif + if (p1 || p2) { + intern->_path_len = (p1 > p2 ? p1 : p2) - tmp_path; + } else { + intern->_path_len = 0; + } + + efree(tmp_path); + + intern->_path = estrndup(intern->u.file.stream->orig_path, intern->_path_len); + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); + +} /* }}} */ + +/* {{{ proto void SplTempFileObject::__construct([int max_memory]) + Construct a new temp file object */ +SPL_METHOD(SplTempFileObject, __construct) +{ + long max_memory = PHP_STREAM_MAX_MEM; + char tmp_fname[48]; + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_memory) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + if (max_memory < 0) { + intern->file_name = "php://memory"; + intern->file_name_len = 12; + } else if (ZEND_NUM_ARGS()) { + intern->file_name_len = slprintf(tmp_fname, sizeof(tmp_fname), "php://temp/maxmemory:%ld", max_memory); + intern->file_name = tmp_fname; + } else { + intern->file_name = "php://temp"; + intern->file_name_len = 10; + } + intern->u.file.open_mode = "wb"; + intern->u.file.open_mode_len = 1; + intern->u.file.zcontext = NULL; + + if (spl_filesystem_file_open(intern, 0, 0 TSRMLS_CC) == SUCCESS) { + intern->_path_len = 0; + intern->_path = estrndup("", 0); + } + zend_restore_error_handling(&error_handling TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void SplFileObject::rewind() + Rewind the file and read the first line */ +SPL_METHOD(SplFileObject, rewind) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void SplFileObject::eof() + Return whether end of file is reached */ +SPL_METHOD(SplFileObject, eof) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(php_stream_eof(intern->u.file.stream)); +} /* }}} */ + +/* {{{ proto void SplFileObject::valid() + Return !eof() */ +SPL_METHOD(SplFileObject, valid) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (SPL_HAS_FLAG(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() + Rturn next line from file */ +SPL_METHOD(SplFileObject, fgets) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (spl_filesystem_file_read(intern, 0 TSRMLS_CC) == FAILURE) { + RETURN_FALSE; + } + RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len, 1); +} /* }}} */ + +/* {{{ proto string SplFileObject::current() + Return current line from file */ +SPL_METHOD(SplFileObject, current) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + 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 && (!SPL_HAS_FLAG(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); + } + RETURN_FALSE; +} /* }}} */ + +/* {{{ proto int SplFileObject::key() + Return line number */ +SPL_METHOD(SplFileObject, key) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + +/* Do not read the next line to support correct counting with fgetc() + if (!intern->current_line) { + spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC); + } */ + RETURN_LONG(intern->u.file.current_line_num); +} /* }}} */ + +/* {{{ proto void SplFileObject::next() + Read next line */ +SPL_METHOD(SplFileObject, next) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_filesystem_file_free_line(intern TSRMLS_CC); + if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { + spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC); + } + intern->u.file.current_line_num++; +} /* }}} */ + +/* {{{ proto void SplFileObject::setFlags(int flags) + Set file handling flags */ +SPL_METHOD(SplFileObject, setFlags) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) { + return; + } +} /* }}} */ + +/* {{{ proto int SplFileObject::getFlags() + Get file handling flags */ +SPL_METHOD(SplFileObject, getFlags) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK); +} /* }}} */ + +/* {{{ proto void SplFileObject::setMaxLineLen(int max_len) + Set maximum line length */ +SPL_METHOD(SplFileObject, setMaxLineLen) +{ + long max_len; + + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &max_len) == FAILURE) { + return; + } + + if (max_len < 0) { + zend_throw_exception_ex(spl_ce_DomainException, 0 TSRMLS_CC, "Maximum line length must be greater than or equal zero"); + return; + } + + intern->u.file.max_line_len = max_len; +} /* }}} */ + +/* {{{ proto int SplFileObject::getMaxLineLen() + Get maximum line length */ +SPL_METHOD(SplFileObject, getMaxLineLen) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG((long)intern->u.file.max_line_len); +} /* }}} */ + +/* {{{ proto bool SplFileObject::hasChildren() + Return false */ +SPL_METHOD(SplFileObject, hasChildren) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_FALSE; +} /* }}} */ + +/* {{{ proto bool SplFileObject::getChildren() + Read NULL */ +SPL_METHOD(SplFileObject, getChildren) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* return NULL */ +} /* }}} */ + +/* {{{ 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, ZEND_NUM_ARGS(), NULL); \ +} +/* }}} */ + +/* {{{ proto array SplFileObject::fgetcsv([string delimiter [, string enclosure [, escape = '\\']]]) + Return current line as csv */ +SPL_METHOD(SplFileObject, fgetcsv) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape; + char *delim = NULL, *enclo = NULL, *esc = NULL; + int d_len = 0, e_len = 0, esc_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) { + switch(ZEND_NUM_ARGS()) + { + case 3: + if (esc_len != 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character"); + RETURN_FALSE; + } + escape = esc[0]; + /* no break */ + 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, escape, return_value TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ proto int SplFileObject::fputcsv(array fields, [string delimiter [, string enclosure]]) + Output a field array as a CSV line */ +SPL_METHOD(SplFileObject, fputcsv) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape; + char *delim = NULL, *enclo = NULL; + int d_len = 0, e_len = 0, ret; + zval *fields = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|ss", &fields, &delim, &d_len, &enclo, &e_len) == SUCCESS) { + switch(ZEND_NUM_ARGS()) + { + case 3: + 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 2: + 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 1: + case 0: + break; + } + ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape TSRMLS_CC); + RETURN_LONG(ret); + } +} +/* }}} */ + +/* {{{ proto void SplFileObject::setCsvControl([string delimiter = ',' [, string enclosure = '"' [, string escape = '\\']]]) + 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 = '"', escape='\\'; + char *delim = NULL, *enclo = NULL, *esc = NULL; + int d_len = 0, e_len = 0, esc_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) { + switch(ZEND_NUM_ARGS()) + { + case 3: + if (esc_len != 1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "escape must be a character"); + RETURN_FALSE; + } + escape = esc[0]; + /* no break */ + 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; + intern->u.file.escape = escape; + } +} +/* }}} */ + +/* {{{ 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]; + + 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); +} +/* }}} */ + +/* {{{ proto bool SplFileObject::flock(int operation [, int &wouldblock]) + Portable file locking */ +FileFunction(flock) +/* }}} */ + +/* {{{ proto bool SplFileObject::fflush() + Flush the file */ +SPL_METHOD(SplFileObject, fflush) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(!php_stream_flush(intern->u.file.stream)); +} /* }}} */ + +/* {{{ proto int SplFileObject::ftell() + Return current file position */ +SPL_METHOD(SplFileObject, ftell) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long ret = php_stream_tell(intern->u.file.stream); + + if (ret == -1) { + RETURN_FALSE; + } else { + RETURN_LONG(ret); + } +} /* }}} */ + +/* {{{ proto int SplFileObject::fseek(int pos [, int whence = SEEK_SET]) + Return current file position */ +SPL_METHOD(SplFileObject, fseek) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long pos, whence = SEEK_SET; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &pos, &whence) == FAILURE) { + return; + } + + spl_filesystem_file_free_line(intern TSRMLS_CC); + RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, whence)); +} /* }}} */ + +/* {{{ proto int SplFileObject::fgetc() + Get a character form the file */ +SPL_METHOD(SplFileObject, fgetc) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char buf[2]; + int result; + + spl_filesystem_file_free_line(intern TSRMLS_CC); + + result = php_stream_getc(intern->u.file.stream); + + if (result == EOF) { + RETVAL_FALSE; + } else { + if (result == '\n') { + intern->u.file.current_line_num++; + } + buf[0] = result; + buf[1] = '\0'; + + RETURN_STRINGL(buf, 1, 1); + } +} /* }}} */ + +/* {{{ proto string SplFileObject::fgetss([string allowable_tags]) + Get a line from file pointer and strip HTML tags */ +SPL_METHOD(SplFileObject, fgetss) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval *arg2 = NULL; + MAKE_STD_ZVAL(arg2); + + if (intern->u.file.max_line_len > 0) { + ZVAL_LONG(arg2, intern->u.file.max_line_len); + } else { + ZVAL_LONG(arg2, 1024); + } + + spl_filesystem_file_free_line(intern TSRMLS_CC); + intern->u.file.current_line_num++; + + FileFunctionCall(fgetss, ZEND_NUM_ARGS(), arg2); + + zval_ptr_dtor(&arg2); +} /* }}} */ + +/* {{{ proto int SplFileObject::fpassthru() + Output all remaining data from a file pointer */ +SPL_METHOD(SplFileObject, fpassthru) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(php_stream_passthru(intern->u.file.stream)); +} /* }}} */ + +/* {{{ proto bool SplFileObject::fscanf(string format [, string ...]) + Implements a mostly ANSI compatible fscanf() */ +SPL_METHOD(SplFileObject, fscanf) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_filesystem_file_free_line(intern TSRMLS_CC); + intern->u.file.current_line_num++; + + FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL); +} +/* }}} */ + +/* {{{ proto mixed SplFileObject::fwrite(string str [, int length]) + Binary-safe file write */ +SPL_METHOD(SplFileObject, fwrite) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *str; + int str_len; + long length = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &length) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() > 1) { + str_len = MAX(0, MIN(length, str_len)); + } + if (!str_len) { + RETURN_LONG(0); + } + + RETURN_LONG(php_stream_write(intern->u.file.stream, str, str_len)); +} /* }}} */ + +/* {{{ proto bool SplFileObject::fstat() + Stat() on a filehandle */ +FileFunction(fstat) +/* }}} */ + +/* {{{ proto bool SplFileObject::ftruncate(int size) + Truncate file to 'size' length */ +SPL_METHOD(SplFileObject, ftruncate) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long size; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size) == FAILURE) { + return; + } + + if (!php_stream_truncate_supported(intern->u.file.stream)) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't truncate file %s", intern->file_name); + RETURN_FALSE; + } + + RETURN_BOOL(0 == php_stream_truncate_set_size(intern->u.file.stream, size)); +} /* }}} */ + +/* {{{ proto void SplFileObject::seek(int line_pos) + Seek to specified line */ +SPL_METHOD(SplFileObject, seek) +{ + spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long line_pos; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &line_pos) == FAILURE) { + return; + } + if (line_pos < 0) { + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "Can't seek file %s to negative line %ld", intern->file_name, line_pos); + RETURN_FALSE; + } + + spl_filesystem_file_rewind(getThis(), intern TSRMLS_CC); + + while(intern->u.file.current_line_num < line_pos) { + if (spl_filesystem_file_read_line(getThis(), intern, 1 TSRMLS_CC) == FAILURE) { + break; + } + } +} /* }}} */ + +/* {{{ Function/Class/Method definitions */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object___construct, 0, 0, 1) + ZEND_ARG_INFO(0, file_name) + ZEND_ARG_INFO(0, open_mode) + ZEND_ARG_INFO(0, use_include_path) + ZEND_ARG_INFO(0, context) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_file_object_setFlags, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_file_object_setMaxLineLen, 0) + ZEND_ARG_INFO(0, max_len) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetcsv, 0, 0, 0) + ZEND_ARG_INFO(0, delimiter) + ZEND_ARG_INFO(0, enclosure) + ZEND_ARG_INFO(0, escape) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fputcsv, 0, 0, 1) + ZEND_ARG_INFO(0, fields) + ZEND_ARG_INFO(0, delimiter) + ZEND_ARG_INFO(0, enclosure) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_flock, 0, 0, 1) + ZEND_ARG_INFO(0, operation) + ZEND_ARG_INFO(1, wouldblock) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fseek, 0, 0, 1) + ZEND_ARG_INFO(0, pos) + ZEND_ARG_INFO(0, whence) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetss, 0, 0, 0) + ZEND_ARG_INFO(0, allowable_tags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 1, 0, 1) + ZEND_ARG_INFO(0, format) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fwrite, 0, 0, 1) + ZEND_ARG_INFO(0, str) + ZEND_ARG_INFO(0, length) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_ftruncate, 0, 0, 1) + ZEND_ARG_INFO(0, size) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_seek, 0, 0, 1) + ZEND_ARG_INFO(0, line_pos) +ZEND_END_ARG_INFO() + +static const zend_function_entry spl_SplFileObject_functions[] = { + SPL_ME(SplFileObject, __construct, arginfo_file_object___construct, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, rewind, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, eof, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, valid, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fgets, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fgetcsv, arginfo_file_object_fgetcsv, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fputcsv, arginfo_file_object_fputcsv, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, setCsvControl, arginfo_file_object_fgetcsv, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, getCsvControl, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, flock, arginfo_file_object_flock, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fflush, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, ftell, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fseek, arginfo_file_object_fseek, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fgetc, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fpassthru, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fgetss, arginfo_file_object_fgetss, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fscanf, arginfo_file_object_fscanf, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fwrite, arginfo_file_object_fwrite, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, fstat, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, ftruncate, arginfo_file_object_ftruncate, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, key, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, next, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, setFlags, arginfo_file_object_setFlags, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, getFlags, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, setMaxLineLen, arginfo_file_object_setMaxLineLen, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, getMaxLineLen, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, hasChildren, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, getChildren, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFileObject, seek, arginfo_file_object_seek, ZEND_ACC_PUBLIC) + /* mappings */ + SPL_MA(SplFileObject, getCurrentLine, SplFileObject, fgets, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + SPL_MA(SplFileObject, __toString, SplFileObject, current, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 0) + ZEND_ARG_INFO(0, max_memory) +ZEND_END_ARG_INFO() + +static const zend_function_entry spl_SplTempFileObject_functions[] = { + SPL_ME(SplTempFileObject, __construct, arginfo_temp_file_object___construct, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION(spl_directory) + */ +PHP_MINIT_FUNCTION(spl_directory) +{ + REGISTER_SPL_STD_CLASS_EX(SplFileInfo, spl_filesystem_object_new, spl_SplFileInfo_functions); + memcpy(&spl_filesystem_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_filesystem_object_handlers.clone_obj = spl_filesystem_object_clone; + spl_filesystem_object_handlers.cast_object = spl_filesystem_object_cast; + spl_filesystem_object_handlers.get_debug_info = spl_filesystem_object_get_debug_info; + spl_ce_SplFileInfo->serialize = zend_class_serialize_deny; + spl_ce_SplFileInfo->unserialize = zend_class_unserialize_deny; + + REGISTER_SPL_SUB_CLASS_EX(DirectoryIterator, SplFileInfo, spl_filesystem_object_new, spl_DirectoryIterator_functions); + zend_class_implements(spl_ce_DirectoryIterator TSRMLS_CC, 1, zend_ce_iterator); + REGISTER_SPL_IMPLEMENTS(DirectoryIterator, SeekableIterator); + + spl_ce_DirectoryIterator->get_iterator = spl_filesystem_dir_get_iterator; + + REGISTER_SPL_SUB_CLASS_EX(FilesystemIterator, DirectoryIterator, spl_filesystem_object_new, spl_FilesystemIterator_functions); + + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_MODE_MASK", SPL_FILE_DIR_CURRENT_MODE_MASK); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_PATHNAME", SPL_FILE_DIR_CURRENT_AS_PATHNAME); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_FILEINFO", SPL_FILE_DIR_CURRENT_AS_FILEINFO); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_SELF", SPL_FILE_DIR_CURRENT_AS_SELF); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_MODE_MASK", SPL_FILE_DIR_KEY_MODE_MASK); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_PATHNAME", SPL_FILE_DIR_KEY_AS_PATHNAME); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "FOLLOW_SYMLINKS", SPL_FILE_DIR_FOLLOW_SYMLINKS); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_FILENAME", SPL_FILE_DIR_KEY_AS_FILENAME); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "NEW_CURRENT_AND_KEY", SPL_FILE_DIR_KEY_AS_FILENAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "OTHER_MODE_MASK", SPL_FILE_DIR_OTHERS_MASK); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "SKIP_DOTS", SPL_FILE_DIR_SKIPDOTS); + REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "UNIX_PATHS", SPL_FILE_DIR_UNIXPATHS); + + spl_ce_FilesystemIterator->get_iterator = spl_filesystem_tree_get_iterator; + + REGISTER_SPL_SUB_CLASS_EX(RecursiveDirectoryIterator, FilesystemIterator, spl_filesystem_object_new, spl_RecursiveDirectoryIterator_functions); + REGISTER_SPL_IMPLEMENTS(RecursiveDirectoryIterator, RecursiveIterator); + + memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers)); + spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check; + +#ifdef HAVE_GLOB + REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new_check, spl_GlobIterator_functions); + REGISTER_SPL_IMPLEMENTS(GlobIterator, Countable); +#endif + + REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new_check, spl_SplFileObject_functions); + REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator); + REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator); + + 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_check, spl_SplTempFileObject_functions); + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_directory.h b/ext/spl/spl_directory.h new file mode 100644 index 0000000..d95ba55 --- /dev/null +++ b/ext/spl/spl_directory.h @@ -0,0 +1,149 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_DIRECTORY_H +#define SPL_DIRECTORY_H + +#include "php.h" +#include "php_spl.h" + +extern PHPAPI zend_class_entry *spl_ce_SplFileInfo; +extern PHPAPI zend_class_entry *spl_ce_DirectoryIterator; +extern PHPAPI zend_class_entry *spl_ce_FilesystemIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator; +extern PHPAPI zend_class_entry *spl_ce_GlobIterator; +extern PHPAPI zend_class_entry *spl_ce_SplFileObject; +extern PHPAPI zend_class_entry *spl_ce_SplTempFileObject; + +PHP_MINIT_FUNCTION(spl_directory); + +typedef enum { + SPL_FS_INFO, /* must be 0 */ + SPL_FS_DIR, + SPL_FS_FILE +} SPL_FS_OBJ_TYPE; + +typedef struct _spl_filesystem_object spl_filesystem_object; + +typedef void (*spl_foreign_dtor_t)(spl_filesystem_object *object TSRMLS_DC); +typedef void (*spl_foreign_clone_t)(spl_filesystem_object *src, spl_filesystem_object *dst TSRMLS_DC); + +PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, int *len TSRMLS_DC); + +typedef struct _spl_other_handler { + spl_foreign_dtor_t dtor; + spl_foreign_clone_t clone; +} spl_other_handler; + +/* define an overloaded iterator structure */ +typedef struct { + zend_object_iterator intern; + zval *current; + spl_filesystem_object *object; +} spl_filesystem_iterator; + +struct _spl_filesystem_object { + zend_object std; + void *oth; + spl_other_handler *oth_handler; + char *_path; + int _path_len; + char *orig_path; + char *file_name; + int file_name_len; + SPL_FS_OBJ_TYPE type; + long flags; + zend_class_entry *file_class; + zend_class_entry *info_class; + union { + struct { + php_stream *dirp; + php_stream_dirent entry; + char *sub_path; + int sub_path_len; + int index; + int is_recursive; + zend_function *func_rewind; + zend_function *func_next; + zend_function *func_valid; + } dir; + struct { + php_stream *stream; + php_stream_context *context; + zval *zcontext; + char *open_mode; + int open_mode_len; + zval *current_zval; + char *current_line; + size_t current_line_len; + size_t max_line_len; + long current_line_num; + zval zresource; + zend_function *func_getCurr; + char delimiter; + char enclosure; + char escape; + } file; + } u; + spl_filesystem_iterator it; +}; + +static inline spl_filesystem_iterator* spl_filesystem_object_to_iterator(spl_filesystem_object *obj) +{ + return &obj->it; +} + +static inline spl_filesystem_object* spl_filesystem_iterator_to_object(spl_filesystem_iterator *it) +{ + return (spl_filesystem_object*)((char*)it - XtOffsetOf(spl_filesystem_object, it)); +} + +#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 0x00000004 /* skip empty lines */ +#define SPL_FILE_OBJECT_READ_CSV 0x00000008 /* read via fgetcsv */ +#define SPL_FILE_OBJECT_MASK 0x0000000F /* read via fgetcsv */ + +#define SPL_FILE_DIR_CURRENT_AS_FILEINFO 0x00000000 /* make RecursiveDirectoryTree::current() return SplFileInfo */ +#define SPL_FILE_DIR_CURRENT_AS_SELF 0x00000010 /* make RecursiveDirectoryTree::current() return getSelf() */ +#define SPL_FILE_DIR_CURRENT_AS_PATHNAME 0x00000020 /* make RecursiveDirectoryTree::current() return getPathname() */ +#define SPL_FILE_DIR_CURRENT_MODE_MASK 0x000000F0 /* mask RecursiveDirectoryTree::current() */ +#define SPL_FILE_DIR_CURRENT(intern,mode) ((intern->flags&SPL_FILE_DIR_CURRENT_MODE_MASK)==mode) + +#define SPL_FILE_DIR_KEY_AS_PATHNAME 0x00000000 /* make RecursiveDirectoryTree::key() return getPathname() */ +#define SPL_FILE_DIR_KEY_AS_FILENAME 0x00000100 /* make RecursiveDirectoryTree::key() return getFilename() */ +#define SPL_FILE_DIR_FOLLOW_SYMLINKS 0x00000200 /* make RecursiveDirectoryTree::hasChildren() follow symlinks */ +#define SPL_FILE_DIR_KEY_MODE_MASK 0x00000F00 /* mask RecursiveDirectoryTree::key() */ +#define SPL_FILE_DIR_KEY(intern,mode) ((intern->flags&SPL_FILE_DIR_KEY_MODE_MASK)==mode) + +#define SPL_FILE_DIR_SKIPDOTS 0x00001000 /* Tells whether it should skip dots or not */ +#define SPL_FILE_DIR_UNIXPATHS 0x00002000 /* Whether to unixify path separators */ +#define SPL_FILE_DIR_OTHERS_MASK 0x00003000 /* mask used for get/setFlags */ + +#endif /* SPL_DIRECTORY_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_dllist.c b/ext/spl/spl_dllist.c new file mode 100644 index 0000000..a8417fe --- /dev/null +++ b/ext/spl/spl_dllist.c @@ -0,0 +1,1376 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "zend_exceptions.h" +#include "zend_hash.h" + +#include "php_spl.h" +#include "ext/standard/info.h" +#include "ext/standard/php_var.h" +#include "ext/standard/php_smart_str.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_iterators.h" +#include "spl_dllist.h" +#include "spl_exceptions.h" + +zend_object_handlers spl_handler_SplDoublyLinkedList; +PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList; +PHPAPI zend_class_entry *spl_ce_SplQueue; +PHPAPI zend_class_entry *spl_ce_SplStack; + +#define SPL_LLIST_DELREF(elem) if(!--(elem)->rc) { \ + efree(elem); \ + elem = NULL; \ +} + +#define SPL_LLIST_CHECK_DELREF(elem) if((elem) && !--(elem)->rc) { \ + efree(elem); \ + elem = NULL; \ +} + +#define SPL_LLIST_ADDREF(elem) (elem)->rc++ +#define SPL_LLIST_CHECK_ADDREF(elem) if(elem) (elem)->rc++ + +#define SPL_DLLIST_IT_DELETE 0x00000001 /* Delete flag makes the iterator delete the current element on next */ +#define SPL_DLLIST_IT_LIFO 0x00000002 /* LIFO flag makes the iterator traverse the structure as a LastInFirstOut */ +#define SPL_DLLIST_IT_MASK 0x00000003 /* Mask to isolate flags related to iterators */ +#define SPL_DLLIST_IT_FIX 0x00000004 /* Backward/Forward bit is fixed */ + +#ifdef accept +#undef accept +#endif + +typedef struct _spl_ptr_llist_element { + struct _spl_ptr_llist_element *prev; + struct _spl_ptr_llist_element *next; + int rc; + void *data; +} spl_ptr_llist_element; + +typedef void (*spl_ptr_llist_dtor_func)(spl_ptr_llist_element * TSRMLS_DC); +typedef void (*spl_ptr_llist_ctor_func)(spl_ptr_llist_element * TSRMLS_DC); + +typedef struct _spl_ptr_llist { + spl_ptr_llist_element *head; + spl_ptr_llist_element *tail; + spl_ptr_llist_dtor_func dtor; + spl_ptr_llist_ctor_func ctor; + int count; +} spl_ptr_llist; + +typedef struct _spl_dllist_object spl_dllist_object; +typedef struct _spl_dllist_it spl_dllist_it; + +struct _spl_dllist_object { + zend_object std; + spl_ptr_llist *llist; + int traverse_position; + spl_ptr_llist_element *traverse_pointer; + zval *retval; + int flags; + zend_function *fptr_offset_get; + zend_function *fptr_offset_set; + zend_function *fptr_offset_has; + zend_function *fptr_offset_del; + zend_function *fptr_count; + zend_class_entry *ce_get_iterator; + HashTable *debug_info; +}; + +/* define an overloaded iterator structure */ +struct _spl_dllist_it { + zend_user_iterator intern; + int traverse_position; + spl_ptr_llist_element *traverse_pointer; + int flags; + spl_dllist_object *object; +}; + +/* {{{ spl_ptr_llist */ +static void spl_ptr_llist_zval_dtor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */ + if (elem->data) { + zval_ptr_dtor((zval **)&elem->data); + } +} +/* }}} */ + +static void spl_ptr_llist_zval_ctor(spl_ptr_llist_element *elem TSRMLS_DC) { /* {{{ */ + Z_ADDREF_P((zval *)elem->data); +} +/* }}} */ + +static spl_ptr_llist *spl_ptr_llist_init(spl_ptr_llist_ctor_func ctor, spl_ptr_llist_dtor_func dtor) /* {{{ */ +{ + spl_ptr_llist *llist = emalloc(sizeof(spl_ptr_llist)); + + llist->head = NULL; + llist->tail = NULL; + llist->count = 0; + llist->dtor = dtor; + llist->ctor = ctor; + + return llist; +} +/* }}} */ + +static long spl_ptr_llist_count(spl_ptr_llist *llist) /* {{{ */ +{ + return (long)llist->count; +} +/* }}} */ + +static void spl_ptr_llist_destroy(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */ +{ + spl_ptr_llist_element *current = llist->head, *next; + spl_ptr_llist_dtor_func dtor = llist->dtor; + + while (current) { + next = current->next; + if(current && dtor) { + dtor(current TSRMLS_CC); + } + SPL_LLIST_DELREF(current); + current = next; + } + + efree(llist); +} +/* }}} */ + +static spl_ptr_llist_element *spl_ptr_llist_offset(spl_ptr_llist *llist, long offset, int backward) /* {{{ */ +{ + + spl_ptr_llist_element *current; + int pos = 0; + + if (backward) { + current = llist->tail; + } else { + current = llist->head; + } + + while (current && pos < offset) { + pos++; + if (backward) { + current = current->prev; + } else { + current = current->next; + } + } + + return current; +} +/* }}} */ + +static void spl_ptr_llist_unshift(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */ +{ + spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element)); + + elem->data = data; + elem->rc = 1; + elem->prev = NULL; + elem->next = llist->head; + + if (llist->head) { + llist->head->prev = elem; + } else { + llist->tail = elem; + } + + llist->head = elem; + llist->count++; + + if (llist->ctor) { + llist->ctor(elem TSRMLS_CC); + } +} +/* }}} */ + +static void spl_ptr_llist_push(spl_ptr_llist *llist, void *data TSRMLS_DC) /* {{{ */ +{ + spl_ptr_llist_element *elem = emalloc(sizeof(spl_ptr_llist_element)); + + elem->data = data; + elem->rc = 1; + elem->prev = llist->tail; + elem->next = NULL; + + if (llist->tail) { + llist->tail->next = elem; + } else { + llist->head = elem; + } + + llist->tail = elem; + llist->count++; + + if (llist->ctor) { + llist->ctor(elem TSRMLS_CC); + } +} +/* }}} */ + +static void *spl_ptr_llist_pop(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */ +{ + void *data; + spl_ptr_llist_element *tail = llist->tail; + + if (tail == NULL) { + return NULL; + } + + if (tail->prev) { + tail->prev->next = NULL; + } else { + llist->head = NULL; + } + + llist->tail = tail->prev; + llist->count--; + data = tail->data; + + if (llist->dtor) { + llist->dtor(tail TSRMLS_CC); + } + + tail->data = NULL; + + SPL_LLIST_DELREF(tail); + + return data; +} +/* }}} */ + +static void *spl_ptr_llist_last(spl_ptr_llist *llist) /* {{{ */ +{ + spl_ptr_llist_element *tail = llist->tail; + + if (tail == NULL) { + return NULL; + } else { + return tail->data; + } +} +/* }}} */ + +static void *spl_ptr_llist_first(spl_ptr_llist *llist) /* {{{ */ +{ + spl_ptr_llist_element *head = llist->head; + + if (head == NULL) { + return NULL; + } else { + return head->data; + } +} +/* }}} */ + +static void *spl_ptr_llist_shift(spl_ptr_llist *llist TSRMLS_DC) /* {{{ */ +{ + void *data; + spl_ptr_llist_element *head = llist->head; + + if (head == NULL) { + return NULL; + } + + if (head->next) { + head->next->prev = NULL; + } else { + llist->tail = NULL; + } + + llist->head = head->next; + llist->count--; + data = head->data; + + if (llist->dtor) { + llist->dtor(head TSRMLS_CC); + } + head->data = NULL; + + SPL_LLIST_DELREF(head); + + return data; +} +/* }}} */ + +static void spl_ptr_llist_copy(spl_ptr_llist *from, spl_ptr_llist *to TSRMLS_DC) /* {{{ */ +{ + spl_ptr_llist_element *current = from->head, *next; + spl_ptr_llist_ctor_func ctor = from->ctor; + + while (current) { + next = current->next; + + if (ctor) { + ctor(current TSRMLS_CC); + } + + spl_ptr_llist_push(to, current->data TSRMLS_CC); + current = next; + } + +} +/* }}} */ + +/* }}} */ + +static void spl_dllist_object_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + spl_dllist_object *intern = (spl_dllist_object *)object; + zval *tmp = NULL; + + zend_object_std_dtor(&intern->std TSRMLS_CC); + + while(intern->llist->count > 0) { + tmp = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC); + zval_ptr_dtor(&tmp); + } + + spl_ptr_llist_destroy(intern->llist TSRMLS_CC); + SPL_LLIST_CHECK_DELREF(intern->traverse_pointer); + zval_ptr_dtor(&intern->retval); + + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + + efree(object); +} +/* }}} */ + +zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); + +static zend_object_value spl_dllist_object_new_ex(zend_class_entry *class_type, spl_dllist_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + spl_dllist_object *intern; + zend_class_entry *parent = class_type; + int inherited = 0; + + intern = ecalloc(1, sizeof(spl_dllist_object)); + *obj = intern; + ALLOC_INIT_ZVAL(intern->retval); + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + intern->flags = 0; + intern->traverse_position = 0; + intern->debug_info = NULL; + + if (orig) { + spl_dllist_object *other = (spl_dllist_object*)zend_object_store_get_object(orig TSRMLS_CC); + intern->ce_get_iterator = other->ce_get_iterator; + + if (clone_orig) { + intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(other->llist->ctor, other->llist->dtor); + spl_ptr_llist_copy(other->llist, intern->llist TSRMLS_CC); + intern->traverse_pointer = intern->llist->head; + SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer); + } else { + intern->llist = other->llist; + intern->traverse_pointer = intern->llist->head; + SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer); + } + + intern->flags = other->flags; + } else { + intern->llist = (spl_ptr_llist *)spl_ptr_llist_init(spl_ptr_llist_zval_ctor, spl_ptr_llist_zval_dtor); + intern->traverse_pointer = intern->llist->head; + SPL_LLIST_CHECK_ADDREF(intern->traverse_pointer); + } + + while (parent) { + if (parent == spl_ce_SplStack) { + intern->flags |= (SPL_DLLIST_IT_FIX | SPL_DLLIST_IT_LIFO); + retval.handlers = &spl_handler_SplDoublyLinkedList; + } else if (parent == spl_ce_SplQueue) { + intern->flags |= SPL_DLLIST_IT_FIX; + retval.handlers = &spl_handler_SplDoublyLinkedList; + } + + if (parent == spl_ce_SplDoublyLinkedList) { + retval.handlers = &spl_handler_SplDoublyLinkedList; + break; + } + + parent = parent->parent; + inherited = 1; + } + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_dllist_object_free_storage, NULL TSRMLS_CC); + + if (!parent) { /* this must never happen */ + php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplDoublyLinkedList"); + } + if (inherited) { + zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get); + if (intern->fptr_offset_get->common.scope == parent) { + intern->fptr_offset_get = NULL; + } + zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set); + if (intern->fptr_offset_set->common.scope == parent) { + intern->fptr_offset_set = NULL; + } + zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has); + if (intern->fptr_offset_has->common.scope == parent) { + intern->fptr_offset_has = NULL; + } + zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del); + if (intern->fptr_offset_del->common.scope == parent) { + intern->fptr_offset_del = NULL; + } + zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count); + if (intern->fptr_count->common.scope == parent) { + intern->fptr_count = NULL; + } + } + + return retval; +} +/* }}} */ + +static zend_object_value spl_dllist_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ +{ + spl_dllist_object *tmp; + return spl_dllist_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC); +} +/* }}} */ + +static zend_object_value spl_dllist_object_clone(zval *zobject TSRMLS_DC) /* {{{ */ +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_dllist_object *intern; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + new_obj_val = spl_dllist_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC); + new_object = &intern->std; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + return new_obj_val; +} +/* }}} */ + +static int spl_dllist_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_count) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + convert_to_long(intern->retval); + *count = (long) Z_LVAL_P(intern->retval); + return SUCCESS; + } + *count = 0; + return FAILURE; + } + + *count = spl_ptr_llist_count(intern->llist); + return SUCCESS; +} +/* }}} */ + +static HashTable* spl_dllist_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{{ */ +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(obj TSRMLS_CC); + spl_ptr_llist_element *current = intern->llist->head, *next; + zval *tmp, zrv, *dllist_array; + char *pnstr; + int pnlen; + int i = 0; + + *is_temp = 0; + + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + zend_hash_init(intern->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0); + } + + if (intern->debug_info->nApplyCount == 0) { + INIT_PZVAL(&zrv); + Z_ARRVAL(zrv) = intern->debug_info; + + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); + add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags); + efree(pnstr); + + ALLOC_INIT_ZVAL(dllist_array); + array_init(dllist_array); + + while (current) { + next = current->next; + + add_index_zval(dllist_array, i, (zval *)current->data); + Z_ADDREF_P(current->data); + i++; + + current = next; + } + + pnstr = spl_gen_private_prop_name(spl_ce_SplDoublyLinkedList, "dllist", sizeof("dllist")-1, &pnlen TSRMLS_CC); + add_assoc_zval_ex(&zrv, pnstr, pnlen+1, dllist_array); + efree(pnstr); + } + + return intern->debug_info; +} +/* }}}} */ + +/* {{{ proto bool SplDoublyLinkedList::push(mixed $value) U + Push $value on the SplDoublyLinkedList */ +SPL_METHOD(SplDoublyLinkedList, push) +{ + zval *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) { + return; + } + + SEPARATE_ARG_IF_REF(value); + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_ptr_llist_push(intern->llist, value TSRMLS_CC); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SplDoublyLinkedList::unshift(mixed $value) U + Unshift $value on the SplDoublyLinkedList */ +SPL_METHOD(SplDoublyLinkedList, unshift) +{ + zval *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) { + return; + } + + SEPARATE_ARG_IF_REF(value); + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_ptr_llist_unshift(intern->llist, value TSRMLS_CC); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto mixed SplDoublyLinkedList::pop() U + Pop an element out of the SplDoublyLinkedList */ +SPL_METHOD(SplDoublyLinkedList, pop) +{ + zval *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + value = (zval *)spl_ptr_llist_pop(intern->llist TSRMLS_CC); + + if (value == NULL) { + zend_throw_exception(spl_ce_RuntimeException, "Can't pop from an empty datastructure", 0 TSRMLS_CC); + return; + } + + RETURN_ZVAL(value, 1, 1); +} +/* }}} */ + +/* {{{ proto mixed SplDoublyLinkedList::shift() U + Shift an element out of the SplDoublyLinkedList */ +SPL_METHOD(SplDoublyLinkedList, shift) +{ + zval *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + value = (zval *)spl_ptr_llist_shift(intern->llist TSRMLS_CC); + + if (value == NULL) { + zend_throw_exception(spl_ce_RuntimeException, "Can't shift from an empty datastructure", 0 TSRMLS_CC); + return; + } + + RETURN_ZVAL(value, 1, 1); +} +/* }}} */ + +/* {{{ proto mixed SplDoublyLinkedList::top() U + Peek at the top element of the SplDoublyLinkedList */ +SPL_METHOD(SplDoublyLinkedList, top) +{ + zval *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + value = (zval *)spl_ptr_llist_last(intern->llist); + + if (value == NULL) { + zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC); + return; + } + + RETURN_ZVAL(value, 1, 0); +} +/* }}} */ + +/* {{{ proto mixed SplDoublyLinkedList::bottom() U + Peek at the bottom element of the SplDoublyLinkedList */ +SPL_METHOD(SplDoublyLinkedList, bottom) +{ + zval *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + value = (zval *)spl_ptr_llist_first(intern->llist); + + if (value == NULL) { + zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty datastructure", 0 TSRMLS_CC); + return; + } + + RETURN_ZVAL(value, 1, 0); +} +/* }}} */ + +/* {{{ proto int SplDoublyLinkedList::count() U + Return the number of elements in the datastructure. */ +SPL_METHOD(SplDoublyLinkedList, count) +{ + long count; + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + count = spl_ptr_llist_count(intern->llist); + RETURN_LONG(count); +} +/* }}} */ + +/* {{{ proto int SplDoublyLinkedList::isEmpty() U + Return true if the SplDoublyLinkedList is empty. */ +SPL_METHOD(SplDoublyLinkedList, isEmpty) +{ + long count; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + spl_dllist_object_count_elements(getThis(), &count TSRMLS_CC); + RETURN_BOOL(count==0); +} +/* }}} */ + +/* {{{ proto int SplDoublyLinkedList::setIteratorMode($flags) U + Set the mode of iteration */ +SPL_METHOD(SplDoublyLinkedList, setIteratorMode) +{ + long value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->flags & SPL_DLLIST_IT_FIX + && (intern->flags & SPL_DLLIST_IT_LIFO) != (value & SPL_DLLIST_IT_LIFO)) { + zend_throw_exception(spl_ce_RuntimeException, "Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen", 0 TSRMLS_CC); + return; + } + + intern->flags = value & SPL_DLLIST_IT_MASK; + + RETURN_LONG(intern->flags); +} +/* }}} */ + +/* {{{ proto int SplDoublyLinkedList::getIteratorMode() U + Return the mode of iteration */ +SPL_METHOD(SplDoublyLinkedList, getIteratorMode) +{ + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_LONG(intern->flags); +} +/* }}} */ + +/* {{{ proto bool SplDoublyLinkedList::offsetExists(mixed $index) U + Returns whether the requested $index exists. */ +SPL_METHOD(SplDoublyLinkedList, offsetExists) +{ + zval *zindex; + spl_dllist_object *intern; + long index; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + index = spl_offset_convert_to_long(zindex TSRMLS_CC); + + RETURN_BOOL(index >= 0 && index < intern->llist->count); +} /* }}} */ + +/* {{{ proto mixed SplDoublyLinkedList::offsetGet(mixed $index) U + Returns the value at the specified $index. */ +SPL_METHOD(SplDoublyLinkedList, offsetGet) +{ + zval *zindex, *value; + long index; + spl_dllist_object *intern; + spl_ptr_llist_element *element; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + index = spl_offset_convert_to_long(zindex TSRMLS_CC); + + if (index < 0 || index >= intern->llist->count) { + zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC); + return; + } + + element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); + + if (element != NULL) { + value = (zval *)element->data; + RETURN_ZVAL(value, 1, 0); + } else { + zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC); + return; + } +} /* }}} */ + +/* {{{ proto void SplDoublyLinkedList::offsetSet(mixed $index, mixed $newval) U + Sets the value at the specified $index to $newval. */ +SPL_METHOD(SplDoublyLinkedList, offsetSet) +{ + zval *zindex, *value; + spl_dllist_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) { + return; + } + SEPARATE_ARG_IF_REF(value); + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (Z_TYPE_P(zindex) == IS_NULL) { + /* $obj[] = ... */ + spl_ptr_llist_push(intern->llist, value TSRMLS_CC); + } else { + /* $obj[$foo] = ... */ + long index; + spl_ptr_llist_element *element; + + index = spl_offset_convert_to_long(zindex TSRMLS_CC); + + if (index < 0 || index >= intern->llist->count) { + zval_ptr_dtor(&value); + zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid or out of range", 0 TSRMLS_CC); + return; + } + + element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); + + if (element != NULL) { + /* call dtor on the old element as in spl_ptr_llist_pop */ + if (intern->llist->dtor) { + intern->llist->dtor(element TSRMLS_CC); + } + + /* the element is replaced, delref the old one as in + * SplDoublyLinkedList::pop() */ + zval_ptr_dtor((zval **)&element->data); + element->data = value; + + /* new element, call ctor as in spl_ptr_llist_push */ + if (intern->llist->ctor) { + intern->llist->ctor(element TSRMLS_CC); + } + } else { + zval_ptr_dtor(&value); + zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC); + return; + } + } +} /* }}} */ + +/* {{{ proto void SplDoublyLinkedList::offsetUnset(mixed $index) U + Unsets the value at the specified $index. */ +SPL_METHOD(SplDoublyLinkedList, offsetUnset) +{ + zval *zindex; + long index; + spl_dllist_object *intern; + spl_ptr_llist_element *element; + spl_ptr_llist *llist; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + index = (int)spl_offset_convert_to_long(zindex TSRMLS_CC); + llist = intern->llist; + + if (index < 0 || index >= intern->llist->count) { + zend_throw_exception(spl_ce_OutOfRangeException, "Offset out of range", 0 TSRMLS_CC); + return; + } + + element = spl_ptr_llist_offset(intern->llist, index, intern->flags & SPL_DLLIST_IT_LIFO); + + if (element != NULL) { + /* connect the neightbors */ + if (element->prev) { + element->prev->next = element->next; + } + + if (element->next) { + element->next->prev = element->prev; + } + + /* take care of head/tail */ + if (element == llist->head) { + llist->head = element->next; + } + + if (element == llist->tail) { + llist->tail = element->prev; + } + + /* finally, delete the element */ + llist->count--; + + if(llist->dtor) { + llist->dtor(element TSRMLS_CC); + } + + zval_ptr_dtor((zval **)&element->data); + element->data = NULL; + + SPL_LLIST_DELREF(element); + } else { + zend_throw_exception(spl_ce_OutOfRangeException, "Offset invalid", 0 TSRMLS_CC); + return; + } +} /* }}} */ + +static void spl_dllist_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator = (spl_dllist_it *)iter; + + SPL_LLIST_CHECK_DELREF(iterator->traverse_pointer); + + zend_user_it_invalidate_current(iter TSRMLS_CC); + zval_ptr_dtor((zval**)&iterator->intern.it.data); + + efree(iterator); +} +/* }}} */ + +static void spl_dllist_it_helper_rewind(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */ +{ + SPL_LLIST_CHECK_DELREF(*traverse_pointer_ptr); + + if (flags & SPL_DLLIST_IT_LIFO) { + *traverse_position_ptr = llist->count-1; + *traverse_pointer_ptr = llist->tail; + } else { + *traverse_position_ptr = 0; + *traverse_pointer_ptr = llist->head; + } + + SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr); +} +/* }}} */ + +static void spl_dllist_it_helper_move_forward(spl_ptr_llist_element **traverse_pointer_ptr, int *traverse_position_ptr, spl_ptr_llist *llist, int flags TSRMLS_DC) /* {{{ */ +{ + if (*traverse_pointer_ptr) { + spl_ptr_llist_element *old = *traverse_pointer_ptr; + + if (flags & SPL_DLLIST_IT_LIFO) { + *traverse_pointer_ptr = old->prev; + (*traverse_position_ptr)--; + + if (flags & SPL_DLLIST_IT_DELETE) { + zval *prev = (zval *)spl_ptr_llist_pop(llist TSRMLS_CC); + + if (prev) { + zval_ptr_dtor((zval **)&prev); + } + } + } else { + *traverse_pointer_ptr = old->next; + + if (flags & SPL_DLLIST_IT_DELETE) { + zval *prev = (zval *)spl_ptr_llist_shift(llist TSRMLS_CC); + + if (prev) { + zval_ptr_dtor((zval **)&prev); + } + } else { + (*traverse_position_ptr)++; + } + } + + SPL_LLIST_DELREF(old); + SPL_LLIST_CHECK_ADDREF(*traverse_pointer_ptr); + } +} +/* }}} */ + +static void spl_dllist_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator = (spl_dllist_it *)iter; + spl_dllist_object *object = iterator->object; + spl_ptr_llist *llist = object->llist; + + spl_dllist_it_helper_rewind(&iterator->traverse_pointer, &iterator->traverse_position, llist, object->flags TSRMLS_CC); +} +/* }}} */ + +static int spl_dllist_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator = (spl_dllist_it *)iter; + spl_ptr_llist_element *element = iterator->traverse_pointer; + + return (element != NULL ? SUCCESS : FAILURE); +} +/* }}} */ + +static void spl_dllist_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator = (spl_dllist_it *)iter; + spl_ptr_llist_element *element = iterator->traverse_pointer; + + if (element == NULL || element->data == NULL) { + *data = NULL; + } else { + *data = (zval **)&element->data; + } +} +/* }}} */ + +static int spl_dllist_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator = (spl_dllist_it *)iter; + + *int_key = (ulong) iterator->traverse_position; + return HASH_KEY_IS_LONG; +} +/* }}} */ + +static void spl_dllist_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator = (spl_dllist_it *)iter; + spl_dllist_object *object = iterator->object; + + zend_user_it_invalidate_current(iter TSRMLS_CC); + + spl_dllist_it_helper_move_forward(&iterator->traverse_pointer, &iterator->traverse_position, object->llist, object->flags TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int SplDoublyLinkedList::key() U + Return current array key */ +SPL_METHOD(SplDoublyLinkedList, key) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->traverse_position); +} +/* }}} */ + +/* {{{ proto void SplDoublyLinkedList::prev() U + Move to next entry */ +SPL_METHOD(SplDoublyLinkedList, prev) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags ^ SPL_DLLIST_IT_LIFO TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void SplDoublyLinkedList::next() U + Move to next entry */ +SPL_METHOD(SplDoublyLinkedList, next) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_dllist_it_helper_move_forward(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto bool SplDoublyLinkedList::valid() U + Check whether the datastructure contains more entries */ +SPL_METHOD(SplDoublyLinkedList, valid) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(intern->traverse_pointer != NULL); +} +/* }}} */ + +/* {{{ proto void SplDoublyLinkedList::rewind() U + Rewind the datastructure back to the start */ +SPL_METHOD(SplDoublyLinkedList, rewind) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_dllist_it_helper_rewind(&intern->traverse_pointer, &intern->traverse_position, intern->llist, intern->flags TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto mixed|NULL SplDoublyLinkedList::current() U + Return current datastructure entry */ +SPL_METHOD(SplDoublyLinkedList, current) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_ptr_llist_element *element = intern->traverse_pointer; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (element == NULL || element->data == NULL) { + RETURN_NULL(); + } else { + zval *data = (zval *)element->data; + RETURN_ZVAL(data, 1, 0); + } +} +/* }}} */ +/* {{{ proto string SplDoublyLinkedList::serialize() + Serializes storage */ +SPL_METHOD(SplDoublyLinkedList, serialize) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + smart_str buf = {0}; + spl_ptr_llist_element *current = intern->llist->head, *next; + zval *flags; + php_serialize_data_t var_hash; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + PHP_VAR_SERIALIZE_INIT(var_hash); + + /* flags */ + MAKE_STD_ZVAL(flags); + ZVAL_LONG(flags, intern->flags); + php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC); + zval_ptr_dtor(&flags); + + /* elements */ + while (current) { + smart_str_appendc(&buf, ':'); + next = current->next; + + php_var_serialize(&buf, (zval **)¤t->data, &var_hash TSRMLS_CC); + + current = next; + } + + smart_str_0(&buf); + + /* done */ + PHP_VAR_SERIALIZE_DESTROY(var_hash); + + if (buf.c) { + RETURN_STRINGL(buf.c, buf.len, 0); + } else { + RETURN_NULL(); + } + +} /* }}} */ + +/* {{{ proto void SplDoublyLinkedList::unserialize(string serialized) + Unserializes storage */ +SPL_METHOD(SplDoublyLinkedList, unserialize) +{ + spl_dllist_object *intern = (spl_dllist_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval *flags, *elem; + char *buf; + int buf_len; + const unsigned char *p, *s; + php_unserialize_data_t var_hash; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { + return; + } + + if (buf_len == 0) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Serialized string cannot be empty"); + return; + } + + s = p = (const unsigned char*)buf; + PHP_VAR_UNSERIALIZE_INIT(var_hash); + + /* flags */ + ALLOC_INIT_ZVAL(flags); + if (!php_var_unserialize(&flags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(flags) != IS_LONG) { + zval_ptr_dtor(&flags); + goto error; + } + intern->flags = Z_LVAL_P(flags); + zval_ptr_dtor(&flags); + + /* elements */ + while(*p == ':') { + ++p; + ALLOC_INIT_ZVAL(elem); + if (!php_var_unserialize(&elem, &p, s + buf_len, &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&elem); + goto error; + } + + spl_ptr_llist_push(intern->llist, elem TSRMLS_CC); + } + + if (*p != '\0') { + goto error; + } + + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return; + +error: + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len); + return; + +} /* }}} */ + +/* iterator handler table */ +zend_object_iterator_funcs spl_dllist_it_funcs = { + spl_dllist_it_dtor, + spl_dllist_it_valid, + spl_dllist_it_get_current_data, + spl_dllist_it_get_current_key, + spl_dllist_it_move_forward, + spl_dllist_it_rewind +}; + +zend_object_iterator *spl_dllist_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ +{ + spl_dllist_it *iterator; + spl_dllist_object *dllist_object = (spl_dllist_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (by_ref) { + zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC); + return NULL; + } + + Z_ADDREF_P(object); + + iterator = emalloc(sizeof(spl_dllist_it)); + iterator->intern.it.data = (void*)object; + iterator->intern.it.funcs = &spl_dllist_it_funcs; + iterator->intern.ce = ce; + iterator->intern.value = NULL; + iterator->traverse_position = dllist_object->traverse_position; + iterator->traverse_pointer = dllist_object->traverse_pointer; + iterator->flags = dllist_object->flags & SPL_DLLIST_IT_MASK; + iterator->object = dllist_object; + + SPL_LLIST_CHECK_ADDREF(iterator->traverse_pointer); + + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +/* Function/Class/Method definitions */ +ZEND_BEGIN_ARG_INFO(arginfo_dllist_setiteratormode, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_dllist_push, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_dllist_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_dllist_void, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_dllist_serialized, 0) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_SplQueue[] = { + SPL_MA(SplQueue, enqueue, SplDoublyLinkedList, push, arginfo_dllist_push, ZEND_ACC_PUBLIC) + SPL_MA(SplQueue, dequeue, SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static const zend_function_entry spl_funcs_SplDoublyLinkedList[] = { + SPL_ME(SplDoublyLinkedList, pop, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, shift, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, push, arginfo_dllist_push, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, unshift, arginfo_dllist_push, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, top, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, bottom, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, isEmpty, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, setIteratorMode, arginfo_dllist_setiteratormode, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, getIteratorMode, arginfo_dllist_void, ZEND_ACC_PUBLIC) + /* Countable */ + SPL_ME(SplDoublyLinkedList, count, arginfo_dllist_void, ZEND_ACC_PUBLIC) + /* ArrayAccess */ + SPL_ME(SplDoublyLinkedList, offsetExists, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, offsetGet, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, offsetSet, arginfo_dllist_offsetSet, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, offsetUnset, arginfo_dllist_offsetGet, ZEND_ACC_PUBLIC) + /* Iterator */ + SPL_ME(SplDoublyLinkedList, rewind, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, current, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, key, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, next, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, prev, arginfo_dllist_void, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, valid, arginfo_dllist_void, ZEND_ACC_PUBLIC) + /* Serializable */ + SPL_ME(SplDoublyLinkedList, unserialize, arginfo_dllist_serialized, ZEND_ACC_PUBLIC) + SPL_ME(SplDoublyLinkedList, serialize, arginfo_dllist_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +PHP_MINIT_FUNCTION(spl_dllist) /* {{{ */ +{ + REGISTER_SPL_STD_CLASS_EX(SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplDoublyLinkedList); + memcpy(&spl_handler_SplDoublyLinkedList, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_SplDoublyLinkedList.clone_obj = spl_dllist_object_clone; + spl_handler_SplDoublyLinkedList.count_elements = spl_dllist_object_count_elements; + spl_handler_SplDoublyLinkedList.get_debug_info = spl_dllist_object_get_debug_info; + + REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_LIFO", SPL_DLLIST_IT_LIFO); + REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_FIFO", 0); + REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_DELETE",SPL_DLLIST_IT_DELETE); + REGISTER_SPL_CLASS_CONST_LONG(SplDoublyLinkedList, "IT_MODE_KEEP", 0); + + REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Iterator); + REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Countable); + REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, ArrayAccess); + REGISTER_SPL_IMPLEMENTS(SplDoublyLinkedList, Serializable); + + spl_ce_SplDoublyLinkedList->get_iterator = spl_dllist_get_iterator; + + REGISTER_SPL_SUB_CLASS_EX(SplQueue, SplDoublyLinkedList, spl_dllist_object_new, spl_funcs_SplQueue); + REGISTER_SPL_SUB_CLASS_EX(SplStack, SplDoublyLinkedList, spl_dllist_object_new, NULL); + + spl_ce_SplQueue->get_iterator = spl_dllist_get_iterator; + spl_ce_SplStack->get_iterator = spl_dllist_get_iterator; + + return SUCCESS; +} +/* }}} */ +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_dllist.h b/ext/spl/spl_dllist.h new file mode 100644 index 0000000..8615f74 --- /dev/null +++ b/ext/spl/spl_dllist.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_DLLIST_H +#define SPL_DLLIST_H + +#include "php.h" +#include "php_spl.h" + +extern PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList; +extern PHPAPI zend_class_entry *spl_ce_SplQueue; +extern PHPAPI zend_class_entry *spl_ce_SplStack; + +PHP_MINIT_FUNCTION(spl_dllist); + +#endif /* SPL_DLLIST_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_engine.c b/ext/spl/spl_engine.c new file mode 100644 index 0000000..ea2349f --- /dev/null +++ b/ext/spl/spl_engine.c @@ -0,0 +1,70 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "zend_interfaces.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" + +#include "spl_array.h" + +/* {{{ spl_instantiate */ +PHPAPI void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC) +{ + if (alloc) { + ALLOC_ZVAL(*object); + } + object_init_ex(*object, pce); + Z_SET_REFCOUNT_PP(object, 1); + Z_SET_ISREF_PP(object); /* check if this can be hold always */ +} +/* }}} */ + +PHPAPI long spl_offset_convert_to_long(zval *offset TSRMLS_DC) /* {{{ */ +{ + switch (Z_TYPE_P(offset)) { + case IS_STRING: + ZEND_HANDLE_NUMERIC(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, idx); + break; + case IS_DOUBLE: + return (long)Z_DVAL_P(offset); + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + return Z_LVAL_P(offset); + } + return -1; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_engine.h b/ext/spl/spl_engine.h new file mode 100644 index 0000000..103a5c4 --- /dev/null +++ b/ext/spl/spl_engine.h @@ -0,0 +1,61 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_ENGINE_H +#define SPL_ENGINE_H + +#include "php.h" +#include "php_spl.h" +#include "zend_interfaces.h" + +PHPAPI void spl_instantiate(zend_class_entry *pce, zval **object, int alloc TSRMLS_DC); + +PHPAPI long spl_offset_convert_to_long(zval *offset TSRMLS_DC); + +/* {{{ spl_instantiate_arg_ex1 */ +static inline int spl_instantiate_arg_ex1(zend_class_entry *pce, zval **retval, int alloc, zval *arg1 TSRMLS_DC) +{ + spl_instantiate(pce, retval, alloc TSRMLS_CC); + + zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), NULL, 1, arg1, NULL TSRMLS_CC); + return 0; +} +/* }}} */ + +/* {{{ spl_instantiate_arg_ex2 */ +static inline int spl_instantiate_arg_ex2(zend_class_entry *pce, zval **retval, int alloc, zval *arg1, zval *arg2 TSRMLS_DC) +{ + spl_instantiate(pce, retval, alloc TSRMLS_CC); + + zend_call_method(retval, pce, &pce->constructor, pce->constructor->common.function_name, strlen(pce->constructor->common.function_name), NULL, 2, arg1, arg2 TSRMLS_CC); + return 0; +} +/* }}} */ + +#endif /* SPL_ENGINE_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_exceptions.c b/ext/spl/spl_exceptions.c new file mode 100644 index 0000000..d905070 --- /dev/null +++ b/ext/spl/spl_exceptions.c @@ -0,0 +1,81 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "zend_interfaces.h" +#include "zend_exceptions.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_exceptions.h" + +PHPAPI zend_class_entry *spl_ce_LogicException; +PHPAPI zend_class_entry *spl_ce_BadFunctionCallException; +PHPAPI zend_class_entry *spl_ce_BadMethodCallException; +PHPAPI zend_class_entry *spl_ce_DomainException; +PHPAPI zend_class_entry *spl_ce_InvalidArgumentException; +PHPAPI zend_class_entry *spl_ce_LengthException; +PHPAPI zend_class_entry *spl_ce_OutOfRangeException; +PHPAPI zend_class_entry *spl_ce_RuntimeException; +PHPAPI zend_class_entry *spl_ce_OutOfBoundsException; +PHPAPI zend_class_entry *spl_ce_OverflowException; +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(TSRMLS_C) + +/* {{{ PHP_MINIT_FUNCTION(spl_exceptions) */ +PHP_MINIT_FUNCTION(spl_exceptions) +{ + REGISTER_SPL_SUB_CLASS_EX(LogicException, Exception, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(BadFunctionCallException, LogicException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(BadMethodCallException, BadFunctionCallException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(DomainException, LogicException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(InvalidArgumentException, LogicException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(LengthException, LogicException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(OutOfRangeException, LogicException, NULL, NULL); + + REGISTER_SPL_SUB_CLASS_EX(RuntimeException, Exception, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(OutOfBoundsException, RuntimeException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(OverflowException, RuntimeException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(RangeException, RuntimeException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(UnderflowException, RuntimeException, NULL, NULL); + REGISTER_SPL_SUB_CLASS_EX(UnexpectedValueException, RuntimeException, NULL, NULL); + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_exceptions.h b/ext/spl/spl_exceptions.h new file mode 100644 index 0000000..e4e7f27 --- /dev/null +++ b/ext/spl/spl_exceptions.h @@ -0,0 +1,53 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_EXCEPTIONS_H +#define SPL_EXCEPTIONS_H + +#include "php.h" +#include "php_spl.h" + +extern PHPAPI zend_class_entry *spl_ce_LogicException; +extern PHPAPI zend_class_entry *spl_ce_BadFunctionCallException; +extern PHPAPI zend_class_entry *spl_ce_BadMethodCallException; +extern PHPAPI zend_class_entry *spl_ce_DomainException; +extern PHPAPI zend_class_entry *spl_ce_InvalidArgumentException; +extern PHPAPI zend_class_entry *spl_ce_LengthException; +extern PHPAPI zend_class_entry *spl_ce_OutOfRangeException; + +extern PHPAPI zend_class_entry *spl_ce_RuntimeException; +extern PHPAPI zend_class_entry *spl_ce_OutOfBoundsException; +extern PHPAPI zend_class_entry *spl_ce_OverflowException; +extern PHPAPI zend_class_entry *spl_ce_RangeException; +extern PHPAPI zend_class_entry *spl_ce_UnderflowException; +extern PHPAPI zend_class_entry *spl_ce_UnexpectedValueException; + +PHP_MINIT_FUNCTION(spl_exceptions); + +#endif /* SPL_EXCEPTIONS_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c new file mode 100644 index 0000000..ebc4e34 --- /dev/null +++ b/ext/spl/spl_fixedarray.c @@ -0,0 +1,1140 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Antony Dovgal <tony@daylessday.org> | + | Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "zend_exceptions.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_fixedarray.h" +#include "spl_exceptions.h" +#include "spl_iterators.h" + +zend_object_handlers spl_handler_SplFixedArray; +PHPAPI zend_class_entry *spl_ce_SplFixedArray; + +#ifdef COMPILE_DL_SPL_FIXEDARRAY +ZEND_GET_MODULE(spl_fixedarray) +#endif + +typedef struct _spl_fixedarray { /* {{{ */ + long size; + zval **elements; +} spl_fixedarray; +/* }}} */ + +typedef struct _spl_fixedarray_object { /* {{{ */ + zend_object std; + spl_fixedarray *array; + zval *retval; + zend_function *fptr_offset_get; + zend_function *fptr_offset_set; + zend_function *fptr_offset_has; + zend_function *fptr_offset_del; + zend_function *fptr_count; + int current; + int flags; + zend_class_entry *ce_get_iterator; +} spl_fixedarray_object; +/* }}} */ + +typedef struct _spl_fixedarray_it { /* {{{ */ + zend_user_iterator intern; + spl_fixedarray_object *object; +} spl_fixedarray_it; +/* }}} */ + +#define SPL_FIXEDARRAY_OVERLOADED_REWIND 0x0001 +#define SPL_FIXEDARRAY_OVERLOADED_VALID 0x0002 +#define SPL_FIXEDARRAY_OVERLOADED_KEY 0x0004 +#define SPL_FIXEDARRAY_OVERLOADED_CURRENT 0x0008 +#define SPL_FIXEDARRAY_OVERLOADED_NEXT 0x0010 + +static void spl_fixedarray_init(spl_fixedarray *array, long size TSRMLS_DC) /* {{{ */ +{ + if (size > 0) { + array->size = 0; /* reset size in case ecalloc() fails */ + array->elements = ecalloc(size, sizeof(zval *)); + array->size = size; + } else { + array->elements = NULL; + array->size = 0; + } +} +/* }}} */ + +static void spl_fixedarray_resize(spl_fixedarray *array, long size TSRMLS_DC) /* {{{ */ +{ + if (size == array->size) { + /* nothing to do */ + return; + } + + /* first initialization */ + if (array->size == 0) { + spl_fixedarray_init(array, size TSRMLS_CC); + return; + } + + /* clearing the array */ + if (size == 0) { + long i; + + for (i = 0; i < array->size; i++) { + if (array->elements[i]) { + zval_ptr_dtor(&(array->elements[i])); + } + } + + if (array->elements) { + efree(array->elements); + array->elements = NULL; + } + } else if (size > array->size) { + array->elements = erealloc(array->elements, sizeof(zval *) * size); + memset(array->elements + array->size, '\0', sizeof(zval *) * (size - array->size)); + } else { /* size < array->size */ + long i; + + for (i = size; i < array->size; i++) { + if (array->elements[i]) { + zval_ptr_dtor(&(array->elements[i])); + } + } + array->elements = erealloc(array->elements, sizeof(zval *) * size); + } + + array->size = size; +} +/* }}} */ + +static void spl_fixedarray_copy(spl_fixedarray *to, spl_fixedarray *from TSRMLS_DC) /* {{{ */ +{ + int i; + for (i = 0; i < from->size; i++) { + if (from->elements[i]) { + Z_ADDREF_P(from->elements[i]); + to->elements[i] = from->elements[i]; + } else { + to->elements[i] = NULL; + } + } +} +/* }}} */ + +static HashTable* spl_fixedarray_object_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{{ */ +{ + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC); + HashTable *ht = zend_std_get_properties(obj TSRMLS_CC); + + if (intern->array) { + *table = intern->array->elements; + *n = intern->array->size; + } else { + *table = NULL; + *n = 0; + } + + return ht; +} +/* }}}} */ + +static HashTable* spl_fixedarray_object_get_properties(zval *obj TSRMLS_DC) /* {{{{ */ +{ + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(obj TSRMLS_CC); + HashTable *ht = zend_std_get_properties(obj TSRMLS_CC); + int i = 0; + + if (intern->array) { + int j = zend_hash_num_elements(ht); + + for (i = 0; i < intern->array->size; i++) { + if (intern->array->elements[i]) { + zend_hash_index_update(ht, i, (void *)&intern->array->elements[i], sizeof(zval *), NULL); + Z_ADDREF_P(intern->array->elements[i]); + } else { + zend_hash_index_update(ht, i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL); + Z_ADDREF_P(EG(uninitialized_zval_ptr)); + } + } + if (j > intern->array->size) { + for (i = intern->array->size; i < j; ++i) { + zend_hash_index_del(ht, i); + } + } + } + + return ht; +} +/* }}}} */ + +static void spl_fixedarray_object_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *intern = (spl_fixedarray_object *)object; + long i; + + if (intern->array) { + for (i = 0; i < intern->array->size; i++) { + if (intern->array->elements[i]) { + zval_ptr_dtor(&(intern->array->elements[i])); + } + } + + if (intern->array->size > 0 && intern->array->elements) { + efree(intern->array->elements); + } + efree(intern->array); + } + + zend_object_std_dtor(&intern->std TSRMLS_CC); + zval_ptr_dtor(&intern->retval); + + efree(object); +} +/* }}} */ + +zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); + +static zend_object_value spl_fixedarray_object_new_ex(zend_class_entry *class_type, spl_fixedarray_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + spl_fixedarray_object *intern; + zend_class_entry *parent = class_type; + int inherited = 0; + + intern = ecalloc(1, sizeof(spl_fixedarray_object)); + *obj = intern; + ALLOC_INIT_ZVAL(intern->retval); + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + intern->current = 0; + intern->flags = 0; + + if (orig && clone_orig) { + spl_fixedarray_object *other = (spl_fixedarray_object*)zend_object_store_get_object(orig TSRMLS_CC); + intern->ce_get_iterator = other->ce_get_iterator; + if (!other->array) { + /* leave a empty object, will be dtor later by CLONE handler */ + zend_throw_exception(spl_ce_RuntimeException, "The instance wasn't initialized properly", 0 TSRMLS_CC); + } else { + intern->array = emalloc(sizeof(spl_fixedarray)); + spl_fixedarray_init(intern->array, other->array->size TSRMLS_CC); + spl_fixedarray_copy(intern->array, other->array TSRMLS_CC); + } + } + + while (parent) { + if (parent == spl_ce_SplFixedArray) { + retval.handlers = &spl_handler_SplFixedArray; + class_type->get_iterator = spl_fixedarray_get_iterator; + break; + } + + parent = parent->parent; + inherited = 1; + } + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_fixedarray_object_free_storage, NULL TSRMLS_CC); + + if (!parent) { /* this must never happen */ + php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplFixedArray"); + } + 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->flags |= SPL_FIXEDARRAY_OVERLOADED_REWIND; + } + if (class_type->iterator_funcs.zf_valid->common.scope != parent) { + intern->flags |= SPL_FIXEDARRAY_OVERLOADED_VALID; + } + if (class_type->iterator_funcs.zf_key->common.scope != parent) { + intern->flags |= SPL_FIXEDARRAY_OVERLOADED_KEY; + } + if (class_type->iterator_funcs.zf_current->common.scope != parent) { + intern->flags |= SPL_FIXEDARRAY_OVERLOADED_CURRENT; + } + if (class_type->iterator_funcs.zf_next->common.scope != parent) { + intern->flags |= SPL_FIXEDARRAY_OVERLOADED_NEXT; + } + + zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get); + if (intern->fptr_offset_get->common.scope == parent) { + intern->fptr_offset_get = NULL; + } + zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set); + if (intern->fptr_offset_set->common.scope == parent) { + intern->fptr_offset_set = NULL; + } + zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has); + if (intern->fptr_offset_has->common.scope == parent) { + intern->fptr_offset_has = NULL; + } + zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del); + if (intern->fptr_offset_del->common.scope == parent) { + intern->fptr_offset_del = NULL; + } + zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count); + if (intern->fptr_count->common.scope == parent) { + intern->fptr_count = NULL; + } + } + + return retval; +} +/* }}} */ + +static zend_object_value spl_fixedarray_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *tmp; + return spl_fixedarray_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC); +} +/* }}} */ + +static zend_object_value spl_fixedarray_object_clone(zval *zobject TSRMLS_DC) /* {{{ */ +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_fixedarray_object *intern; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + new_obj_val = spl_fixedarray_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC); + new_object = &intern->std; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + return new_obj_val; +} +/* }}} */ + +static inline zval **spl_fixedarray_object_read_dimension_helper(spl_fixedarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */ +{ + long index; + + /* we have to return NULL on error here to avoid memleak because of + * ZE duplicating uninitialized_zval_ptr */ + if (!offset) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return NULL; + } + + if (Z_TYPE_P(offset) != IS_LONG) { + index = spl_offset_convert_to_long(offset TSRMLS_CC); + } else { + index = Z_LVAL_P(offset); + } + + if (index < 0 || intern->array == NULL || index >= intern->array->size) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return NULL; + } else if(!intern->array->elements[index]) { + return NULL; + } else { + return &intern->array->elements[index]; + } +} +/* }}} */ + +static zval *spl_fixedarray_object_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *intern; + zval **retval; + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_get) { + zval *rv; + if (!offset) { + ALLOC_INIT_ZVAL(offset); + } else { + SEPARATE_ARG_IF_REF(offset); + } + zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_get, "offsetGet", &rv, offset); + zval_ptr_dtor(&offset); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + return intern->retval; + } + return EG(uninitialized_zval_ptr); + } + + retval = spl_fixedarray_object_read_dimension_helper(intern, offset TSRMLS_CC); + if (retval) { + return *retval; + } + return NULL; +} +/* }}} */ + +static inline void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *intern, zval *offset, zval *value TSRMLS_DC) /* {{{ */ +{ + long index; + + if (!offset) { + /* '$array[] = value' syntax is not supported */ + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return; + } + + if (Z_TYPE_P(offset) != IS_LONG) { + index = spl_offset_convert_to_long(offset TSRMLS_CC); + } else { + index = Z_LVAL_P(offset); + } + + if (index < 0 || intern->array == NULL || index >= intern->array->size) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return; + } else { + if (intern->array->elements[index]) { + zval_ptr_dtor(&(intern->array->elements[index])); + } + SEPARATE_ARG_IF_REF(value); + intern->array->elements[index] = value; + } +} +/* }}} */ + +static void spl_fixedarray_object_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *intern; + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_set) { + if (!offset) { + ALLOC_INIT_ZVAL(offset); + } else { + SEPARATE_ARG_IF_REF(offset); + } + SEPARATE_ARG_IF_REF(value); + zend_call_method_with_2_params(&object, intern->std.ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value); + zval_ptr_dtor(&value); + zval_ptr_dtor(&offset); + return; + } + + spl_fixedarray_object_write_dimension_helper(intern, offset, value TSRMLS_CC); +} +/* }}} */ + +static inline void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *intern, zval *offset TSRMLS_DC) /* {{{ */ +{ + long index; + + if (Z_TYPE_P(offset) != IS_LONG) { + index = spl_offset_convert_to_long(offset TSRMLS_CC); + } else { + index = Z_LVAL_P(offset); + } + + if (index < 0 || intern->array == NULL || index >= intern->array->size) { + zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0 TSRMLS_CC); + return; + } else { + if (intern->array->elements[index]) { + zval_ptr_dtor(&(intern->array->elements[index])); + } + intern->array->elements[index] = NULL; + } +} +/* }}} */ + +static void spl_fixedarray_object_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *intern; + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_del) { + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset); + zval_ptr_dtor(&offset); + return; + } + + spl_fixedarray_object_unset_dimension_helper(intern, offset TSRMLS_CC); + +} +/* }}} */ + +static inline int spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *intern, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ +{ + long index; + int retval; + + if (Z_TYPE_P(offset) != IS_LONG) { + index = spl_offset_convert_to_long(offset TSRMLS_CC); + } else { + index = Z_LVAL_P(offset); + } + + if (index < 0 || intern->array == NULL || index >= intern->array->size) { + retval = 0; + } else { + if (!intern->array->elements[index]) { + retval = 0; + } else if (check_empty) { + if (zend_is_true(intern->array->elements[index])) { + retval = 1; + } else { + retval = 0; + } + } else { /* != NULL and !check_empty */ + retval = 1; + } + } + + return retval; +} +/* }}} */ + +static int spl_fixedarray_object_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *intern; + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_offset_get) { + zval *rv; + SEPARATE_ARG_IF_REF(offset); + zend_call_method_with_1_params(&object, intern->std.ce, &intern->fptr_offset_has, "offsetExists", &rv, offset); + zval_ptr_dtor(&offset); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + return zend_is_true(intern->retval); + } + return 0; + } + + return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty TSRMLS_CC); +} +/* }}} */ + +static int spl_fixedarray_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_object *intern; + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + if (intern->fptr_count) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + convert_to_long(intern->retval); + *count = (long) Z_LVAL_P(intern->retval); + return SUCCESS; + } + } else if (intern->array) { + *count = intern->array->size; + return SUCCESS; + } + + *count = 0; + return SUCCESS; +} +/* }}} */ + +/* {{{ proto void SplFixedArray::__construct([int size]) +*/ +SPL_METHOD(SplFixedArray, __construct) +{ + zval *object = getThis(); + spl_fixedarray_object *intern; + long size = 0; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &size)) { + return; + } + + if (size < 0) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero"); + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->array) { + /* called __construct() twice, bail out */ + return; + } + + intern->array = emalloc(sizeof(spl_fixedarray)); + spl_fixedarray_init(intern->array, size TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int SplFixedArray::count(void) +*/ +SPL_METHOD(SplFixedArray, count) +{ + zval *object = getThis(); + spl_fixedarray_object *intern; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + if (intern->array) { + RETURN_LONG(intern->array->size); + } + RETURN_LONG(0); +} +/* }}} */ + +/* {{{ proto object SplFixedArray::toArray() +*/ +SPL_METHOD(SplFixedArray, toArray) +{ + spl_fixedarray_object *intern; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + array_init(return_value); + if (intern->array) { + int i = 0; + for (; i < intern->array->size; i++) { + if (intern->array->elements[i]) { + zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *)&intern->array->elements[i], sizeof(zval *), NULL); + Z_ADDREF_P(intern->array->elements[i]); + } else { + zend_hash_index_update(Z_ARRVAL_P(return_value), i, (void *)&EG(uninitialized_zval_ptr), sizeof(zval *), NULL); + Z_ADDREF_P(EG(uninitialized_zval_ptr)); + } + } + } +} +/* }}} */ + +/* {{{ proto object SplFixedArray::fromArray(array data[, bool save_indexes]) +*/ +SPL_METHOD(SplFixedArray, fromArray) +{ + zval *data; + spl_fixedarray *array; + spl_fixedarray_object *intern; + int num; + zend_bool save_indexes = 1; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b", &data, &save_indexes)) { + return; + } + + array = ecalloc(1, sizeof(*array)); + num = zend_hash_num_elements(Z_ARRVAL_P(data)); + + if (num > 0 && save_indexes) { + zval **element, *value; + char *str_index; + ulong num_index, max_index = 0; + long tmp; + + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data)); + zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS; + zend_hash_move_forward(Z_ARRVAL_P(data)) + ) { + if (zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0) != HASH_KEY_IS_LONG || (long)num_index < 0) { + efree(array); + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array must contain only positive integer keys"); + return; + } + + if (num_index > max_index) { + max_index = num_index; + } + } + + tmp = max_index + 1; + if (tmp <= 0) { + efree(array); + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "integer overflow detected"); + return; + } + spl_fixedarray_init(array, tmp TSRMLS_CC); + + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data)); + zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS; + zend_hash_move_forward(Z_ARRVAL_P(data)) + ) { + + zend_hash_get_current_key(Z_ARRVAL_P(data), &str_index, &num_index, 0); + value = *element; + + SEPARATE_ARG_IF_REF(value); + array->elements[num_index] = value; + } + + } else if (num > 0 && !save_indexes) { + zval **element, *value; + long i = 0; + + spl_fixedarray_init(array, num TSRMLS_CC); + + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(data)); + zend_hash_get_current_data(Z_ARRVAL_P(data), (void **) &element) == SUCCESS; + zend_hash_move_forward(Z_ARRVAL_P(data)) + ) { + + value = *element; + + SEPARATE_ARG_IF_REF(value); + array->elements[i] = value; + i++; + } + } else { + spl_fixedarray_init(array, 0 TSRMLS_CC); + } + + object_init_ex(return_value, spl_ce_SplFixedArray); + Z_TYPE_P(return_value) = IS_OBJECT; + + intern = (spl_fixedarray_object *)zend_object_store_get_object(return_value TSRMLS_CC); + intern->array = array; +} +/* }}} */ + +/* {{{ proto int SplFixedArray::getSize(void) +*/ +SPL_METHOD(SplFixedArray, getSize) +{ + zval *object = getThis(); + spl_fixedarray_object *intern; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "")) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + if (intern->array) { + RETURN_LONG(intern->array->size); + } + RETURN_LONG(0); +} +/* }}} */ + +/* {{{ proto bool SplFixedArray::setSize(int size) +*/ +SPL_METHOD(SplFixedArray, setSize) +{ + zval *object = getThis(); + spl_fixedarray_object *intern; + long size; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size)) { + return; + } + + if (size < 0) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "array size cannot be less than zero"); + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(object TSRMLS_CC); + if (!intern->array) { + intern->array = ecalloc(1, sizeof(spl_fixedarray)); + } + + spl_fixedarray_resize(intern->array, size TSRMLS_CC); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SplFixedArray::offsetExists(mixed $index) U + Returns whether the requested $index exists. */ +SPL_METHOD(SplFixedArray, offsetExists) +{ + zval *zindex; + spl_fixedarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + + RETURN_BOOL(spl_fixedarray_object_has_dimension_helper(intern, zindex, 0 TSRMLS_CC)); +} /* }}} */ + +/* {{{ proto mixed SplFixedArray::offsetGet(mixed $index) U + Returns the value at the specified $index. */ +SPL_METHOD(SplFixedArray, offsetGet) +{ + zval *zindex, **value_pp; + spl_fixedarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC); + + if (value_pp) { + RETURN_ZVAL(*value_pp, 1, 0); + } + RETURN_NULL(); +} /* }}} */ + +/* {{{ proto void SplFixedArray::offsetSet(mixed $index, mixed $newval) U + Sets the value at the specified $index to $newval. */ +SPL_METHOD(SplFixedArray, offsetSet) +{ + zval *zindex, *value; + spl_fixedarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zindex, &value) == FAILURE) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_fixedarray_object_write_dimension_helper(intern, zindex, value TSRMLS_CC); + +} /* }}} */ + +/* {{{ proto void SplFixedArray::offsetUnset(mixed $index) U + Unsets the value at the specified $index. */ +SPL_METHOD(SplFixedArray, offsetUnset) +{ + zval *zindex; + spl_fixedarray_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zindex) == FAILURE) { + return; + } + + intern = (spl_fixedarray_object *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_fixedarray_object_unset_dimension_helper(intern, zindex TSRMLS_CC); + +} /* }}} */ + +static void spl_fixedarray_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; + + zend_user_it_invalidate_current(iter TSRMLS_CC); + zval_ptr_dtor((zval**)&iterator->intern.it.data); + + efree(iterator); +} +/* }}} */ + +static void spl_fixedarray_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; + spl_fixedarray_object *intern = iterator->object; + + if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_REWIND) { + zend_user_it_rewind(iter TSRMLS_CC); + } else { + iterator->object->current = 0; + } +} +/* }}} */ + +static int spl_fixedarray_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; + spl_fixedarray_object *intern = iterator->object; + + if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_VALID) { + return zend_user_it_valid(iter TSRMLS_CC); + } + + if (iterator->object->current >= 0 && iterator->object->array && iterator->object->current < iterator->object->array->size) { + return SUCCESS; + } + + return FAILURE; +} +/* }}} */ + +static void spl_fixedarray_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ +{ + zval *zindex; + spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; + spl_fixedarray_object *intern = iterator->object; + + if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_CURRENT) { + zend_user_it_get_current_data(iter, data TSRMLS_CC); + } else { + ALLOC_INIT_ZVAL(zindex); + ZVAL_LONG(zindex, iterator->object->current); + + *data = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC); + + if (*data == NULL) { + *data = &EG(uninitialized_zval_ptr); + } + + zval_ptr_dtor(&zindex); + } +} +/* }}} */ + +static int spl_fixedarray_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; + spl_fixedarray_object *intern = iterator->object; + + if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_KEY) { + return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC); + } else { + *int_key = (ulong) iterator->object->current; + return HASH_KEY_IS_LONG; + } + +} +/* }}} */ + +static void spl_fixedarray_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_it *iterator = (spl_fixedarray_it *)iter; + spl_fixedarray_object *intern = iterator->object; + + if (intern->flags & SPL_FIXEDARRAY_OVERLOADED_NEXT) { + zend_user_it_move_forward(iter TSRMLS_CC); + } else { + zend_user_it_invalidate_current(iter TSRMLS_CC); + iterator->object->current++; + } +} +/* }}} */ + +/* {{{ proto int SplFixedArray::key() U + Return current array key */ +SPL_METHOD(SplFixedArray, key) +{ + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->current); +} +/* }}} */ + +/* {{{ proto void SplFixedArray::next() U + Move to next entry */ +SPL_METHOD(SplFixedArray, next) +{ + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + intern->current++; +} +/* }}} */ + +/* {{{ proto bool SplFixedArray::valid() U + Check whether the datastructure contains more entries */ +SPL_METHOD(SplFixedArray, valid) +{ + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(intern->current >= 0 && intern->array && intern->current < intern->array->size); +} +/* }}} */ + +/* {{{ proto void SplFixedArray::rewind() U + Rewind the datastructure back to the start */ +SPL_METHOD(SplFixedArray, rewind) +{ + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + intern->current = 0; +} +/* }}} */ + +/* {{{ proto mixed|NULL SplFixedArray::current() U + Return current datastructure entry */ +SPL_METHOD(SplFixedArray, current) +{ + zval *zindex, **value_pp; + spl_fixedarray_object *intern = (spl_fixedarray_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + ALLOC_INIT_ZVAL(zindex); + ZVAL_LONG(zindex, intern->current); + + value_pp = spl_fixedarray_object_read_dimension_helper(intern, zindex TSRMLS_CC); + + zval_ptr_dtor(&zindex); + + if (value_pp) { + RETURN_ZVAL(*value_pp, 1, 0); + } + RETURN_NULL(); +} +/* }}} */ + +/* iterator handler table */ +zend_object_iterator_funcs spl_fixedarray_it_funcs = { + spl_fixedarray_it_dtor, + spl_fixedarray_it_valid, + spl_fixedarray_it_get_current_data, + spl_fixedarray_it_get_current_key, + spl_fixedarray_it_move_forward, + spl_fixedarray_it_rewind +}; + +zend_object_iterator *spl_fixedarray_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ +{ + spl_fixedarray_it *iterator; + spl_fixedarray_object *fixedarray_object = (spl_fixedarray_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (by_ref) { + zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC); + return NULL; + } + + Z_ADDREF_P(object); + + iterator = emalloc(sizeof(spl_fixedarray_it)); + iterator->intern.it.data = (void*)object; + iterator->intern.it.funcs = &spl_fixedarray_it_funcs; + iterator->intern.ce = ce; + iterator->intern.value = NULL; + iterator->object = fixedarray_object; + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_splfixedarray_construct, 0, 0, 0) + ZEND_ARG_INFO(0, size) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_fixedarray_setSize, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_fixedarray_fromArray, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, save_indexes) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_splfixedarray_void, 0) +ZEND_END_ARG_INFO() + +static zend_function_entry spl_funcs_SplFixedArray[] = { /* {{{ */ + SPL_ME(SplFixedArray, __construct, arginfo_splfixedarray_construct,ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, count, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, toArray, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, fromArray, arginfo_fixedarray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + SPL_ME(SplFixedArray, getSize, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, setSize, arginfo_fixedarray_setSize, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, offsetExists, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, offsetGet, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, offsetSet, arginfo_fixedarray_offsetSet, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, offsetUnset, arginfo_fixedarray_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, rewind, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, current, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, key, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, next, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + SPL_ME(SplFixedArray, valid, arginfo_splfixedarray_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION */ +PHP_MINIT_FUNCTION(spl_fixedarray) +{ + REGISTER_SPL_STD_CLASS_EX(SplFixedArray, spl_fixedarray_new, spl_funcs_SplFixedArray); + memcpy(&spl_handler_SplFixedArray, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_SplFixedArray.clone_obj = spl_fixedarray_object_clone; + spl_handler_SplFixedArray.read_dimension = spl_fixedarray_object_read_dimension; + spl_handler_SplFixedArray.write_dimension = spl_fixedarray_object_write_dimension; + spl_handler_SplFixedArray.unset_dimension = spl_fixedarray_object_unset_dimension; + spl_handler_SplFixedArray.has_dimension = spl_fixedarray_object_has_dimension; + spl_handler_SplFixedArray.count_elements = spl_fixedarray_object_count_elements; + spl_handler_SplFixedArray.get_properties = spl_fixedarray_object_get_properties; + spl_handler_SplFixedArray.get_gc = spl_fixedarray_object_get_gc; + + REGISTER_SPL_IMPLEMENTS(SplFixedArray, Iterator); + REGISTER_SPL_IMPLEMENTS(SplFixedArray, ArrayAccess); + REGISTER_SPL_IMPLEMENTS(SplFixedArray, Countable); + + spl_ce_SplFixedArray->get_iterator = spl_fixedarray_get_iterator; + + return SUCCESS; +} +/* }}} */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_fixedarray.h b/ext/spl/spl_fixedarray.h new file mode 100644 index 0000000..8f1b8df --- /dev/null +++ b/ext/spl/spl_fixedarray.h @@ -0,0 +1,38 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Antony Dovgal <tony@daylessday.org> | + | Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef SPL_FIXEDARRAY_H +#define SPL_FIXEDARRAY_H + +extern PHPAPI zend_class_entry *spl_ce_SplFixedArray; + +PHP_MINIT_FUNCTION(spl_fixedarray); + +#endif /* SPL_FIXEDARRAY_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_functions.c b/ext/spl/spl_functions.c new file mode 100644 index 0000000..7f17d5e --- /dev/null +++ b/ext/spl/spl_functions.c @@ -0,0 +1,153 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_spl.h" + +/* {{{ spl_register_interface */ +void spl_register_interface(zend_class_entry ** ppce, char * class_name, const zend_function_entry * functions TSRMLS_DC) +{ + zend_class_entry ce; + + INIT_CLASS_ENTRY_EX(ce, class_name, strlen(class_name), functions); + *ppce = zend_register_internal_interface(&ce TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_register_std_class */ +PHPAPI void spl_register_std_class(zend_class_entry ** ppce, char * class_name, void * obj_ctor, const zend_function_entry * function_list TSRMLS_DC) +{ + zend_class_entry ce; + + INIT_CLASS_ENTRY_EX(ce, class_name, strlen(class_name), function_list); + *ppce = zend_register_internal_class(&ce TSRMLS_CC); + + /* entries changed by initialize */ + if (obj_ctor) { + (*ppce)->create_object = obj_ctor; + } +} +/* }}} */ + +/* {{{ spl_register_sub_class */ +PHPAPI void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, void *obj_ctor, const zend_function_entry * function_list TSRMLS_DC) +{ + zend_class_entry ce; + + INIT_CLASS_ENTRY_EX(ce, class_name, strlen(class_name), function_list); + *ppce = zend_register_internal_class_ex(&ce, parent_ce, NULL TSRMLS_CC); + + /* entries changed by initialize */ + if (obj_ctor) { + (*ppce)->create_object = obj_ctor; + } else { + (*ppce)->create_object = parent_ce->create_object; + } +} +/* }}} */ + +/* {{{ spl_register_property */ +void spl_register_property( zend_class_entry * class_entry, char *prop_name, int prop_name_len, int prop_flags TSRMLS_DC) +{ + zend_declare_property_null(class_entry, prop_name, prop_name_len, prop_flags TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_add_class_name */ +void spl_add_class_name(zval *list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC) +{ + if (!allow || (allow > 0 && pce->ce_flags & ce_flags) || (allow < 0 && !(pce->ce_flags & ce_flags))) { + size_t len = pce->name_length; + zval *tmp; + + if (zend_hash_find(Z_ARRVAL_P(list), pce->name, len+1, (void*)&tmp) == FAILURE) { + MAKE_STD_ZVAL(tmp); + ZVAL_STRINGL(tmp, pce->name, pce->name_length, 1); + zend_hash_add(Z_ARRVAL_P(list), pce->name, len+1, &tmp, sizeof(zval *), NULL); + } + } +} +/* }}} */ + +/* {{{ spl_add_interfaces */ +void spl_add_interfaces(zval *list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC) +{ + zend_uint num_interfaces; + + for (num_interfaces = 0; num_interfaces < pce->num_interfaces; num_interfaces++) { + spl_add_class_name(list, pce->interfaces[num_interfaces], allow, ce_flags TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ spl_add_traits */ +void spl_add_traits(zval *list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC) +{ + zend_uint num_traits; + + for (num_traits = 0; num_traits < pce->num_traits; num_traits++) { + spl_add_class_name(list, pce->traits[num_traits], allow, ce_flags TSRMLS_CC); + } +} +/* }}} */ + + +/* {{{ spl_add_classes */ +int spl_add_classes(zend_class_entry *pce, zval *list, int sub, int allow, int ce_flags TSRMLS_DC) +{ + if (!pce) { + return 0; + } + spl_add_class_name(list, pce, allow, ce_flags TSRMLS_CC); + if (sub) { + spl_add_interfaces(list, pce, allow, ce_flags TSRMLS_CC); + while (pce->parent) { + pce = pce->parent; + spl_add_classes(pce, list, sub, allow, ce_flags TSRMLS_CC); + } + } + return 0; +} +/* }}} */ + +char * spl_gen_private_prop_name(zend_class_entry *ce, char *prop_name, int prop_len, int *name_len TSRMLS_DC) /* {{{ */ +{ + char *rv; + + zend_mangle_property_name(&rv, name_len, ce->name, ce->name_length, prop_name, prop_len, 0); + + return rv; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_functions.h b/ext/spl/spl_functions.h new file mode 100644 index 0000000..29ce4a7 --- /dev/null +++ b/ext/spl/spl_functions.h @@ -0,0 +1,91 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef PHP_FUNCTIONS_H +#define PHP_FUNCTIONS_H + +#include "php.h" + +typedef zend_object_value (*create_object_func_t)(zend_class_entry *class_type TSRMLS_DC); + +#define REGISTER_SPL_STD_CLASS(class_name, obj_ctor) \ + spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, NULL TSRMLS_CC); + +#define REGISTER_SPL_STD_CLASS_EX(class_name, obj_ctor, funcs) \ + spl_register_std_class(&spl_ce_ ## class_name, # class_name, obj_ctor, funcs TSRMLS_CC); + +#define REGISTER_SPL_SUB_CLASS_EX(class_name, parent_class_name, obj_ctor, funcs) \ + spl_register_sub_class(&spl_ce_ ## class_name, spl_ce_ ## parent_class_name, # class_name, obj_ctor, funcs TSRMLS_CC); + +#define REGISTER_SPL_INTERFACE(class_name) \ + spl_register_interface(&spl_ce_ ## class_name, # class_name, spl_funcs_ ## class_name TSRMLS_CC); + +#define REGISTER_SPL_IMPLEMENTS(class_name, interface_name) \ + zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, spl_ce_ ## interface_name); + +#define REGISTER_SPL_ITERATOR(class_name) \ + zend_class_implements(spl_ce_ ## class_name TSRMLS_CC, 1, zend_ce_iterator); + +#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); + +void spl_register_std_class(zend_class_entry ** ppce, char * class_name, create_object_func_t ctor, const zend_function_entry * function_list TSRMLS_DC); +void spl_register_sub_class(zend_class_entry ** ppce, zend_class_entry * parent_ce, char * class_name, create_object_func_t ctor, const zend_function_entry * function_list TSRMLS_DC); +void spl_register_interface(zend_class_entry ** ppce, char * class_name, const zend_function_entry *functions 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 + allow > 0: allow all that match and mask ce_flags + allow < 0: disallow all that match and mask ce_flags + */ +void spl_add_class_name(zval * list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC); +void spl_add_interfaces(zval * list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC); +void spl_add_traits(zval * list, zend_class_entry * pce, int allow, int ce_flags TSRMLS_DC); +int spl_add_classes(zend_class_entry *pce, zval *list, int sub, int allow, int ce_flags TSRMLS_DC); + +/* caller must efree(return) */ +char * spl_gen_private_prop_name(zend_class_entry *ce, char *prop_name, int prop_len, int *name_len TSRMLS_DC); + +#define SPL_ME(class_name, function_name, arg_info, flags) \ + PHP_ME( spl_ ## class_name, function_name, arg_info, flags) + +#define SPL_ABSTRACT_ME(class_name, function_name, arg_info) \ + ZEND_ABSTRACT_ME( spl_ ## class_name, function_name, arg_info) + +#define SPL_METHOD(class_name, function_name) \ + PHP_METHOD(spl_ ## class_name, function_name) + +#define SPL_MA(class_name, function_name, alias_class, alias_function, arg_info, flags) \ + PHP_MALIAS(spl_ ## alias_class, function_name, alias_function, arg_info, flags) +#endif /* PHP_FUNCTIONS_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c new file mode 100644 index 0000000..d2de85b --- /dev/null +++ b/ext/spl/spl_heap.c @@ -0,0 +1,1262 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "zend_exceptions.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_iterators.h" +#include "spl_heap.h" +#include "spl_exceptions.h" + +#define PTR_HEAP_BLOCK_SIZE 64 + +#define SPL_HEAP_CORRUPTED 0x00000001 + +#define SPL_PQUEUE_EXTR_MASK 0x00000003 +#define SPL_PQUEUE_EXTR_BOTH 0x00000003 +#define SPL_PQUEUE_EXTR_DATA 0x00000001 +#define SPL_PQUEUE_EXTR_PRIORITY 0x00000002 + +zend_object_handlers spl_handler_SplHeap; +zend_object_handlers spl_handler_SplPriorityQueue; + +PHPAPI zend_class_entry *spl_ce_SplHeap; +PHPAPI zend_class_entry *spl_ce_SplMaxHeap; +PHPAPI zend_class_entry *spl_ce_SplMinHeap; +PHPAPI zend_class_entry *spl_ce_SplPriorityQueue; + +typedef void *spl_ptr_heap_element; + +typedef void (*spl_ptr_heap_dtor_func)(spl_ptr_heap_element TSRMLS_DC); +typedef void (*spl_ptr_heap_ctor_func)(spl_ptr_heap_element TSRMLS_DC); +typedef int (*spl_ptr_heap_cmp_func)(spl_ptr_heap_element, spl_ptr_heap_element, void* TSRMLS_DC); + +typedef struct _spl_ptr_heap { + spl_ptr_heap_element *elements; + spl_ptr_heap_ctor_func ctor; + spl_ptr_heap_dtor_func dtor; + spl_ptr_heap_cmp_func cmp; + int count; + int max_size; + int flags; +} spl_ptr_heap; + +typedef struct _spl_heap_object spl_heap_object; +typedef struct _spl_heap_it spl_heap_it; + +struct _spl_heap_object { + zend_object std; + spl_ptr_heap *heap; + zval *retval; + int flags; + zend_class_entry *ce_get_iterator; + zend_function *fptr_cmp; + zend_function *fptr_count; + HashTable *debug_info; +}; + +/* define an overloaded iterator structure */ +struct _spl_heap_it { + zend_user_iterator intern; + int flags; + spl_heap_object *object; +}; + +/* {{{ spl_ptr_heap */ +static void spl_ptr_heap_zval_dtor(spl_ptr_heap_element elem TSRMLS_DC) { /* {{{ */ + if (elem) { + zval_ptr_dtor((zval **)&elem); + } +} +/* }}} */ + +static void spl_ptr_heap_zval_ctor(spl_ptr_heap_element elem TSRMLS_DC) { /* {{{ */ + Z_ADDREF_P((zval *)elem); +} +/* }}} */ + +static int spl_ptr_heap_cmp_cb_helper(zval *object, spl_heap_object *heap_object, zval *a, zval *b, long *result TSRMLS_DC) { /* {{{ */ + zval *result_p = NULL; + + zend_call_method_with_2_params(&object, heap_object->std.ce, &heap_object->fptr_cmp, "compare", &result_p, a, b); + + if (EG(exception)) { + return FAILURE; + } + + convert_to_long(result_p); + *result = Z_LVAL_P(result_p); + + zval_ptr_dtor(&result_p); + + return SUCCESS; +} +/* }}} */ + +static zval **spl_pqueue_extract_helper(zval **value, int flags) /* {{{ */ +{ + if ((flags & SPL_PQUEUE_EXTR_BOTH) == SPL_PQUEUE_EXTR_BOTH) { + return value; + } else if ((flags & SPL_PQUEUE_EXTR_BOTH) > 0) { + + if ((flags & SPL_PQUEUE_EXTR_DATA) == SPL_PQUEUE_EXTR_DATA) { + zval **data; + if (zend_hash_find(Z_ARRVAL_PP(value), "data", sizeof("data"), (void **) &data) == SUCCESS) { + return data; + } + } else { + zval **priority; + if (zend_hash_find(Z_ARRVAL_PP(value), "priority", sizeof("priority"), (void **) &priority) == SUCCESS) { + return priority; + } + } + } + + return NULL; +} +/* }}} */ + +static int spl_ptr_heap_zval_max_cmp(spl_ptr_heap_element a, spl_ptr_heap_element b, void* object TSRMLS_DC) { /* {{{ */ + zval result; + + if (EG(exception)) { + return 0; + } + + if (object) { + spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object((zval *)object TSRMLS_CC); + if (heap_object->fptr_cmp) { + long lval = 0; + if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, (zval *)a, (zval *)b, &lval TSRMLS_CC) == FAILURE) { + /* exception or call failure */ + return 0; + } + return lval; + } + } + + INIT_ZVAL(result); + compare_function(&result, (zval *)a, (zval *)b TSRMLS_CC); + return Z_LVAL(result); +} +/* }}} */ + +static int spl_ptr_heap_zval_min_cmp(spl_ptr_heap_element a, spl_ptr_heap_element b, void* object TSRMLS_DC) { /* {{{ */ + zval result; + + if (EG(exception)) { + return 0; + } + + if (object) { + spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object((zval *)object TSRMLS_CC); + if (heap_object->fptr_cmp) { + long lval = 0; + if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, (zval *)a, (zval *)b, &lval TSRMLS_CC) == FAILURE) { + /* exception or call failure */ + return 0; + } + return lval; + } + } + + INIT_ZVAL(result); + compare_function(&result, (zval *)b, (zval *)a TSRMLS_CC); + return Z_LVAL(result); +} +/* }}} */ + +static int spl_ptr_pqueue_zval_cmp(spl_ptr_heap_element a, spl_ptr_heap_element b, void* object TSRMLS_DC) { /* {{{ */ + zval result; + zval **a_priority_pp = spl_pqueue_extract_helper((zval **)&a, SPL_PQUEUE_EXTR_PRIORITY); + zval **b_priority_pp = spl_pqueue_extract_helper((zval **)&b, SPL_PQUEUE_EXTR_PRIORITY); + + if ((!a_priority_pp) || (!b_priority_pp)) { + zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); + return 0; + } + if (EG(exception)) { + return 0; + } + + if (object) { + spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC); + if (heap_object->fptr_cmp) { + long lval = 0; + if (spl_ptr_heap_cmp_cb_helper((zval *)object, heap_object, *a_priority_pp, *b_priority_pp, &lval TSRMLS_CC) == FAILURE) { + /* exception or call failure */ + return 0; + } + return lval; + } + } + + INIT_ZVAL(result); + compare_function(&result, *a_priority_pp, *b_priority_pp TSRMLS_CC); + return Z_LVAL(result); +} +/* }}} */ + +static spl_ptr_heap *spl_ptr_heap_init(spl_ptr_heap_cmp_func cmp, spl_ptr_heap_ctor_func ctor, spl_ptr_heap_dtor_func dtor) /* {{{ */ +{ + spl_ptr_heap *heap = emalloc(sizeof(spl_ptr_heap)); + + heap->dtor = dtor; + heap->ctor = ctor; + heap->cmp = cmp; + heap->elements = safe_emalloc(sizeof(spl_ptr_heap_element), PTR_HEAP_BLOCK_SIZE, 0); + heap->max_size = PTR_HEAP_BLOCK_SIZE; + heap->count = 0; + heap->flags = 0; + + return heap; +} +/* }}} */ + +static void spl_ptr_heap_insert(spl_ptr_heap *heap, spl_ptr_heap_element elem, void *cmp_userdata TSRMLS_DC) { /* {{{ */ + int i; + + if (heap->count+1 > heap->max_size) { + /* we need to allocate more memory */ + heap->elements = (void **) safe_erealloc(heap->elements, sizeof(spl_ptr_heap_element), (heap->max_size), (sizeof(spl_ptr_heap_element) * (heap->max_size))); + heap->max_size *= 2; + } + + heap->ctor(elem TSRMLS_CC); + + /* sifting up */ + for(i = heap->count++; i > 0 && heap->cmp(heap->elements[(i-1)/2], elem, cmp_userdata TSRMLS_CC) < 0; i = (i-1)/2) { + heap->elements[i] = heap->elements[(i-1)/2]; + } + + if (EG(exception)) { + /* exception thrown during comparison */ + heap->flags |= SPL_HEAP_CORRUPTED; + } + + heap->elements[i] = elem; + +} +/* }}} */ + +static spl_ptr_heap_element spl_ptr_heap_top(spl_ptr_heap *heap) { /* {{{ */ + if (heap->count == 0) { + return NULL; + } + + return heap->elements[0]; +} +/* }}} */ + +static spl_ptr_heap_element spl_ptr_heap_delete_top(spl_ptr_heap *heap, void *cmp_userdata TSRMLS_DC) { /* {{{ */ + int i, j; + const int limit = (heap->count-1)/2; + spl_ptr_heap_element top; + spl_ptr_heap_element bottom; + + if (heap->count == 0) { + return NULL; + } + + top = heap->elements[0]; + bottom = heap->elements[--heap->count]; + + for( i = 0; i < limit; i = j) + { + /* Find smaller child */ + j = i*2+1; + if(j != heap->count && heap->cmp(heap->elements[j+1], heap->elements[j], cmp_userdata TSRMLS_CC) > 0) { + j++; /* next child is bigger */ + } + + /* swap elements between two levels */ + if(heap->cmp(bottom, heap->elements[j], cmp_userdata TSRMLS_CC) < 0) { + heap->elements[i] = heap->elements[j]; + } else { + break; + } + } + + if (EG(exception)) { + /* exception thrown during comparison */ + heap->flags |= SPL_HEAP_CORRUPTED; + } + + heap->elements[i] = bottom; + heap->dtor(top TSRMLS_CC); + return top; +} +/* }}} */ + +static spl_ptr_heap *spl_ptr_heap_clone(spl_ptr_heap *from TSRMLS_DC) { /* {{{ */ + int i; + + spl_ptr_heap *heap = emalloc(sizeof(spl_ptr_heap)); + + heap->dtor = from->dtor; + heap->ctor = from->ctor; + heap->cmp = from->cmp; + heap->max_size = from->max_size; + heap->count = from->count; + heap->flags = from->flags; + + heap->elements = safe_emalloc(sizeof(spl_ptr_heap_element),from->max_size,0); + memcpy(heap->elements, from->elements, sizeof(spl_ptr_heap_element)*from->max_size); + + for (i=0; i < heap->count; ++i) { + heap->ctor(heap->elements[i] TSRMLS_CC); + } + + return heap; +} +/* }}} */ + +static void spl_ptr_heap_destroy(spl_ptr_heap *heap TSRMLS_DC) { /* {{{ */ + int i; + + for (i=0; i < heap->count; ++i) { + heap->dtor(heap->elements[i] TSRMLS_CC); + } + + efree(heap->elements); + efree(heap); +} +/* }}} */ + +static int spl_ptr_heap_count(spl_ptr_heap *heap) { /* {{{ */ + return heap->count; +} +/* }}} */ +/* }}} */ + +zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); + +static void spl_heap_object_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + int i; + spl_heap_object *intern = (spl_heap_object *)object; + + zend_object_std_dtor(&intern->std TSRMLS_CC); + + for (i = 0; i < intern->heap->count; ++i) { + if (intern->heap->elements[i]) { + zval_ptr_dtor((zval **)&intern->heap->elements[i]); + } + } + + spl_ptr_heap_destroy(intern->heap TSRMLS_CC); + + zval_ptr_dtor(&intern->retval); + + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + + efree(object); +} +/* }}} */ + +static zend_object_value spl_heap_object_new_ex(zend_class_entry *class_type, spl_heap_object **obj, zval *orig, int clone_orig TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + spl_heap_object *intern; + zend_class_entry *parent = class_type; + int inherited = 0; + + intern = ecalloc(1, sizeof(spl_heap_object)); + *obj = intern; + ALLOC_INIT_ZVAL(intern->retval); + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + intern->flags = 0; + intern->fptr_cmp = NULL; + intern->debug_info = NULL; + + if (orig) { + spl_heap_object *other = (spl_heap_object*)zend_object_store_get_object(orig TSRMLS_CC); + intern->ce_get_iterator = other->ce_get_iterator; + + if (clone_orig) { + int i; + intern->heap = spl_ptr_heap_clone(other->heap TSRMLS_CC); + for (i = 0; i < intern->heap->count; ++i) { + if (intern->heap->elements[i]) { + Z_ADDREF_P((zval *)intern->heap->elements[i]); + } + } + } else { + intern->heap = other->heap; + } + + intern->flags = other->flags; + } else { + intern->heap = spl_ptr_heap_init(spl_ptr_heap_zval_max_cmp, spl_ptr_heap_zval_ctor, spl_ptr_heap_zval_dtor); + } + + retval.handlers = &spl_handler_SplHeap; + + while (parent) { + if (parent == spl_ce_SplPriorityQueue) { + intern->heap->cmp = spl_ptr_pqueue_zval_cmp; + intern->flags = SPL_PQUEUE_EXTR_DATA; + retval.handlers = &spl_handler_SplPriorityQueue; + break; + } + + if (parent == spl_ce_SplMinHeap) { + intern->heap->cmp = spl_ptr_heap_zval_min_cmp; + break; + } + + if (parent == spl_ce_SplMaxHeap) { + intern->heap->cmp = spl_ptr_heap_zval_max_cmp; + break; + } + + if (parent == spl_ce_SplHeap) { + break; + } + + parent = parent->parent; + inherited = 1; + } + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, spl_heap_object_free_storage, NULL TSRMLS_CC); + + if (!parent) { /* this must never happen */ + php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of SplHeap"); + } + + if (inherited) { + zend_hash_find(&class_type->function_table, "compare", sizeof("compare"), (void **) &intern->fptr_cmp); + if (intern->fptr_cmp->common.scope == parent) { + intern->fptr_cmp = NULL; + } + zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count); + if (intern->fptr_count->common.scope == parent) { + intern->fptr_count = NULL; + } + } + + return retval; +} +/* }}} */ + +static zend_object_value spl_heap_object_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ +{ + spl_heap_object *tmp; + return spl_heap_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC); +} +/* }}} */ + +static zend_object_value spl_heap_object_clone(zval *zobject TSRMLS_DC) /* {{{ */ +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_heap_object *intern; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + new_obj_val = spl_heap_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC); + new_object = &intern->std; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + return new_obj_val; +} +/* }}} */ + +static int spl_heap_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */ +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (intern->fptr_count) { + zval *rv; + zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv); + if (rv) { + zval_ptr_dtor(&intern->retval); + MAKE_STD_ZVAL(intern->retval); + ZVAL_ZVAL(intern->retval, rv, 1, 1); + convert_to_long(intern->retval); + *count = (long) Z_LVAL_P(intern->retval); + return SUCCESS; + } + *count = 0; + return FAILURE; + } + + *count = spl_ptr_heap_count(intern->heap); + + return SUCCESS; +} +/* }}} */ + +static HashTable* spl_heap_object_get_debug_info_helper(zend_class_entry *ce, zval *obj, int *is_temp TSRMLS_DC) { /* {{{ */ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(obj TSRMLS_CC); + zval *tmp, zrv, *heap_array; + char *pnstr; + int pnlen; + int i; + + *is_temp = 0; + + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0); + } + + if (intern->debug_info->nApplyCount == 0) { + INIT_PZVAL(&zrv); + Z_ARRVAL(zrv) = intern->debug_info; + + zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + pnstr = spl_gen_private_prop_name(ce, "flags", sizeof("flags")-1, &pnlen TSRMLS_CC); + add_assoc_long_ex(&zrv, pnstr, pnlen+1, intern->flags); + efree(pnstr); + + pnstr = spl_gen_private_prop_name(ce, "isCorrupted", sizeof("isCorrupted")-1, &pnlen TSRMLS_CC); + add_assoc_bool_ex(&zrv, pnstr, pnlen+1, intern->heap->flags&SPL_HEAP_CORRUPTED); + efree(pnstr); + + ALLOC_INIT_ZVAL(heap_array); + array_init(heap_array); + + for (i = 0; i < intern->heap->count; ++i) { + add_index_zval(heap_array, i, (zval *)intern->heap->elements[i]); + Z_ADDREF_P(intern->heap->elements[i]); + } + + pnstr = spl_gen_private_prop_name(ce, "heap", sizeof("heap")-1, &pnlen TSRMLS_CC); + add_assoc_zval_ex(&zrv, pnstr, pnlen+1, heap_array); + efree(pnstr); + } + + return intern->debug_info; +} +/* }}} */ + +static HashTable* spl_heap_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */ +{ + return spl_heap_object_get_debug_info_helper(spl_ce_SplHeap, obj, is_temp TSRMLS_CC); +} +/* }}} */ + +static HashTable* spl_pqueue_object_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */ +{ + return spl_heap_object_get_debug_info_helper(spl_ce_SplPriorityQueue, obj, is_temp TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int SplHeap::count() U + Return the number of elements in the heap. */ +SPL_METHOD(SplHeap, count) +{ + long count; + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + count = spl_ptr_heap_count(intern->heap); + RETURN_LONG(count); +} +/* }}} */ + +/* {{{ proto int SplHeap::isEmpty() U + Return true if the heap is empty. */ +SPL_METHOD(SplHeap, isEmpty) +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + RETURN_BOOL(spl_ptr_heap_count(intern->heap)==0); +} +/* }}} */ + +/* {{{ proto bool SplHeap::insert(mixed $value) U + Push $value on the heap */ +SPL_METHOD(SplHeap, insert) +{ + zval *value; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + SEPARATE_ARG_IF_REF(value); + + spl_ptr_heap_insert(intern->heap, value, getThis() TSRMLS_CC); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto mixed SplHeap::extract() U + extract the element out of the top of the heap */ +SPL_METHOD(SplHeap, extract) +{ + zval *value; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + value = (zval *)spl_ptr_heap_delete_top(intern->heap, getThis() TSRMLS_CC); + + if (!value) { + zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0 TSRMLS_CC); + return; + } + + RETURN_ZVAL(value, 1, 1); +} +/* }}} */ + +/* {{{ proto bool SplPriorityQueue::insert(mixed $value, mixed $priority) U + Push $value with the priority $priodiry on the priorityqueue */ +SPL_METHOD(SplPriorityQueue, insert) +{ + zval *data, *priority, *elem; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &data, &priority) == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + SEPARATE_ARG_IF_REF(data); + SEPARATE_ARG_IF_REF(priority); + + ALLOC_INIT_ZVAL(elem); + + array_init(elem); + add_assoc_zval_ex(elem, "data", sizeof("data"), data); + add_assoc_zval_ex(elem, "priority", sizeof("priority"), priority); + + spl_ptr_heap_insert(intern->heap, elem, getThis() TSRMLS_CC); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto mixed SplPriorityQueue::extract() U + extract the element out of the top of the priority queue */ +SPL_METHOD(SplPriorityQueue, extract) +{ + zval *value, *value_out, **value_out_pp; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + value = (zval *)spl_ptr_heap_delete_top(intern->heap, getThis() TSRMLS_CC); + + if (!value) { + zend_throw_exception(spl_ce_RuntimeException, "Can't extract from an empty heap", 0 TSRMLS_CC); + return; + } + + value_out_pp = spl_pqueue_extract_helper(&value, intern->flags); + + + if (!value_out_pp) { + zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); + zval_ptr_dtor(&value); + return; + } + + value_out = *value_out_pp; + + Z_ADDREF_P(value_out); + zval_ptr_dtor(&value); + + RETURN_ZVAL(value_out, 1, 1); +} +/* }}} */ + +/* {{{ proto mixed SplPriorityQueue::top() U + Peek at the top element of the priority queue */ +SPL_METHOD(SplPriorityQueue, top) +{ + zval *value, **value_out; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + value = (zval *)spl_ptr_heap_top(intern->heap); + + if (!value) { + zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0 TSRMLS_CC); + return; + } + + value_out = spl_pqueue_extract_helper(&value, intern->flags); + + if (!value_out) { + zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); + return; + } + + RETURN_ZVAL(*value_out, 1, 0); +} +/* }}} */ + +/* {{{ proto int SplPriorityQueue::setIteratorMode($flags) U + Set the flags of extraction*/ +SPL_METHOD(SplPriorityQueue, setExtractFlags) +{ + long value; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + intern->flags = value & SPL_PQUEUE_EXTR_MASK; + + RETURN_LONG(intern->flags); +} +/* }}} */ + +/* {{{ proto int SplHeap::recoverFromCorruption() U + Recover from a corrupted state*/ +SPL_METHOD(SplHeap, recoverFromCorruption) +{ + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + intern->heap->flags = intern->heap->flags & ~SPL_HEAP_CORRUPTED; + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SplPriorityQueue::compare(mixed $a, mixed $b) U + compare the priorities */ +SPL_METHOD(SplPriorityQueue, compare) +{ + zval *a, *b; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a, &b) == FAILURE) { + return; + } + + RETURN_LONG(spl_ptr_heap_zval_max_cmp(a, b, NULL TSRMLS_CC)); +} +/* }}} */ + +/* {{{ proto mixed SplHeap::top() U + Peek at the top element of the heap */ +SPL_METHOD(SplHeap, top) +{ + zval *value; + spl_heap_object *intern; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) { + return; + } + + intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + value = (zval *)spl_ptr_heap_top(intern->heap); + + if (!value) { + zend_throw_exception(spl_ce_RuntimeException, "Can't peek at an empty heap", 0 TSRMLS_CC); + return; + } + + RETURN_ZVAL(value, 1, 0); +} +/* }}} */ + +/* {{{ proto bool SplMinHeap::compare(mixed $a, mixed $b) U + compare the values */ +SPL_METHOD(SplMinHeap, compare) +{ + zval *a, *b; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a, &b) == FAILURE) { + return; + } + + RETURN_LONG(spl_ptr_heap_zval_min_cmp(a, b, NULL TSRMLS_CC)); +} +/* }}} */ + +/* {{{ proto bool SplMaxHeap::compare(mixed $a, mixed $b) U + compare the values */ +SPL_METHOD(SplMaxHeap, compare) +{ + zval *a, *b; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a, &b) == FAILURE) { + return; + } + + RETURN_LONG(spl_ptr_heap_zval_max_cmp(a, b, NULL TSRMLS_CC)); +} +/* }}} */ + +static void spl_heap_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator = (spl_heap_it *)iter; + + zend_user_it_invalidate_current(iter TSRMLS_CC); + zval_ptr_dtor((zval**)&iterator->intern.it.data); + + efree(iterator); +} +/* }}} */ + +static void spl_heap_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + /* do nothing, the iterator always points to the top element */ +} +/* }}} */ + +static int spl_heap_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator = (spl_heap_it *)iter; + + return (iterator->object->heap->count != 0 ? SUCCESS : FAILURE); +} +/* }}} */ + +static void spl_heap_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator = (spl_heap_it *)iter; + zval **element = (zval **)&iterator->object->heap->elements[0]; + + if (iterator->object->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + if (iterator->object->heap->count == 0 || !*element) { + *data = NULL; + } else { + *data = element; + } +} +/* }}} */ + +static void spl_pqueue_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator = (spl_heap_it *)iter; + zval **element = (zval **)&iterator->object->heap->elements[0]; + + if (iterator->object->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + if (iterator->object->heap->count == 0 || !*element) { + *data = NULL; + } else { + *data = spl_pqueue_extract_helper(element, iterator->object->flags); + if (!*data) { + zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); + } + } +} +/* }}} */ + +static int spl_heap_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator = (spl_heap_it *)iter; + + *int_key = (ulong) iterator->object->heap->count - 1; + return HASH_KEY_IS_LONG; +} +/* }}} */ + +static void spl_heap_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */ +{ + zval *object = (zval*)((zend_user_iterator *)iter)->it.data; + spl_heap_it *iterator = (spl_heap_it *)iter; + spl_ptr_heap_element elem; + + if (iterator->object->heap->flags & SPL_HEAP_CORRUPTED) { + zend_throw_exception(spl_ce_RuntimeException, "Heap is corrupted, heap properties are no longer ensured.", 0 TSRMLS_CC); + return; + } + + elem = spl_ptr_heap_delete_top(iterator->object->heap, object TSRMLS_CC); + + if (elem != NULL) { + zval_ptr_dtor((zval **)&elem); + } + + zend_user_it_invalidate_current(iter TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int SplHeap::key() U + Return current array key */ +SPL_METHOD(SplHeap, key) +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->heap->count - 1); +} +/* }}} */ + +/* {{{ proto void SplHeap::next() U + Move to next entry */ +SPL_METHOD(SplHeap, next) +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_ptr_heap_element elem = spl_ptr_heap_delete_top(intern->heap, getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (elem != NULL) { + zval_ptr_dtor((zval **)&elem); + } +} +/* }}} */ + +/* {{{ proto bool SplHeap::valid() U + Check whether the datastructure contains more entries */ +SPL_METHOD(SplHeap, valid) +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(intern->heap->count != 0); +} +/* }}} */ + +/* {{{ proto void SplHeap::rewind() U + Rewind the datastructure back to the start */ +SPL_METHOD(SplHeap, rewind) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* do nothing, the iterator always points to the top element */ +} +/* }}} */ + +/* {{{ proto mixed|NULL SplHeap::current() U + Return current datastructure entry */ +SPL_METHOD(SplHeap, current) +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval *element = (zval *)intern->heap->elements[0]; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (!intern->heap->count || !element) { + RETURN_NULL(); + } else { + RETURN_ZVAL(element, 1, 0); + } +} +/* }}} */ + +/* {{{ proto mixed|NULL SplPriorityQueue::current() U + Return current datastructure entry */ +SPL_METHOD(SplPriorityQueue, current) +{ + spl_heap_object *intern = (spl_heap_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval **element = (zval **)&intern->heap->elements[0]; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (!intern->heap->count || !*element) { + RETURN_NULL(); + } else { + zval **data = spl_pqueue_extract_helper(element, intern->flags); + + if (!data) { + zend_error(E_RECOVERABLE_ERROR, "Unable to extract from the PriorityQueue node"); + RETURN_NULL(); + } + + RETURN_ZVAL(*data, 1, 0); + } +} +/* }}} */ + +/* iterator handler table */ +zend_object_iterator_funcs spl_heap_it_funcs = { + spl_heap_it_dtor, + spl_heap_it_valid, + spl_heap_it_get_current_data, + spl_heap_it_get_current_key, + spl_heap_it_move_forward, + spl_heap_it_rewind +}; + +zend_object_iterator_funcs spl_pqueue_it_funcs = { + spl_heap_it_dtor, + spl_heap_it_valid, + spl_pqueue_it_get_current_data, + spl_heap_it_get_current_key, + spl_heap_it_move_forward, + spl_heap_it_rewind +}; + +zend_object_iterator *spl_heap_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator; + spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (by_ref) { + zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC); + return NULL; + } + + Z_ADDREF_P(object); + + iterator = emalloc(sizeof(spl_heap_it)); + iterator->intern.it.data = (void*)object; + iterator->intern.it.funcs = &spl_heap_it_funcs; + iterator->intern.ce = ce; + iterator->intern.value = NULL; + iterator->flags = heap_object->flags; + iterator->object = heap_object; + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +zend_object_iterator *spl_pqueue_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */ +{ + spl_heap_it *iterator; + spl_heap_object *heap_object = (spl_heap_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (by_ref) { + zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0 TSRMLS_CC); + return NULL; + } + + Z_ADDREF_P(object); + + iterator = emalloc(sizeof(spl_heap_it)); + iterator->intern.it.data = (void*)object; + iterator->intern.it.funcs = &spl_pqueue_it_funcs; + iterator->intern.ce = ce; + iterator->intern.value = NULL; + iterator->flags = heap_object->flags; + iterator->object = heap_object; + + return (zend_object_iterator*)iterator; +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_heap_insert, 0) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_heap_compare, 0) + ZEND_ARG_INFO(0, a) + ZEND_ARG_INFO(0, b) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_pqueue_insert, 0) + ZEND_ARG_INFO(0, value) + ZEND_ARG_INFO(0, priority) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_pqueue_setflags, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_splheap_void, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry spl_funcs_SplMinHeap[] = { + SPL_ME(SplMinHeap, compare, arginfo_heap_compare, ZEND_ACC_PROTECTED) + {NULL, NULL, NULL} +}; +static const zend_function_entry spl_funcs_SplMaxHeap[] = { + SPL_ME(SplMaxHeap, compare, arginfo_heap_compare, ZEND_ACC_PROTECTED) + {NULL, NULL, NULL} +}; + +static const zend_function_entry spl_funcs_SplPriorityQueue[] = { + SPL_ME(SplPriorityQueue, compare, arginfo_heap_compare, ZEND_ACC_PUBLIC) + SPL_ME(SplPriorityQueue, insert, arginfo_pqueue_insert, ZEND_ACC_PUBLIC) + SPL_ME(SplPriorityQueue, setExtractFlags, arginfo_pqueue_setflags, ZEND_ACC_PUBLIC) + SPL_ME(SplPriorityQueue, top, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplPriorityQueue, extract, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, count, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, isEmpty, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, rewind, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplPriorityQueue, current, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, key, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, next, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, valid, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, recoverFromCorruption, arginfo_splheap_void, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +static const zend_function_entry spl_funcs_SplHeap[] = { + SPL_ME(SplHeap, extract, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, insert, arginfo_heap_insert, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, top, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, count, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, isEmpty, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, rewind, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, current, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, key, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, next, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, valid, arginfo_splheap_void, ZEND_ACC_PUBLIC) + SPL_ME(SplHeap, recoverFromCorruption, arginfo_splheap_void, ZEND_ACC_PUBLIC) + ZEND_FENTRY(compare, NULL, NULL, ZEND_ACC_PROTECTED|ZEND_ACC_ABSTRACT) + {NULL, NULL, NULL} +}; +/* }}} */ + +PHP_MINIT_FUNCTION(spl_heap) /* {{{ */ +{ + REGISTER_SPL_STD_CLASS_EX(SplHeap, spl_heap_object_new, spl_funcs_SplHeap); + memcpy(&spl_handler_SplHeap, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_SplHeap.clone_obj = spl_heap_object_clone; + spl_handler_SplHeap.count_elements = spl_heap_object_count_elements; + spl_handler_SplHeap.get_debug_info = spl_heap_object_get_debug_info; + + REGISTER_SPL_IMPLEMENTS(SplHeap, Iterator); + REGISTER_SPL_IMPLEMENTS(SplHeap, Countable); + + spl_ce_SplHeap->get_iterator = spl_heap_get_iterator; + + REGISTER_SPL_SUB_CLASS_EX(SplMinHeap, SplHeap, spl_heap_object_new, spl_funcs_SplMinHeap); + REGISTER_SPL_SUB_CLASS_EX(SplMaxHeap, SplHeap, spl_heap_object_new, spl_funcs_SplMaxHeap); + + spl_ce_SplMaxHeap->get_iterator = spl_heap_get_iterator; + spl_ce_SplMinHeap->get_iterator = spl_heap_get_iterator; + + REGISTER_SPL_STD_CLASS_EX(SplPriorityQueue, spl_heap_object_new, spl_funcs_SplPriorityQueue); + memcpy(&spl_handler_SplPriorityQueue, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_SplPriorityQueue.clone_obj = spl_heap_object_clone; + spl_handler_SplPriorityQueue.count_elements = spl_heap_object_count_elements; + spl_handler_SplPriorityQueue.get_debug_info = spl_pqueue_object_get_debug_info; + + REGISTER_SPL_IMPLEMENTS(SplPriorityQueue, Iterator); + REGISTER_SPL_IMPLEMENTS(SplPriorityQueue, Countable); + + spl_ce_SplPriorityQueue->get_iterator = spl_pqueue_get_iterator; + + REGISTER_SPL_CLASS_CONST_LONG(SplPriorityQueue, "EXTR_BOTH", SPL_PQUEUE_EXTR_BOTH); + REGISTER_SPL_CLASS_CONST_LONG(SplPriorityQueue, "EXTR_PRIORITY", SPL_PQUEUE_EXTR_PRIORITY); + REGISTER_SPL_CLASS_CONST_LONG(SplPriorityQueue, "EXTR_DATA", SPL_PQUEUE_EXTR_DATA); + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ + diff --git a/ext/spl/spl_heap.h b/ext/spl/spl_heap.h new file mode 100644 index 0000000..11bce04 --- /dev/null +++ b/ext/spl/spl_heap.h @@ -0,0 +1,44 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_HEAP_H +#define SPL_HEAP_H + +#include "php.h" +#include "php_spl.h" + +extern PHPAPI zend_class_entry *spl_ce_SplHeap; +extern PHPAPI zend_class_entry *spl_ce_SplMinHeap; +extern PHPAPI zend_class_entry *spl_ce_SplMaxHeap; + +extern PHPAPI zend_class_entry *spl_ce_SplPriorityQueue; + +PHP_MINIT_FUNCTION(spl_heap); + +#endif /* SPL_HEAP_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c new file mode 100644 index 0000000..e6cd155 --- /dev/null +++ b/ext/spl/spl_iterators.c @@ -0,0 +1,3774 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "zend_exceptions.h" +#include "zend_interfaces.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_iterators.h" +#include "spl_directory.h" +#include "spl_array.h" +#include "spl_exceptions.h" +#include "ext/standard/php_smart_str.h" + +#ifdef accept +#undef accept +#endif + +PHPAPI zend_class_entry *spl_ce_RecursiveIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator; +PHPAPI zend_class_entry *spl_ce_FilterIterator; +PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator; +PHPAPI zend_class_entry *spl_ce_ParentIterator; +PHPAPI zend_class_entry *spl_ce_SeekableIterator; +PHPAPI zend_class_entry *spl_ce_LimitIterator; +PHPAPI zend_class_entry *spl_ce_CachingIterator; +PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator; +PHPAPI zend_class_entry *spl_ce_OuterIterator; +PHPAPI zend_class_entry *spl_ce_IteratorIterator; +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; +PHPAPI zend_class_entry *spl_ce_Countable; +PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator; + +ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0) +ZEND_END_ARG_INFO() + +const zend_function_entry spl_funcs_RecursiveIterator[] = { + SPL_ABSTRACT_ME(RecursiveIterator, hasChildren, arginfo_recursive_it_void) + SPL_ABSTRACT_ME(RecursiveIterator, getChildren, arginfo_recursive_it_void) + PHP_FE_END +}; + +typedef enum { + RIT_LEAVES_ONLY = 0, + RIT_SELF_FIRST = 1, + RIT_CHILD_FIRST = 2 +} RecursiveIteratorMode; + +#define RIT_CATCH_GET_CHILD CIT_CATCH_GET_CHILD + +typedef enum { + RTIT_BYPASS_CURRENT = 4, + RTIT_BYPASS_KEY = 8 +} RecursiveTreeIteratorFlags; + +typedef enum { + RS_NEXT = 0, + RS_TEST = 1, + RS_SELF = 2, + RS_CHILD = 3, + RS_START = 4 +} RecursiveIteratorState; + +typedef struct _spl_sub_iterator { + zend_object_iterator *iterator; + zval *zobject; + zend_class_entry *ce; + RecursiveIteratorState state; +} spl_sub_iterator; + +typedef struct _spl_recursive_it_object { + zend_object std; + spl_sub_iterator *iterators; + int level; + RecursiveIteratorMode mode; + int flags; + int max_depth; + zend_bool in_iteration; + zend_function *beginIteration; + zend_function *endIteration; + zend_function *callHasChildren; + zend_function *callGetChildren; + zend_function *beginChildren; + zend_function *endChildren; + zend_function *nextElement; + zend_class_entry *ce; + smart_str prefix[6]; +} spl_recursive_it_object; + +typedef struct _spl_recursive_it_iterator { + zend_object_iterator intern; + zval *zobject; +} spl_recursive_it_iterator; + +static zend_object_handlers spl_handlers_rec_it_it; +static zend_object_handlers spl_handlers_dual_it; + +#define SPL_FETCH_AND_CHECK_DUAL_IT(var, objzval) \ + do { \ + spl_dual_it_object *it = zend_object_store_get_object((objzval) TSRMLS_CC); \ + if (it->dit_type == DIT_Unknown) { \ + zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, \ + "The object is in an invalid state as the parent constructor was not called"); \ + return; \ + } \ + (var) = it; \ + } while (0) + +static void spl_recursive_it_dtor(zend_object_iterator *_iter TSRMLS_DC) +{ + spl_recursive_it_iterator *iter = (spl_recursive_it_iterator*)_iter; + spl_recursive_it_object *object = (spl_recursive_it_object*)_iter->data; + zend_object_iterator *sub_iter; + + while (object->level > 0) { + sub_iter = object->iterators[object->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level--].zobject); + } + object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator)); + object->level = 0; + + zval_ptr_dtor(&iter->zobject); + efree(iter); +} + +static int spl_recursive_it_valid_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC) +{ + zend_object_iterator *sub_iter; + int level = object->level; + + while (level >=0) { + sub_iter = object->iterators[level].iterator; + if (sub_iter->funcs->valid(sub_iter TSRMLS_CC) == SUCCESS) { + return SUCCESS; + } + level--; + } + if (object->endIteration && object->in_iteration) { + zend_call_method_with_0_params(&zthis, object->ce, &object->endIteration, "endIteration", NULL); + } + object->in_iteration = 0; + return FAILURE; +} + +static int spl_recursive_it_valid(zend_object_iterator *iter TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; + + return spl_recursive_it_valid_ex(object, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC); +} + +static void spl_recursive_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; + zend_object_iterator *sub_iter = object->iterators[object->level].iterator; + + sub_iter->funcs->get_current_data(sub_iter, data TSRMLS_CC); +} + +static int spl_recursive_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)iter->data; + zend_object_iterator *sub_iter = object->iterators[object->level].iterator; + + if (sub_iter->funcs->get_current_key) { + return sub_iter->funcs->get_current_key(sub_iter, str_key, str_key_len, int_key TSRMLS_CC); + } else { + *int_key = iter->index; + return HASH_KEY_IS_LONG; + } +} + +static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC) +{ + zend_object_iterator *iterator; + zval *zobject; + zend_class_entry *ce; + zval *retval, *child; + zend_object_iterator *sub_iter; + int has_children; + + while (!EG(exception)) { +next_step: + iterator = object->iterators[object->level].iterator; + 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); + } + } + /* fall through */ + case RS_START: + if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) { + break; + } + object->iterators[object->level].state = RS_TEST; + /* break; */ + case RS_TEST: + ce = object->iterators[object->level].ce; + zobject = object->iterators[object->level].zobject; + if (object->callHasChildren) { + zend_call_method_with_0_params(&zthis, object->ce, &object->callHasChildren, "callHasChildren", &retval); + } 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); + if (has_children) { + if (object->max_depth == -1 || object->max_depth > object->level) { + switch (object->mode) { + case RIT_LEAVES_ONLY: + case RIT_CHILD_FIRST: + object->iterators[object->level].state = RS_CHILD; + goto next_step; + case RIT_SELF_FIRST: + object->iterators[object->level].state = RS_SELF; + goto next_step; + } + } else { + /* do not recurse into */ + if (object->mode == RIT_LEAVES_ONLY) { + /* this is not a leave, so skip it */ + object->iterators[object->level].state = RS_NEXT; + goto next_step; + } + } + } + } + if (object->nextElement) { + 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)) { + zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL); + } + if (object->mode == RIT_SELF_FIRST) { + object->iterators[object->level].state = RS_CHILD; + } else { + object->iterators[object->level].state = RS_NEXT; + } + return /* self */; + case RS_CHILD: + ce = object->iterators[object->level].ce; + zobject = object->iterators[object->level].zobject; + if (object->callGetChildren) { + zend_call_method_with_0_params(&zthis, object->ce, &object->callGetChildren, "callGetChildren", &child); + } else { + zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &child); + } + + if (EG(exception)) { + if (!(object->flags & RIT_CATCH_GET_CHILD)) { + return; + } else { + zend_clear_exception(TSRMLS_C); + if (child) { + zval_ptr_dtor(&child); + } + object->iterators[object->level].state = RS_NEXT; + goto next_step; + } + } + + ce = child && Z_TYPE_P(child) == IS_OBJECT ? Z_OBJCE_P(child) : NULL; + if (!ce || !instanceof_function(ce, spl_ce_RecursiveIterator TSRMLS_CC)) { + if (child) { + zval_ptr_dtor(&child); + } + zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0 TSRMLS_CC); + return; + } + if (object->mode == RIT_CHILD_FIRST) { + object->iterators[object->level].state = RS_SELF; + } else { + 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, 0 TSRMLS_CC); + object->iterators[object->level].iterator = sub_iter; + object->iterators[object->level].zobject = child; + object->iterators[object->level].ce = ce; + object->iterators[object->level].state = RS_START; + if (sub_iter->funcs->rewind) { + sub_iter->funcs->rewind(sub_iter TSRMLS_CC); + } + 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; + } + /* no more elements */ + 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); + object->level--; + } else { + return; /* done completeley */ + } + } +} + +static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zthis TSRMLS_DC) +{ + zend_object_iterator *sub_iter; + + if (!object->iterators) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_P(zthis)->name); + } + + while (object->level) { + sub_iter = object->iterators[object->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level--].zobject); + 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); + } + } + object->iterators = erealloc(object->iterators, sizeof(spl_sub_iterator)); + object->iterators[0].state = RS_START; + sub_iter = object->iterators[0].iterator; + if (sub_iter->funcs->rewind) { + sub_iter->funcs->rewind(sub_iter TSRMLS_CC); + } + 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; + spl_recursive_it_move_forward_ex(object, zthis TSRMLS_CC); +} + +static void spl_recursive_it_move_forward(zend_object_iterator *iter TSRMLS_DC) +{ + spl_recursive_it_move_forward_ex((spl_recursive_it_object*)iter->data, ((spl_recursive_it_iterator*)iter)->zobject TSRMLS_CC); +} + +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, int by_ref TSRMLS_DC) +{ + 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); + if (object->iterators == NULL) { + zend_error(E_ERROR, "The object to be iterated is in an invalid state: " + "the parent constructor has not been called"); + } + + Z_ADDREF_P(zobject); + iterator->intern.data = (void*)object; + iterator->intern.funcs = ce->iterator_funcs.funcs; + iterator->zobject = zobject; + return (zend_object_iterator*)iterator; +} + +zend_object_iterator_funcs spl_recursive_it_iterator_funcs = { + spl_recursive_it_dtor, + spl_recursive_it_valid, + spl_recursive_it_get_current_data, + spl_recursive_it_get_current_key, + spl_recursive_it_move_forward, + spl_recursive_it_rewind +}; + +static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_base, zend_class_entry *ce_inner, recursive_it_it_type rit_type) +{ + zval *object = getThis(); + spl_recursive_it_object *intern; + zval *iterator; + zend_class_entry *ce_iterator; + long mode, flags; + int inc_refcount = 1; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC); + + switch(rit_type) { + case RIT_RecursiveTreeIterator: { + + zval *caching_it, *caching_it_flags, *user_caching_it_flags = NULL; + mode = RIT_SELF_FIRST; + flags = RTIT_BYPASS_KEY; + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|lzl", &iterator, &flags, &user_caching_it_flags, &mode) == SUCCESS) { + if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) { + zval *aggregate = iterator; + zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator); + inc_refcount = 0; + } + + MAKE_STD_ZVAL(caching_it_flags); + if (user_caching_it_flags) { + ZVAL_ZVAL(caching_it_flags, user_caching_it_flags, 1, 0); + } else { + ZVAL_LONG(caching_it_flags, CIT_CATCH_GET_CHILD); + } + spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &caching_it, 1, iterator, caching_it_flags TSRMLS_CC); + zval_ptr_dtor(&caching_it_flags); + if (inc_refcount == 0 && iterator) { + zval_ptr_dtor(&iterator); + } + iterator = caching_it; + inc_refcount = 0; + } else { + iterator = NULL; + } + break; + } + case RIT_RecursiveIteratorIterator: + default: { + mode = RIT_LEAVES_ONLY; + flags = 0; + + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o|ll", &iterator, &mode, &flags) == SUCCESS) { + if (instanceof_function(Z_OBJCE_P(iterator), zend_ce_aggregate TSRMLS_CC)) { + zval *aggregate = iterator; + zend_call_method_with_0_params(&aggregate, Z_OBJCE_P(aggregate), &Z_OBJCE_P(aggregate)->iterator_funcs.zf_new_iterator, "getiterator", &iterator); + inc_refcount = 0; + } + } else { + iterator = NULL; + } + break; + } + } + if (!iterator || !instanceof_function(Z_OBJCE_P(iterator), spl_ce_RecursiveIterator TSRMLS_CC)) { + if (iterator && !inc_refcount) { + zval_ptr_dtor(&iterator); + } + zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0 TSRMLS_CC); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + intern = (spl_recursive_it_object*)zend_object_store_get_object(object TSRMLS_CC); + intern->iterators = emalloc(sizeof(spl_sub_iterator)); + intern->level = 0; + intern->mode = mode; + intern->flags = flags; + intern->max_depth = -1; + intern->in_iteration = 0; + intern->ce = Z_OBJCE_P(object); + + zend_hash_find(&intern->ce->function_table, "beginiteration", sizeof("beginiteration"), (void **) &intern->beginIteration); + if (intern->beginIteration->common.scope == ce_base) { + intern->beginIteration = NULL; + } + zend_hash_find(&intern->ce->function_table, "enditeration", sizeof("enditeration"), (void **) &intern->endIteration); + if (intern->endIteration->common.scope == ce_base) { + intern->endIteration = NULL; + } + zend_hash_find(&intern->ce->function_table, "callhaschildren", sizeof("callHasChildren"), (void **) &intern->callHasChildren); + if (intern->callHasChildren->common.scope == ce_base) { + intern->callHasChildren = NULL; + } + zend_hash_find(&intern->ce->function_table, "callgetchildren", sizeof("callGetChildren"), (void **) &intern->callGetChildren); + if (intern->callGetChildren->common.scope == ce_base) { + intern->callGetChildren = NULL; + } + zend_hash_find(&intern->ce->function_table, "beginchildren", sizeof("beginchildren"), (void **) &intern->beginChildren); + if (intern->beginChildren->common.scope == ce_base) { + intern->beginChildren = NULL; + } + zend_hash_find(&intern->ce->function_table, "endchildren", sizeof("endchildren"), (void **) &intern->endChildren); + if (intern->endChildren->common.scope == ce_base) { + intern->endChildren = NULL; + } + zend_hash_find(&intern->ce->function_table, "nextelement", sizeof("nextElement"), (void **) &intern->nextElement); + if (intern->nextElement->common.scope == ce_base) { + 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, 0 TSRMLS_CC); + if (inc_refcount) { + Z_ADDREF_P(iterator); + } + intern->iterators[0].zobject = iterator; + intern->iterators[0].ce = ce_iterator; + intern->iterators[0].state = RS_START; + + zend_restore_error_handling(&error_handling TSRMLS_CC); + + if (EG(exception)) { + zend_object_iterator *sub_iter; + + while (intern->level >= 0) { + sub_iter = intern->iterators[intern->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&intern->iterators[intern->level--].zobject); + } + efree(intern->iterators); + intern->iterators = NULL; + } +} + +/* {{{ proto void RecursiveIteratorIterator::__construct(RecursiveIterator|IteratorAggregate it [, int mode = RIT_LEAVES_ONLY [, int flags = 0]]) throws InvalidArgumentException + Creates a RecursiveIteratorIterator from a RecursiveIterator. */ +SPL_METHOD(RecursiveIteratorIterator, __construct) +{ + spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveIteratorIterator, zend_ce_iterator, RIT_RecursiveIteratorIterator); +} /* }}} */ + +/* {{{ proto void RecursiveIteratorIterator::rewind() + Rewind the iterator to the first element of the top level inner iterator. */ +SPL_METHOD(RecursiveIteratorIterator, rewind) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_recursive_it_rewind_ex(object, getThis() TSRMLS_CC); +} /* }}} */ + +/* {{{ proto bool RecursiveIteratorIterator::valid() + Check whether the current position is valid */ +SPL_METHOD(RecursiveIteratorIterator, valid) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(spl_recursive_it_valid_ex(object, getThis() TSRMLS_CC) == SUCCESS); +} /* }}} */ + +/* {{{ proto mixed RecursiveIteratorIterator::key() + Access the current key */ +SPL_METHOD(RecursiveIteratorIterator, key) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_object_iterator *iterator = object->iterators[object->level].iterator; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (iterator->funcs->get_current_key) { + char *str_key; + uint str_key_len; + ulong int_key; + + switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { + case HASH_KEY_IS_LONG: + RETURN_LONG(int_key); + break; + case HASH_KEY_IS_STRING: + RETURN_STRINGL(str_key, str_key_len-1, 0); + break; + default: + RETURN_NULL(); + } + } else { + RETURN_NULL(); + } +} /* }}} */ + +/* {{{ proto mixed RecursiveIteratorIterator::current() + Access the current element value */ +SPL_METHOD(RecursiveIteratorIterator, current) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_object_iterator *iterator = object->iterators[object->level].iterator; + zval **data; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + iterator->funcs->get_current_data(iterator, &data TSRMLS_CC); + if (data && *data) { + RETURN_ZVAL(*data, 1, 0); + } +} /* }}} */ + +/* {{{ proto void RecursiveIteratorIterator::next() + Move forward to the next element */ +SPL_METHOD(RecursiveIteratorIterator, next) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_recursive_it_move_forward_ex(object, getThis() TSRMLS_CC); +} /* }}} */ + +/* {{{ proto int RecursiveIteratorIterator::getDepth() + Get the current depth of the recursive iteration */ +SPL_METHOD(RecursiveIteratorIterator, getDepth) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(object->level); +} /* }}} */ + +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::getSubIterator([int level]) + The current active sub iterator or the iterator at specified level */ +SPL_METHOD(RecursiveIteratorIterator, getSubIterator) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long level = object->level; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &level) == FAILURE) { + return; + } + if (level < 0 || level > object->level) { + RETURN_NULL(); + } + RETURN_ZVAL(object->iterators[level].zobject, 1, 0); +} /* }}} */ + +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::getInnerIterator() + The current active sub iterator */ +SPL_METHOD(RecursiveIteratorIterator, getInnerIterator) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long level = object->level; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_ZVAL(object->iterators[level].zobject, 1, 0); +} /* }}} */ + +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::beginIteration() + Called when iteration begins (after first rewind() call) */ +SPL_METHOD(RecursiveIteratorIterator, beginIteration) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* nothing to do */ +} /* }}} */ + +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::endIteration() + Called when iteration ends (when valid() first returns false */ +SPL_METHOD(RecursiveIteratorIterator, endIteration) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* nothing to do */ +} /* }}} */ + +/* {{{ proto bool RecursiveIteratorIterator::callHasChildren() + Called for each element to test whether it has children */ +SPL_METHOD(RecursiveIteratorIterator, callHasChildren) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_class_entry *ce = object->iterators[object->level].ce; + zval *retval, *zobject; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zobject = object->iterators[object->level].zobject; + if (!zobject) { + RETURN_FALSE; + } else { + zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } else { + RETURN_FALSE; + } + } +} /* }}} */ + +/* {{{ proto RecursiveIterator RecursiveIteratorIterator::callGetChildren() + Return children of current element */ +SPL_METHOD(RecursiveIteratorIterator, callGetChildren) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_class_entry *ce = object->iterators[object->level].ce; + zval *retval, *zobject; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zobject = object->iterators[object->level].zobject; + if (!zobject) { + return; + } else { + zend_call_method_with_0_params(&zobject, ce, NULL, "getchildren", &retval); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } + } +} /* }}} */ + +/* {{{ proto void RecursiveIteratorIterator::beginChildren() + Called when recursing one level down */ +SPL_METHOD(RecursiveIteratorIterator, beginChildren) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* nothing to do */ +} /* }}} */ + +/* {{{ proto void RecursiveIteratorIterator::endChildren() + Called when end recursing one level */ +SPL_METHOD(RecursiveIteratorIterator, endChildren) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* nothing to do */ +} /* }}} */ + +/* {{{ proto void RecursiveIteratorIterator::nextElement() + Called when the next element is available */ +SPL_METHOD(RecursiveIteratorIterator, nextElement) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* nothing to do */ +} /* }}} */ + +/* {{{ proto void RecursiveIteratorIterator::setMaxDepth([$max_depth = -1]) + Set the maximum allowed depth (or any depth if pmax_depth = -1] */ +SPL_METHOD(RecursiveIteratorIterator, setMaxDepth) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long max_depth = -1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &max_depth) == FAILURE) { + return; + } + if (max_depth < -1) { + zend_throw_exception(spl_ce_OutOfRangeException, "Parameter max_depth must be >= -1", 0 TSRMLS_CC); + return; + } + object->max_depth = max_depth; +} /* }}} */ + +/* {{{ proto int|false RecursiveIteratorIterator::getMaxDepth() + Return the maximum accepted depth or false if any depth is allowed */ +SPL_METHOD(RecursiveIteratorIterator, getMaxDepth) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (object->max_depth == -1) { + RETURN_FALSE; + } else { + RETURN_LONG(object->max_depth); + } +} /* }}} */ + +static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC) +{ + union _zend_function *function_handler; + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC); + long level = object->level; + zval *zobj; + + if (!object->iterators) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "The %s instance wasn't initialized properly", Z_OBJCE_PP(object_ptr)->name); + } + zobj = object->iterators[level].zobject; + + function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC); + if (!function_handler) { + if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) { + if (Z_OBJ_HT_P(zobj)->get_method) { + *object_ptr = zobj; + function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC); + } + } + } + return function_handler; +} + +/* {{{ spl_RecursiveIteratorIterator_dtor */ +static void spl_RecursiveIteratorIterator_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object *)_object; + zend_object_iterator *sub_iter; + + /* call standard dtor */ + zend_objects_destroy_object(_object, handle TSRMLS_CC); + + if (object->iterators) { + while (object->level >= 0) { + sub_iter = object->iterators[object->level].iterator; + sub_iter->funcs->dtor(sub_iter TSRMLS_CC); + zval_ptr_dtor(&object->iterators[object->level--].zobject); + } + efree(object->iterators); + object->iterators = NULL; + } +} +/* }}} */ + +/* {{{ spl_RecursiveIteratorIterator_free_storage */ +static void spl_RecursiveIteratorIterator_free_storage(void *_object TSRMLS_DC) +{ + spl_recursive_it_object *object = (spl_recursive_it_object *)_object; + + zend_object_std_dtor(&object->std TSRMLS_CC); + smart_str_free(&object->prefix[0]); + smart_str_free(&object->prefix[1]); + smart_str_free(&object->prefix[2]); + smart_str_free(&object->prefix[3]); + smart_str_free(&object->prefix[4]); + smart_str_free(&object->prefix[5]); + + efree(object); +} +/* }}} */ + +/* {{{ spl_RecursiveIteratorIterator_new_ex */ +static zend_object_value spl_RecursiveIteratorIterator_new_ex(zend_class_entry *class_type, int init_prefix TSRMLS_DC) +{ + zend_object_value retval; + spl_recursive_it_object *intern; + + intern = emalloc(sizeof(spl_recursive_it_object)); + memset(intern, 0, sizeof(spl_recursive_it_object)); + + if (init_prefix) { + smart_str_appendl(&intern->prefix[0], "", 0); + smart_str_appendl(&intern->prefix[1], "| ", 2); + smart_str_appendl(&intern->prefix[2], " ", 2); + smart_str_appendl(&intern->prefix[3], "|-", 2); + smart_str_appendl(&intern->prefix[4], "\\-", 2); + smart_str_appendl(&intern->prefix[5], "", 0); + } + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)spl_RecursiveIteratorIterator_dtor, (zend_objects_free_object_storage_t) spl_RecursiveIteratorIterator_free_storage, NULL TSRMLS_CC); + retval.handlers = &spl_handlers_rec_it_it; + return retval; +} +/* }}} */ + +/* {{{ spl_RecursiveIteratorIterator_new */ +static zend_object_value spl_RecursiveIteratorIterator_new(zend_class_entry *class_type TSRMLS_DC) +{ + return spl_RecursiveIteratorIterator_new_ex(class_type, 0 TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_RecursiveTreeIterator_new */ +static zend_object_value spl_RecursiveTreeIterator_new(zend_class_entry *class_type TSRMLS_DC) +{ + return spl_RecursiveIteratorIterator_new_ex(class_type, 1 TSRMLS_CC); +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it___construct, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) + ZEND_ARG_INFO(0, mode) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_getSubIterator, 0, 0, 0) + ZEND_ARG_INFO(0, level) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_it_setMaxDepth, 0, 0, 0) + ZEND_ARG_INFO(0, max_depth) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_RecursiveIteratorIterator[] = { + SPL_ME(RecursiveIteratorIterator, __construct, arginfo_recursive_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, getDepth, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, getSubIterator, arginfo_recursive_it_getSubIterator, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, setMaxDepth, arginfo_recursive_it_setMaxDepth, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, getMaxDepth, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static void spl_recursive_tree_iterator_get_prefix(spl_recursive_it_object *object, zval *return_value TSRMLS_DC) +{ + smart_str str = {0}; + zval *has_next; + int level; + + smart_str_appendl(&str, object->prefix[0].c, object->prefix[0].len); + + for (level = 0; level < object->level; ++level) { + zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next); + if (has_next) { + if (Z_LVAL_P(has_next)) { + smart_str_appendl(&str, object->prefix[1].c, object->prefix[1].len); + } else { + smart_str_appendl(&str, object->prefix[2].c, object->prefix[2].len); + } + zval_ptr_dtor(&has_next); + } + } + zend_call_method_with_0_params(&object->iterators[level].zobject, object->iterators[level].ce, NULL, "hasnext", &has_next); + if (has_next) { + if (Z_LVAL_P(has_next)) { + smart_str_appendl(&str, object->prefix[3].c, object->prefix[3].len); + } else { + smart_str_appendl(&str, object->prefix[4].c, object->prefix[4].len); + } + zval_ptr_dtor(&has_next); + } + + smart_str_appendl(&str, object->prefix[5].c, object->prefix[5].len); + smart_str_0(&str); + + RETVAL_STRINGL(str.c, str.len, 0); +} + +static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object * object, zval * return_value TSRMLS_DC) +{ + zend_object_iterator *iterator = object->iterators[object->level].iterator; + zval **data; + zend_error_handling error_handling; + + iterator->funcs->get_current_data(iterator, &data TSRMLS_CC); + + zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling TSRMLS_CC); + if (data && *data) { + RETVAL_ZVAL(*data, 1, 0); + } + if (Z_TYPE_P(return_value) == IS_ARRAY) { + zval_dtor(return_value); + ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1, 1); + } else { + convert_to_string(return_value); + } + zend_restore_error_handling(&error_handling TSRMLS_CC); +} + +static void spl_recursive_tree_iterator_get_postfix(spl_recursive_it_object * object, zval * return_value TSRMLS_DC) +{ + RETVAL_STRINGL("", 0, 1); +} + +/* {{{ proto void RecursiveTreeIterator::__construct(RecursiveIterator|IteratorAggregate it [, int flags = RTIT_BYPASS_KEY [, int cit_flags = CIT_CATCH_GET_CHILD [, mode = RIT_SELF_FIRST ]]]) throws InvalidArgumentException + RecursiveIteratorIterator to generate ASCII graphic trees for the entries in a RecursiveIterator */ +SPL_METHOD(RecursiveTreeIterator, __construct) +{ + spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveTreeIterator, zend_ce_iterator, RIT_RecursiveTreeIterator); +} /* }}} */ + +/* {{{ proto void RecursiveTreeIterator::setPrefixPart(int part, string prefix) throws OutOfRangeException + Sets prefix parts as used in getPrefix() */ +SPL_METHOD(RecursiveTreeIterator, setPrefixPart) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + long part; + char* prefix; + int prefix_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &part, &prefix, &prefix_len) == FAILURE) { + return; + } + if (0 > part || part > 5) { + zend_throw_exception_ex(spl_ce_OutOfRangeException, 0 TSRMLS_CC, "Use RecursiveTreeIterator::PREFIX_* constant"); + return; + } + + smart_str_free(&object->prefix[part]); + smart_str_appendl(&object->prefix[part], prefix, prefix_len); +} /* }}} */ + +/* {{{ proto string RecursiveTreeIterator::getPrefix() + Returns the string to place in front of current element */ +SPL_METHOD(RecursiveTreeIterator, getPrefix) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + spl_recursive_tree_iterator_get_prefix(object, return_value TSRMLS_CC); +} /* }}} */ + +/* {{{ proto string RecursiveTreeIterator::getEntry() + Returns the string presentation built for current element */ +SPL_METHOD(RecursiveTreeIterator, getEntry) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_recursive_tree_iterator_get_entry(object, return_value TSRMLS_CC); +} /* }}} */ + +/* {{{ proto string RecursiveTreeIterator::getPostfix() + Returns the string to place after the current element */ +SPL_METHOD(RecursiveTreeIterator, getPostfix) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_recursive_tree_iterator_get_postfix(object, return_value TSRMLS_CC); +} /* }}} */ + +/* {{{ proto mixed RecursiveTreeIterator::current() + Returns the current element prefixed and postfixed */ +SPL_METHOD(RecursiveTreeIterator, current) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval prefix, entry, postfix; + char *str, *ptr; + size_t str_len; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (object->flags & RTIT_BYPASS_CURRENT) { + zend_object_iterator *iterator = object->iterators[object->level].iterator; + zval **data; + + iterator->funcs->get_current_data(iterator, &data TSRMLS_CC); + if (data && *data) { + RETURN_ZVAL(*data, 1, 0); + } else { + RETURN_NULL(); + } + } + + spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC); + spl_recursive_tree_iterator_get_entry(object, &entry TSRMLS_CC); + spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC); + + str_len = Z_STRLEN(prefix) + Z_STRLEN(entry) + Z_STRLEN(postfix); + str = (char *) emalloc(str_len + 1U); + ptr = str; + + memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix)); + ptr += Z_STRLEN(prefix); + memcpy(ptr, Z_STRVAL(entry), Z_STRLEN(entry)); + ptr += Z_STRLEN(entry); + memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix)); + ptr += Z_STRLEN(postfix); + *ptr = 0; + + zval_dtor(&prefix); + zval_dtor(&entry); + zval_dtor(&postfix); + + RETURN_STRINGL(str, str_len, 0); +} /* }}} */ + +/* {{{ proto mixed RecursiveTreeIterator::key() + Returns the current key prefixed and postfixed */ +SPL_METHOD(RecursiveTreeIterator, key) +{ + spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_object_iterator *iterator = object->iterators[object->level].iterator; + zval prefix, key, postfix, key_copy; + char *str, *ptr; + size_t str_len; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (iterator->funcs->get_current_key) { + char *str_key; + uint str_key_len; + ulong int_key; + + switch (iterator->funcs->get_current_key(iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { + case HASH_KEY_IS_LONG: + ZVAL_LONG(&key, int_key); + break; + case HASH_KEY_IS_STRING: + ZVAL_STRINGL(&key, str_key, str_key_len-1, 0); + break; + default: + ZVAL_NULL(&key); + } + } else { + ZVAL_NULL(&key); + } + + if (object->flags & RTIT_BYPASS_KEY) { + zval *key_ptr = &key; + RETVAL_ZVAL(key_ptr, 1, 0); + zval_dtor(&key); + return; + } + + if (Z_TYPE(key) != IS_STRING) { + int use_copy; + zend_make_printable_zval(&key, &key_copy, &use_copy); + if (use_copy) { + key = key_copy; + } + } + + spl_recursive_tree_iterator_get_prefix(object, &prefix TSRMLS_CC); + spl_recursive_tree_iterator_get_postfix(object, &postfix TSRMLS_CC); + + str_len = Z_STRLEN(prefix) + Z_STRLEN(key) + Z_STRLEN(postfix); + str = (char *) emalloc(str_len + 1U); + ptr = str; + + memcpy(ptr, Z_STRVAL(prefix), Z_STRLEN(prefix)); + ptr += Z_STRLEN(prefix); + memcpy(ptr, Z_STRVAL(key), Z_STRLEN(key)); + ptr += Z_STRLEN(key); + memcpy(ptr, Z_STRVAL(postfix), Z_STRLEN(postfix)); + ptr += Z_STRLEN(postfix); + *ptr = 0; + + zval_dtor(&prefix); + zval_dtor(&key); + zval_dtor(&postfix); + + RETVAL_STRINGL(str, str_len, 0); +} /* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it___construct, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) + ZEND_ARG_INFO(0, flags) + ZEND_ARG_INFO(0, caching_it_flags) + ZEND_ARG_INFO(0, mode) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_recursive_tree_it_setPrefixPart, 0, 0, 2) + ZEND_ARG_INFO(0, part) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_RecursiveTreeIterator[] = { + SPL_ME(RecursiveTreeIterator, __construct, arginfo_recursive_tree_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveTreeIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveTreeIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, beginIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, endIteration, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, callHasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, callGetChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, beginChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, endChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveIteratorIterator, nextElement, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveTreeIterator, getPrefix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveTreeIterator, setPrefixPart, arginfo_recursive_tree_it_setPrefixPart, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveTreeIterator, getEntry, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveTreeIterator, getPostfix, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +#if MBO_0 +static int spl_dual_it_gets_implemented(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC) +{ + class_type->iterator_funcs.zf_valid = NULL; + class_type->iterator_funcs.zf_current = NULL; + class_type->iterator_funcs.zf_key = NULL; + class_type->iterator_funcs.zf_next = NULL; + class_type->iterator_funcs.zf_rewind = NULL; + if (!class_type->iterator_funcs.funcs) { + class_type->iterator_funcs.funcs = &zend_interface_iterator_funcs_iterator; + } + + return SUCCESS; +} +#endif + +static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC) +{ + union _zend_function *function_handler; + spl_dual_it_object *intern; + + intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC); + + function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC); + if (!function_handler && intern->inner.ce) { + if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) { + if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) { + *object_ptr = intern->inner.zobject; + function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC); + } + } else { + *object_ptr = intern->inner.zobject; + } + } + return function_handler; +} + +#if MBO_0 +int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS) +{ + zval ***func_params, func; + zval *retval_ptr; + int arg_count; + int current = 0; + int success; + void **p; + spl_dual_it_object *intern; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + ZVAL_STRING(&func, method, 0); + if (!zend_is_callable(&func, 0, &method TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Method %s::%s() does not exist", intern->inner.ce->name, method); + return FAILURE; + } + + p = EG(argument_stack).top_element-2; + arg_count = (ulong) *p; + + func_params = safe_emalloc(sizeof(zval **), arg_count, 0); + + current = 0; + while (arg_count-- > 0) { + func_params[current] = (zval **) p - (arg_count-current); + current++; + } + arg_count = current; /* restore */ + + if (call_user_function_ex(EG(function_table), NULL, &func, &retval_ptr, arg_count, func_params, 0, NULL TSRMLS_CC) == SUCCESS && retval_ptr) { + RETURN_ZVAL(retval_ptr, 0, 1); + + success = SUCCESS; + } else { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unable to call %s::%s()", intern->inner.ce->name, method); + success = FAILURE; + } + + efree(func_params); + return success; +} +#endif + +#define SPL_CHECK_CTOR(intern, classname) \ + if (intern->dit_type == DIT_Unknown) { \ + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Classes derived from %s must call %s::__construct()", \ + (spl_ce_##classname)->name, (spl_ce_##classname)->name); \ + return; \ + } + +#define APPENDIT_CHECK_CTOR(intern) SPL_CHECK_CTOR(intern, AppendIterator) + +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; + spl_dual_it_object *intern; + zend_class_entry *ce = NULL; + int inc_refcount = 1; + zend_error_handling error_handling; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (intern->dit_type != DIT_Unknown) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%s::getIterator() must be called exactly once per instance", ce_base->name); + return NULL; + } + + zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC); + + intern->dit_type = dit_type; + switch (dit_type) { + case DIT_LimitIterator: { + intern->u.limit.offset = 0; /* start at beginning */ + intern->u.limit.count = -1; /* get all */ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &zobject, ce_inner, &intern->u.limit.offset, &intern->u.limit.count) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + if (intern->u.limit.offset < 0) { + zend_throw_exception(spl_ce_OutOfRangeException, "Parameter offset must be >= 0", 0 TSRMLS_CC); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + if (intern->u.limit.count < 0 && intern->u.limit.count != -1) { + zend_throw_exception(spl_ce_OutOfRangeException, "Parameter count must either be -1 or a value greater than or equal 0", 0 TSRMLS_CC); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + break; + } + case DIT_CachingIterator: + case DIT_RecursiveCachingIterator: { + long flags = CIT_CALL_TOSTRING; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &zobject, ce_inner, &flags) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + 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_CURRENT", 0 TSRMLS_CC); + zend_restore_error_handling(&error_handling 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: { + zend_class_entry **pce_cast; + char * class_name = NULL; + int class_name_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|s", &zobject, ce_inner, &class_name, &class_name_len) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + ce = Z_OBJCE_P(zobject); + if (!instanceof_function(ce, zend_ce_iterator TSRMLS_CC)) { + if (ZEND_NUM_ARGS() > 1) { + if (zend_lookup_class(class_name, class_name_len, &pce_cast TSRMLS_CC) == FAILURE + || !instanceof_function(ce, *pce_cast TSRMLS_CC) + || !(*pce_cast)->get_iterator + ) { + zend_throw_exception(spl_ce_LogicException, "Class to downcast to not found or not base class or does not implement Traversable", 0 TSRMLS_CC); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + ce = *pce_cast; + } + 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); + } + zend_restore_error_handling(&error_handling 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 implements Traversable", ce->name); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + zobject = retval; + ce = Z_OBJCE_P(zobject); + inc_refcount = 0; + } + } + break; + } + 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, 0 TSRMLS_CC); + zend_restore_error_handling(&error_handling 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) { + zend_restore_error_handling(&error_handling 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); + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + intern->u.regex.mode = mode; + intern->u.regex.regex = estrndup(regex, regex_len); + intern->u.regex.regex_len = regex_len; + intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC); + if (intern->u.regex.pce == NULL) { + /* pcre_get_compiled_regex_cache has already sent error */ + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + intern->u.regex.pce->refcount++; + break; + } +#endif + case DIT_CallbackFilterIterator: + case DIT_RecursiveCallbackFilterIterator: { + _spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi)); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + efree(cfi); + return NULL; + } + if (cfi->fci.function_name) { + Z_ADDREF_P(cfi->fci.function_name); + } + if (cfi->fci.object_ptr) { + Z_ADDREF_P(cfi->fci.object_ptr); + } + intern->u.cbfilter = cfi; + break; + } + default: + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zobject, ce_inner) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return NULL; + } + break; + } + + zend_restore_error_handling(&error_handling TSRMLS_CC); + + if (inc_refcount) { + Z_ADDREF_P(zobject); + } + 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, 0 TSRMLS_CC); + + return intern; +} + +/* {{{ proto void FilterIterator::__construct(Iterator it) + Create an Iterator from another iterator */ +SPL_METHOD(FilterIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_FilterIterator, zend_ce_iterator, DIT_FilterIterator); +} /* }}} */ + +/* {{{ proto void CallbackFilterIterator::__construct(Iterator it, callback) + Create an Iterator from another iterator */ +SPL_METHOD(CallbackFilterIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CallbackFilterIterator, zend_ce_iterator, DIT_CallbackFilterIterator); +} /* }}} */ + +/* {{{ proto Iterator FilterIterator::getInnerIterator() + proto Iterator CachingIterator::getInnerIterator() + proto Iterator LimitIterator::getInnerIterator() + proto Iterator ParentIterator::getInnerIterator() + Get the inner iterator */ +SPL_METHOD(dual_it, getInnerIterator) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->inner.zobject) { + RETVAL_ZVAL(intern->inner.zobject, 1, 0); + } else { + RETURN_NULL(); + } +} /* }}} */ + +static inline void spl_dual_it_require(spl_dual_it_object *intern TSRMLS_DC) +{ + if (!intern->inner.iterator) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "The inner constructor wasn't initialized with an iterator instance"); + } +} + +static inline void spl_dual_it_free(spl_dual_it_object *intern TSRMLS_DC) +{ + if (intern->inner.iterator && intern->inner.iterator->funcs->invalidate_current) { + intern->inner.iterator->funcs->invalidate_current(intern->inner.iterator TSRMLS_CC); + } + if (intern->current.data) { + zval_ptr_dtor(&intern->current.data); + intern->current.data = NULL; + } + if (intern->current.str_key) { + efree(intern->current.str_key); + intern->current.str_key = NULL; + } + if (intern->dit_type == DIT_CachingIterator || intern->dit_type == DIT_RecursiveCachingIterator) { + if (intern->u.caching.zstr) { + zval_ptr_dtor(&intern->u.caching.zstr); + intern->u.caching.zstr = NULL; + } + if (intern->u.caching.zchildren) { + zval_ptr_dtor(&intern->u.caching.zchildren); + intern->u.caching.zchildren = NULL; + } + } +} + +static inline void spl_dual_it_rewind(spl_dual_it_object *intern TSRMLS_DC) +{ + spl_dual_it_free(intern TSRMLS_CC); + intern->current.pos = 0; + if (intern->inner.iterator->funcs->rewind) { + intern->inner.iterator->funcs->rewind(intern->inner.iterator TSRMLS_CC); + } +} + +static inline int spl_dual_it_valid(spl_dual_it_object *intern TSRMLS_DC) +{ + if (!intern->inner.iterator) { + return FAILURE; + } + /* FAILURE / SUCCESS */ + return intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC); +} + +static inline int spl_dual_it_fetch(spl_dual_it_object *intern, int check_more TSRMLS_DC) +{ + zval **data; + + spl_dual_it_free(intern TSRMLS_CC); + if (!check_more || spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { + intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC); + if (data && *data) { + intern->current.data = *data; + Z_ADDREF_P(intern->current.data); + } + if (intern->inner.iterator->funcs->get_current_key) { + intern->current.key_type = intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &intern->current.str_key, &intern->current.str_key_len, &intern->current.int_key TSRMLS_CC); + } else { + intern->current.key_type = HASH_KEY_IS_LONG; + intern->current.int_key = intern->current.pos; + } + return EG(exception) ? FAILURE : SUCCESS; + } + return FAILURE; +} + +static inline void spl_dual_it_next(spl_dual_it_object *intern, int do_free TSRMLS_DC) +{ + if (do_free) { + spl_dual_it_free(intern TSRMLS_CC); + } else { + spl_dual_it_require(intern TSRMLS_CC); + } + intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC); + intern->current.pos++; +} + +/* {{{ proto void ParentIterator::rewind() + proto void IteratorIterator::rewind() + Rewind the iterator + */ +SPL_METHOD(dual_it, rewind) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_dual_it_rewind(intern TSRMLS_CC); + spl_dual_it_fetch(intern, 1 TSRMLS_CC); +} /* }}} */ + +/* {{{ proto bool FilterIterator::valid() + proto bool ParentIterator::valid() + proto bool IteratorIterator::valid() + proto bool NoRewindIterator::valid() + Check whether the current element is valid */ +SPL_METHOD(dual_it, valid) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_BOOL(intern->current.data); +} /* }}} */ + +/* {{{ proto mixed FilterIterator::key() + proto mixed CachingIterator::key() + proto mixed LimitIterator::key() + proto mixed ParentIterator::key() + proto mixed IteratorIterator::key() + proto mixed NoRewindIterator::key() + proto mixed AppendIterator::key() + Get the current key */ +SPL_METHOD(dual_it, key) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->current.data) { + if (intern->current.key_type == HASH_KEY_IS_STRING) { + RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1); + } else { + RETURN_LONG(intern->current.int_key); + } + } + RETURN_NULL(); +} /* }}} */ + +/* {{{ proto mixed FilterIterator::current() + proto mixed CachingIterator::current() + proto mixed LimitIterator::current() + proto mixed ParentIterator::current() + proto mixed IteratorIterator::current() + proto mixed NoRewindIterator::current() + proto mixed AppendIterator::current() + Get the current element value */ +SPL_METHOD(dual_it, current) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->current.data) { + RETVAL_ZVAL(intern->current.data, 1, 0); + } else { + RETURN_NULL(); + } +} /* }}} */ + +/* {{{ proto void ParentIterator::next() + proto void IteratorIterator::next() + proto void NoRewindIterator::next() + Move the iterator forward */ +SPL_METHOD(dual_it, next) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_dual_it_next(intern, 1 TSRMLS_CC); + spl_dual_it_fetch(intern, 1 TSRMLS_CC); +} /* }}} */ + +static inline void spl_filter_it_fetch(zval *zthis, spl_dual_it_object *intern TSRMLS_DC) +{ + zval *retval; + + while (spl_dual_it_fetch(intern, 1 TSRMLS_CC) == SUCCESS) { + zend_call_method_with_0_params(&zthis, intern->std.ce, NULL, "accept", &retval); + if (retval) { + if (zend_is_true(retval)) { + zval_ptr_dtor(&retval); + return; + } + 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); +} + +static inline void spl_filter_it_rewind(zval *zthis, spl_dual_it_object *intern TSRMLS_DC) +{ + spl_dual_it_rewind(intern TSRMLS_CC); + spl_filter_it_fetch(zthis, intern TSRMLS_CC); +} + +static inline void spl_filter_it_next(zval *zthis, spl_dual_it_object *intern TSRMLS_DC) +{ + spl_dual_it_next(intern, 1 TSRMLS_CC); + spl_filter_it_fetch(zthis, intern TSRMLS_CC); +} + +/* {{{ proto void FilterIterator::rewind() + Rewind the iterator */ +SPL_METHOD(FilterIterator, rewind) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + spl_filter_it_rewind(getThis(), intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void FilterIterator::next() + Move the iterator forward */ +SPL_METHOD(FilterIterator, next) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + spl_filter_it_next(getThis(), intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void RecursiveCallbackFilterIterator::__construct(RecursiveIterator it, callback) + Create a RecursiveCallbackFilterIterator from a RecursiveIterator */ +SPL_METHOD(RecursiveCallbackFilterIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCallbackFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveCallbackFilterIterator); +} /* }}} */ + + +/* {{{ proto void RecursiveFilterIterator::__construct(RecursiveIterator it) + Create a RecursiveFilterIterator from a RecursiveIterator */ +SPL_METHOD(RecursiveFilterIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveFilterIterator, spl_ce_RecursiveIterator, DIT_RecursiveFilterIterator); +} /* }}} */ + +/* {{{ proto bool RecursiveFilterIterator::hasChildren() + Check whether the inner iterator's current element has children */ +SPL_METHOD(RecursiveFilterIterator, hasChildren) +{ + spl_dual_it_object *intern; + zval *retval; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } else { + RETURN_FALSE; + } +} /* }}} */ + +/* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren() + Return the inner iterator's children contained in a RecursiveFilterIterator */ +SPL_METHOD(RecursiveFilterIterator, getChildren) +{ + spl_dual_it_object *intern; + zval *retval; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &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 RecursiveCallbackFilterIterator RecursiveCallbackFilterIterator::getChildren() + Return the inner iterator's children contained in a RecursiveCallbackFilterIterator */ +SPL_METHOD(RecursiveCallbackFilterIterator, getChildren) +{ + spl_dual_it_object *intern; + zval *retval; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + 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) && retval) { + spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, intern->u.cbfilter->fci.function_name TSRMLS_CC); + } + if (retval) { + zval_ptr_dtor(&retval); + } +} /* }}} */ +/* {{{ proto void ParentIterator::__construct(RecursiveIterator it) + Create a ParentIterator from a RecursiveIterator */ +SPL_METHOD(ParentIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_ParentIterator, spl_ce_RecursiveIterator, DIT_ParentIterator); +} /* }}} */ + +#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 CallbackFilterIterator::accept() + Calls the callback with the current value, the current key and the inner iterator as arguments */ +SPL_METHOD(CallbackFilterIterator, accept) +{ + spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + zend_fcall_info *fci = &intern->u.cbfilter->fci; + zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc; + zval **params[3]; + zval zkey; + zval *zkey_p = &zkey; + zval *result; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (intern->current.data == NULL) { + RETURN_FALSE; + } + + INIT_PZVAL(&zkey); + if (intern->current.key_type == HASH_KEY_IS_LONG) { + ZVAL_LONG(&zkey, intern->current.int_key); + } else { + ZVAL_STRINGL(&zkey, intern->current.str_key, intern->current.str_key_len-1, 0); + } + + params[0] = &intern->current.data; + params[1] = &zkey_p; + params[2] = &intern->inner.zobject; + + fci->retval_ptr_ptr = &result; + fci->param_count = 3; + fci->params = params; + fci->no_separation = 0; + + if (zend_call_function(fci, fcc TSRMLS_CC) != SUCCESS || !result) { + RETURN_FALSE; + } + if (EG(exception)) { + return; + } + + RETURN_ZVAL(result, 1, 1); +} +/* }}} */ + +/* {{{ proto bool RegexIterator::accept() + Match (string)current() against regular expression */ +SPL_METHOD(RegexIterator, accept) +{ + spl_dual_it_object *intern; + char *subject, tmp[32], *result; + int subject_len, use_copy, count = 0, result_len; + zval subject_copy, zcount, *replacement, tmp_replacement; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->current.data == NULL) { + RETURN_FALSE; + } + + if (intern->u.regex.flags & REGIT_USE_KEY) { + if (intern->current.key_type == HASH_KEY_IS_LONG) { + subject_len = slprintf(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); + if (Z_TYPE_P(replacement) != IS_STRING) { + tmp_replacement = *replacement; + zval_copy_ctor(&tmp_replacement); + convert_to_string(&tmp_replacement); + replacement = &tmp_replacement; + } + result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count 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 (replacement == &tmp_replacement) { + zval_dtor(replacement); + } + RETVAL_BOOL(count > 0); + } + + if (intern->u.regex.flags & REGIT_INVERTED) { + RETVAL_BOOL(Z_LVAL_P(return_value)); + } + + if (use_copy) { + efree(subject); + } +} /* }}} */ + +/* {{{ proto string RegexIterator::getRegex() + Returns current regular expression */ +SPL_METHOD(RegexIterator, getRegex) +{ + spl_dual_it_object *intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_STRINGL(intern->u.regex.regex, intern->u.regex.regex_len, 1); +} /* }}} */ + +/* {{{ proto bool RegexIterator::getMode() + Returns current operation mode */ +SPL_METHOD(RegexIterator, getMode) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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; + 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 */ + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + intern->u.regex.mode = mode; +} /* }}} */ + +/* {{{ proto bool RegexIterator::getFlags() + Returns current operation flags */ +SPL_METHOD(RegexIterator, getFlags) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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; + long flags; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &flags) == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->u.regex.use_flags) { + RETURN_LONG(intern->u.regex.preg_flags); + } else { + return; + } +} /* }}} */ + +/* {{{ proto bool RegexIterator::setPregFlags(int new_flags) + Set PREG flags */ +SPL_METHOD(RegexIterator, setPregFlags) +{ + spl_dual_it_object *intern; + long preg_flags; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &preg_flags) == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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_dtor */ +static void spl_dual_it_dtor(zend_object *_object, zend_object_handle handle TSRMLS_DC) +{ + spl_dual_it_object *object = (spl_dual_it_object *)_object; + + /* call standard dtor */ + zend_objects_destroy_object(_object, handle TSRMLS_CC); + + spl_dual_it_free(object TSRMLS_CC); + + if (object->inner.iterator) { + object->inner.iterator->funcs->dtor(object->inner.iterator TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ spl_dual_it_free_storage */ +static void spl_dual_it_free_storage(void *_object TSRMLS_DC) +{ + spl_dual_it_object *object = (spl_dual_it_object *)_object; + + + if (object->inner.zobject) { + zval_ptr_dtor(&object->inner.zobject); + } + + if (object->dit_type == DIT_AppendIterator) { + object->u.append.iterator->funcs->dtor(object->u.append.iterator TSRMLS_CC); + 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 + + if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) { + if (object->u.cbfilter) { + if (object->u.cbfilter->fci.function_name) { + zval_ptr_dtor(&object->u.cbfilter->fci.function_name); + } + if (object->u.cbfilter->fci.object_ptr) { + zval_ptr_dtor(&object->u.cbfilter->fci.object_ptr); + } + efree(object->u.cbfilter); + } + } + + zend_object_std_dtor(&object->std TSRMLS_CC); + + efree(object); +} +/* }}} */ + +/* {{{ spl_dual_it_new */ +static zend_object_value spl_dual_it_new(zend_class_entry *class_type TSRMLS_DC) +{ + zend_object_value retval; + spl_dual_it_object *intern; + + intern = emalloc(sizeof(spl_dual_it_object)); + memset(intern, 0, sizeof(spl_dual_it_object)); + intern->dit_type = DIT_Unknown; + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)spl_dual_it_dtor, (zend_objects_free_object_storage_t) spl_dual_it_free_storage, NULL TSRMLS_CC); + retval.handlers = &spl_handlers_dual_it; + return retval; +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_filter_it___construct, 0) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_FilterIterator[] = { + SPL_ME(FilterIterator, __construct, arginfo_filter_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(FilterIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(FilterIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ABSTRACT_ME(FilterIterator, accept, arginfo_recursive_it_void) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO(arginfo_callback_filter_it___construct, 0) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_INFO(0, callback) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_CallbackFilterIterator[] = { + SPL_ME(CallbackFilterIterator, __construct, arginfo_callback_filter_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(CallbackFilterIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO(arginfo_recursive_callback_filter_it___construct, 0) + ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0) + ZEND_ARG_INFO(0, callback) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_RecursiveCallbackFilterIterator[] = { + SPL_ME(RecursiveCallbackFilterIterator, __construct, arginfo_recursive_callback_filter_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveCallbackFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO(arginfo_parent_it___construct, 0) + ZEND_ARG_OBJ_INFO(0, iterator, RecursiveIterator, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_RecursiveFilterIterator[] = { + SPL_ME(RecursiveFilterIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveFilterIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static const zend_function_entry spl_funcs_ParentIterator[] = { + SPL_ME(ParentIterator, __construct, arginfo_parent_it___construct, ZEND_ACC_PUBLIC) + SPL_MA(ParentIterator, accept, RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +#if HAVE_PCRE || HAVE_BUNDLED_PCRE +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(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_mode, 0, 0, 1) + ZEND_ARG_INFO(0, mode) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_regex_it_set_flags, 0, 0, 1) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +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 const zend_function_entry spl_funcs_RegexIterator[] = { + SPL_ME(RegexIterator, __construct, arginfo_regex_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, accept, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, getMode, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, setMode, arginfo_regex_it_set_mode, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, getFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, setFlags, arginfo_regex_it_set_flags, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, getPregFlags, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, setPregFlags, arginfo_regex_it_set_preg_flags, ZEND_ACC_PUBLIC) + SPL_ME(RegexIterator, getRegex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +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 const zend_function_entry spl_funcs_RecursiveRegexIterator[] = { + SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveFilterIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveRegexIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +#endif + +static inline int spl_limit_it_valid(spl_dual_it_object *intern TSRMLS_DC) +{ + /* FAILURE / SUCCESS */ + if (intern->u.limit.count != -1 && intern->current.pos >= intern->u.limit.offset + intern->u.limit.count) { + return FAILURE; + } else { + return spl_dual_it_valid(intern TSRMLS_CC); + } +} + +static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS_DC) +{ + zval *zpos; + + spl_dual_it_free(intern TSRMLS_CC); + if (pos < intern->u.limit.offset) { + zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is below the offset %ld", pos, intern->u.limit.offset); + return; + } + if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) { + zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Cannot seek to %ld which is behind offset %ld plus count %ld", pos, intern->u.limit.offset, intern->u.limit.count); + return; + } + if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator TSRMLS_CC)) { + MAKE_STD_ZVAL(zpos); + ZVAL_LONG(zpos, pos); + 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); + 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 */ + /* a back ward seek is done by a previous rewind() */ + if (pos < intern->current.pos) { + spl_dual_it_rewind(intern TSRMLS_CC); + } + while (pos > intern->current.pos && spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { + spl_dual_it_next(intern, 1 TSRMLS_CC); + } + if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { + spl_dual_it_fetch(intern, 1 TSRMLS_CC); + } + } +} + +/* {{{ proto LimitIterator::__construct(Iterator it [, int offset, int count]) + Construct a LimitIterator from an Iterator with a given starting offset and optionally a maximum count */ +SPL_METHOD(LimitIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_LimitIterator, zend_ce_iterator, DIT_LimitIterator); +} /* }}} */ + +/* {{{ proto void LimitIterator::rewind() + Rewind the iterator to the specified starting offset */ +SPL_METHOD(LimitIterator, rewind) +{ + spl_dual_it_object *intern; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + spl_dual_it_rewind(intern TSRMLS_CC); + spl_limit_it_seek(intern, intern->u.limit.offset TSRMLS_CC); +} /* }}} */ + +/* {{{ proto bool LimitIterator::valid() + Check whether the current element is valid */ +SPL_METHOD(LimitIterator, valid) +{ + spl_dual_it_object *intern; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + +/* RETURN_BOOL(spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS);*/ + RETURN_BOOL((intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) && intern->current.data); +} /* }}} */ + +/* {{{ proto void LimitIterator::next() + Move the iterator forward */ +SPL_METHOD(LimitIterator, next) +{ + spl_dual_it_object *intern; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_dual_it_next(intern, 1 TSRMLS_CC); + if (intern->u.limit.count == -1 || intern->current.pos < intern->u.limit.offset + intern->u.limit.count) { + spl_dual_it_fetch(intern, 1 TSRMLS_CC); + } +} /* }}} */ + +/* {{{ proto void LimitIterator::seek(int position) + Seek to the given position */ +SPL_METHOD(LimitIterator, seek) +{ + spl_dual_it_object *intern; + long pos; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &pos) == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + spl_limit_it_seek(intern, pos TSRMLS_CC); + RETURN_LONG(intern->current.pos); +} /* }}} */ + +/* {{{ proto int LimitIterator::getPosition() + Return the current position */ +SPL_METHOD(LimitIterator, getPosition) +{ + spl_dual_it_object *intern; + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + RETURN_LONG(intern->current.pos); +} /* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_seekable_it_seek, 0) + ZEND_ARG_INFO(0, position) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_SeekableIterator[] = { + SPL_ABSTRACT_ME(SeekableIterator, seek, arginfo_seekable_it_seek) + PHP_FE_END +}; + +ZEND_BEGIN_ARG_INFO_EX(arginfo_limit_it___construct, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, count) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_limit_it_seek, 0) + ZEND_ARG_INFO(0, position) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_LimitIterator[] = { + SPL_ME(LimitIterator, __construct, arginfo_limit_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(LimitIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(LimitIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(LimitIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(LimitIterator, seek, arginfo_limit_it_seek, ZEND_ACC_PUBLIC) + SPL_ME(LimitIterator, getPosition, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +static inline int spl_caching_it_valid(spl_dual_it_object *intern TSRMLS_DC) +{ + return intern->u.caching.flags & CIT_VALID ? SUCCESS : FAILURE; +} + +static inline int spl_caching_it_has_next(spl_dual_it_object *intern TSRMLS_DC) +{ + return spl_dual_it_valid(intern TSRMLS_CC); +} + +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 (EG(exception)) { + if (retval) { + zval_ptr_dtor(&retval); + } + if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + zend_clear_exception(TSRMLS_C); + } 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); + } + } + zval_ptr_dtor(&retval); + if (EG(exception)) { + if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + zend_clear_exception(TSRMLS_C); + } else { + 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 { + *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); + } + } + spl_dual_it_next(intern, 0 TSRMLS_CC); + } else { + intern->u.caching.flags &= ~CIT_VALID; + } +} + +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); +} + +/* {{{ proto void CachingIterator::__construct(Iterator it [, flags = CIT_CALL_TOSTRING]) + Construct a CachingIterator from an Iterator */ +SPL_METHOD(CachingIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_CachingIterator, zend_ce_iterator, DIT_CachingIterator); +} /* }}} */ + +/* {{{ proto void CachingIterator::rewind() + Rewind the iterator */ +SPL_METHOD(CachingIterator, rewind) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_caching_it_rewind(intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto bool CachingIterator::valid() + Check whether the current element is valid */ +SPL_METHOD(CachingIterator, valid) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_BOOL(spl_caching_it_valid(intern TSRMLS_CC) == SUCCESS); +} /* }}} */ + +/* {{{ proto void CachingIterator::next() + Move the iterator forward */ +SPL_METHOD(CachingIterator, next) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_caching_it_next(intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto bool CachingIterator::hasNext() + Check whether the inner iterator has a valid next element */ +SPL_METHOD(CachingIterator, hasNext) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_BOOL(spl_caching_it_has_next(intern TSRMLS_CC) == SUCCESS); +} /* }}} */ + +/* {{{ proto string CachingIterator::__toString() + Return the string representation of the current element */ +SPL_METHOD(CachingIterator, __toString) +{ + spl_dual_it_object *intern; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); + return; + } + if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) { + if (intern->current.key_type == HASH_KEY_IS_STRING) { + RETURN_STRINGL(intern->current.str_key, intern->current.str_key_len-1, 1); + } else { + RETVAL_LONG(intern->current.int_key); + convert_to_string(return_value); + return; + } + } else if (intern->u.caching.flags & CIT_TOSTRING_USE_CURRENT) { + MAKE_COPY_ZVAL(&intern->current.data, return_value); + convert_to_string(return_value); + return; + } + if (intern->u.caching.zstr) { + RETURN_STRINGL(Z_STRVAL_P(intern->u.caching.zstr), Z_STRLEN_P(intern->u.caching.zstr), 1); + } else { + RETURN_NULL(); + } +} /* }}} */ + +/* {{{ 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; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &arKey, &nKeyLength, &value) == FAILURE) { + return; + } + + Z_ADDREF_P(value); + 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; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); + return; + } + + 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; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); + return; + } + + 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; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); + return; + } + + 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; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_LONG(intern->u.caching.flags); +} +/* }}} */ + +/* {{{ proto void CachingIterator::setFlags(int flags) + Set the internal flags */ +SPL_METHOD(CachingIterator, setFlags) +{ + spl_dual_it_object *intern; + long flags; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); +} +/* }}} */ + +/* {{{ proto void CachingIterator::count() + Number of cached elements */ +SPL_METHOD(CachingIterator, count) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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_LONG(zend_hash_num_elements(HASH_OF(intern->u.caching.zcache))); +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_it___construct, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_caching_it_setFlags, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetGet, 0) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_caching_it_offsetSet, 0) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_CachingIterator[] = { + SPL_ME(CachingIterator, __construct, arginfo_caching_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, hasNext, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, __toString, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, getFlags, arginfo_recursive_it_void, 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, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, count, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +/* {{{ proto void RecursiveCachingIterator::__construct(RecursiveIterator it [, flags = CIT_CALL_TOSTRING]) + Create an iterator from a RecursiveIterator */ +SPL_METHOD(RecursiveCachingIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveCachingIterator, spl_ce_RecursiveIterator, DIT_RecursiveCachingIterator); +} /* }}} */ + +/* {{{ proto bool RecursiveCachingIterator::hasChildren() + Check whether the current element of the inner iterator has children */ +SPL_METHOD(RecursiveCachingIterator, hasChildren) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_BOOL(intern->u.caching.zchildren); +} /* }}} */ + +/* {{{ proto RecursiveCachingIterator RecursiveCachingIterator::getChildren() + Return the inner iterator's children as a RecursiveCachingIterator */ +SPL_METHOD(RecursiveCachingIterator, getChildren) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->u.caching.zchildren) { + RETURN_ZVAL(intern->u.caching.zchildren, 1, 0); + } else { + RETURN_NULL(); + } +} /* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_caching_rec_it___construct, 0, ZEND_RETURN_VALUE, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_RecursiveCachingIterator[] = { + SPL_ME(RecursiveCachingIterator, __construct, arginfo_caching_rec_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveCachingIterator, hasChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveCachingIterator, getChildren, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +/* {{{ proto void IteratorIterator::__construct(Traversable it) + Create an iterator from anything that is traversable */ +SPL_METHOD(IteratorIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_IteratorIterator, zend_ce_traversable, DIT_IteratorIterator); +} /* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_iterator_it___construct, 0) + ZEND_ARG_OBJ_INFO(0, iterator, Traversable, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_IteratorIterator[] = { + SPL_ME(IteratorIterator, __construct, arginfo_iterator_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +/* {{{ proto void NoRewindIterator::__construct(Iterator it) + Create an iterator from another iterator */ +SPL_METHOD(NoRewindIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_NoRewindIterator, zend_ce_iterator, DIT_NoRewindIterator); +} /* }}} */ + +/* {{{ proto void NoRewindIterator::rewind() + Prevent a call to inner iterators rewind() */ +SPL_METHOD(NoRewindIterator, rewind) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + /* nothing to do */ +} /* }}} */ + +/* {{{ proto bool NoRewindIterator::valid() + Return inner iterators valid() */ +SPL_METHOD(NoRewindIterator, valid) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + RETURN_BOOL(intern->inner.iterator->funcs->valid(intern->inner.iterator TSRMLS_CC) == SUCCESS); +} /* }}} */ + +/* {{{ proto mixed NoRewindIterator::key() + Return inner iterators key() */ +SPL_METHOD(NoRewindIterator, key) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + if (intern->inner.iterator->funcs->get_current_key) { + char *str_key; + uint str_key_len; + ulong int_key; + switch (intern->inner.iterator->funcs->get_current_key(intern->inner.iterator, &str_key, &str_key_len, &int_key TSRMLS_CC)) { + case HASH_KEY_IS_LONG: + RETURN_LONG(int_key); + break; + case HASH_KEY_IS_STRING: + RETURN_STRINGL(str_key, str_key_len-1, 0); + break; + default: + RETURN_NULL(); + } + } else { + RETURN_NULL(); + } +} /* }}} */ + +/* {{{ proto mixed NoRewindIterator::current() + Return inner iterators current() */ +SPL_METHOD(NoRewindIterator, current) +{ + spl_dual_it_object *intern; + zval **data; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + intern->inner.iterator->funcs->get_current_data(intern->inner.iterator, &data TSRMLS_CC); + if (data && *data) { + RETURN_ZVAL(*data, 1, 0); + } +} /* }}} */ + +/* {{{ proto void NoRewindIterator::next() + Return inner iterators next() */ +SPL_METHOD(NoRewindIterator, next) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + intern->inner.iterator->funcs->move_forward(intern->inner.iterator TSRMLS_CC); +} /* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_norewind_it___construct, 0) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_NoRewindIterator[] = { + SPL_ME(NoRewindIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(NoRewindIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(NoRewindIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(NoRewindIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(NoRewindIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(NoRewindIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +/* {{{ proto void InfiniteIterator::__construct(Iterator it) + Create an iterator from another iterator */ +SPL_METHOD(InfiniteIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_InfiniteIterator, zend_ce_iterator, DIT_InfiniteIterator); +} /* }}} */ + +/* {{{ proto void InfiniteIterator::next() + Prevent a call to inner iterators rewind() (internally the current data will be fetched if valid()) */ +SPL_METHOD(InfiniteIterator, next) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_dual_it_next(intern, 1 TSRMLS_CC); + if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { + spl_dual_it_fetch(intern, 0 TSRMLS_CC); + } else { + spl_dual_it_rewind(intern TSRMLS_CC); + if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { + spl_dual_it_fetch(intern, 0 TSRMLS_CC); + } + } +} /* }}} */ + +static const zend_function_entry spl_funcs_InfiniteIterator[] = { + SPL_ME(InfiniteIterator, __construct, arginfo_norewind_it___construct, ZEND_ACC_PUBLIC) + SPL_ME(InfiniteIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +/* {{{ proto void EmptyIterator::rewind() + Does nothing */ +SPL_METHOD(EmptyIterator, rewind) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } +} /* }}} */ + +/* {{{ proto false EmptyIterator::valid() + Return false */ +SPL_METHOD(EmptyIterator, valid) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + RETURN_FALSE; +} /* }}} */ + +/* {{{ proto void EmptyIterator::key() + Throws exception BadMethodCallException */ +SPL_METHOD(EmptyIterator, key) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0 TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void EmptyIterator::current() + Throws exception BadMethodCallException */ +SPL_METHOD(EmptyIterator, current) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0 TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void EmptyIterator::next() + Does nothing */ +SPL_METHOD(EmptyIterator, next) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } +} /* }}} */ + +static const zend_function_entry spl_funcs_EmptyIterator[] = { + SPL_ME(EmptyIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(EmptyIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(EmptyIterator, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(EmptyIterator, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(EmptyIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +int spl_append_it_next_iterator(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ +{ + spl_dual_it_free(intern TSRMLS_CC); + + if (intern->inner.zobject) { + zval_ptr_dtor(&intern->inner.zobject); + intern->inner.zobject = NULL; + intern->inner.ce = NULL; + intern->inner.object = NULL; + if (intern->inner.iterator) { + intern->inner.iterator->funcs->dtor(intern->inner.iterator TSRMLS_CC); + intern->inner.iterator = NULL; + } + } + if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) == SUCCESS) { + zval **it; + + intern->u.append.iterator->funcs->get_current_data(intern->u.append.iterator, &it TSRMLS_CC); + Z_ADDREF_PP(it); + 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, 0 TSRMLS_CC); + spl_dual_it_rewind(intern TSRMLS_CC); + return SUCCESS; + } else { + return FAILURE; + } +} /* }}} */ + +void spl_append_it_fetch(spl_dual_it_object *intern TSRMLS_DC) /* {{{*/ +{ + while (spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) { + intern->u.append.iterator->funcs->move_forward(intern->u.append.iterator TSRMLS_CC); + if (spl_append_it_next_iterator(intern TSRMLS_CC) != SUCCESS) { + return; + } + } + spl_dual_it_fetch(intern, 0 TSRMLS_CC); +} /* }}} */ + +void spl_append_it_next(spl_dual_it_object *intern TSRMLS_DC) /* {{{ */ +{ + if (spl_dual_it_valid(intern TSRMLS_CC) == SUCCESS) { + spl_dual_it_next(intern, 1 TSRMLS_CC); + } + spl_append_it_fetch(intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void AppendIterator::__construct() + Create an AppendIterator */ +SPL_METHOD(AppendIterator, __construct) +{ + spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_AppendIterator, zend_ce_iterator, DIT_AppendIterator); +} /* }}} */ + +/* {{{ proto void AppendIterator::append(Iterator it) + Append an iterator */ +SPL_METHOD(AppendIterator, append) +{ + spl_dual_it_object *intern; + zval *it; + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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); + + if (!intern->inner.iterator || spl_dual_it_valid(intern TSRMLS_CC) != SUCCESS) { + if (intern->u.append.iterator->funcs->valid(intern->u.append.iterator TSRMLS_CC) != SUCCESS) { + intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC); + } + do { + spl_append_it_next_iterator(intern TSRMLS_CC); + } while (intern->inner.zobject != it); + spl_append_it_fetch(intern TSRMLS_CC); + } +} /* }}} */ + +/* {{{ proto void AppendIterator::rewind() + Rewind to the first iterator and rewind the first iterator, too */ +SPL_METHOD(AppendIterator, rewind) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + intern->u.append.iterator->funcs->rewind(intern->u.append.iterator TSRMLS_CC); + if (spl_append_it_next_iterator(intern TSRMLS_CC) == SUCCESS) { + spl_append_it_fetch(intern TSRMLS_CC); + } +} /* }}} */ + +/* {{{ proto bool AppendIterator::valid() + Check if the current state is valid */ +SPL_METHOD(AppendIterator, valid) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_BOOL(intern->current.data); +} /* }}} */ + +/* {{{ proto void AppendIterator::next() + Forward to next element */ +SPL_METHOD(AppendIterator, next) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + spl_append_it_next(intern TSRMLS_CC); +} /* }}} */ + +/* {{{ proto int AppendIterator::getIteratorIndex() + Get index of iterator */ +SPL_METHOD(AppendIterator, getIteratorIndex) +{ + spl_dual_it_object *intern; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + 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; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + SPL_FETCH_AND_CHECK_DUAL_IT(intern, getThis()); + + RETURN_ZVAL(intern->u.append.zarrayit, 1, 0); +} /* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_append_it_append, 0) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_AppendIterator[] = { + SPL_ME(AppendIterator, __construct, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(AppendIterator, append, arginfo_append_it_append, ZEND_ACC_PUBLIC) + SPL_ME(AppendIterator, rewind, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(AppendIterator, valid, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, key, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, current, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(AppendIterator, next, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(dual_it, getInnerIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(AppendIterator, getIteratorIndex, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + SPL_ME(AppendIterator, getArrayIterator, arginfo_recursive_it_void, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + +PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC) +{ + zend_object_iterator *iter; + zend_class_entry *ce = Z_OBJCE_P(obj); + + iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC); + + if (EG(exception)) { + goto done; + } + + iter->index = 0; + if (iter->funcs->rewind) { + iter->funcs->rewind(iter TSRMLS_CC); + if (EG(exception)) { + goto done; + } + } + + while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) { + if (EG(exception)) { + goto done; + } + if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) { + goto done; + } + iter->index++; + iter->funcs->move_forward(iter TSRMLS_CC); + if (EG(exception)) { + goto done; + } + } + +done: + if (iter) { + 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 ZEND_HASH_APPLY_STOP; + } + if (data == NULL || *data == NULL) { + 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; + } + Z_ADDREF_PP(data); + 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 { + Z_ADDREF_PP(data); + add_next_index_zval(return_value, *data); + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +static int spl_iterator_to_values_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ +{ + zval **data, *return_value = (zval*)puser; + + iter->funcs->get_current_data(iter, &data TSRMLS_CC); + if (EG(exception)) { + return ZEND_HASH_APPLY_STOP; + } + if (data == NULL || *data == NULL) { + return ZEND_HASH_APPLY_STOP; + } + Z_ADDREF_PP(data); + add_next_index_zval(return_value, *data); + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/* {{{ proto array iterator_to_array(Traversable it [, bool use_keys = true]) + Copy the iterator into an array */ +PHP_FUNCTION(iterator_to_array) +{ + zval *obj; + zend_bool use_keys = 1; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) { + RETURN_FALSE; + } + + array_init(return_value); + + if (spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_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; +} +/* }}} */ + +/* {{{ proto int iterator_count(Traversable it) + Count the elements in an iterator */ +PHP_FUNCTION(iterator_count) +{ + zval *obj; + long count = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) { + RETURN_FALSE; + } + + if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) { + RETURN_LONG(count); + } +} +/* }}} */ + +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; + } + 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; + } + + 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; + } + zend_fcall_info_args(&apply_info.fci, NULL TSRMLS_CC); +} +/* }}} */ + +static const zend_function_entry spl_funcs_OuterIterator[] = { + SPL_ABSTRACT_ME(OuterIterator, getInnerIterator, arginfo_recursive_it_void) + PHP_FE_END +}; + +static const zend_function_entry spl_funcs_Countable[] = { + SPL_ABSTRACT_ME(Countable, count, arginfo_recursive_it_void) + PHP_FE_END +}; + +/* {{{ PHP_MINIT_FUNCTION(spl_iterators) + */ +PHP_MINIT_FUNCTION(spl_iterators) +{ + REGISTER_SPL_INTERFACE(RecursiveIterator); + REGISTER_SPL_ITERATOR(RecursiveIterator); + + REGISTER_SPL_STD_CLASS_EX(RecursiveIteratorIterator, spl_RecursiveIteratorIterator_new, spl_funcs_RecursiveIteratorIterator); + REGISTER_SPL_ITERATOR(RecursiveIteratorIterator); + + memcpy(&spl_handlers_rec_it_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_handlers_rec_it_it.get_method = spl_recursive_it_get_method; + spl_handlers_rec_it_it.clone_obj = NULL; + + memcpy(&spl_handlers_dual_it, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_handlers_dual_it.get_method = spl_dual_it_get_method; + /*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/ + spl_handlers_dual_it.clone_obj = NULL; + + spl_ce_RecursiveIteratorIterator->get_iterator = spl_recursive_it_get_iterator; + spl_ce_RecursiveIteratorIterator->iterator_funcs.funcs = &spl_recursive_it_iterator_funcs; + + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "LEAVES_ONLY", RIT_LEAVES_ONLY); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "SELF_FIRST", RIT_SELF_FIRST); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CHILD_FIRST", RIT_CHILD_FIRST); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveIteratorIterator, "CATCH_GET_CHILD", RIT_CATCH_GET_CHILD); + + REGISTER_SPL_INTERFACE(OuterIterator); + REGISTER_SPL_ITERATOR(OuterIterator); + + 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; + + REGISTER_SPL_SUB_CLASS_EX(RecursiveFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_RecursiveFilterIterator); + REGISTER_SPL_IMPLEMENTS(RecursiveFilterIterator, RecursiveIterator); + + REGISTER_SPL_SUB_CLASS_EX(CallbackFilterIterator, FilterIterator, spl_dual_it_new, spl_funcs_CallbackFilterIterator); + + REGISTER_SPL_SUB_CLASS_EX(RecursiveCallbackFilterIterator, CallbackFilterIterator, spl_dual_it_new, spl_funcs_RecursiveCallbackFilterIterator); + REGISTER_SPL_IMPLEMENTS(RecursiveCallbackFilterIterator, RecursiveIterator); + + + REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator); + + REGISTER_SPL_INTERFACE(Countable); + REGISTER_SPL_INTERFACE(SeekableIterator); + REGISTER_SPL_ITERATOR(SeekableIterator); + + 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_IMPLEMENTS(CachingIterator, Countable); + + 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); + + REGISTER_SPL_SUB_CLASS_EX(NoRewindIterator, IteratorIterator, spl_dual_it_new, spl_funcs_NoRewindIterator); + + 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); + + REGISTER_SPL_SUB_CLASS_EX(RecursiveTreeIterator, RecursiveIteratorIterator, spl_RecursiveTreeIterator_new, spl_funcs_RecursiveTreeIterator); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_CURRENT", RTIT_BYPASS_CURRENT); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "BYPASS_KEY", RTIT_BYPASS_KEY); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_LEFT", 0); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_HAS_NEXT", 1); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_MID_LAST", 2); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_HAS_NEXT", 3); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_END_LAST", 4); + REGISTER_SPL_CLASS_CONST_LONG(RecursiveTreeIterator, "PREFIX_RIGHT", 5); + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h new file mode 100644 index 0000000..39cc0d1 --- /dev/null +++ b/ext/spl/spl_iterators.h @@ -0,0 +1,186 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#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 +#define spl_ce_Aggregate zend_ce_aggregate +#define spl_ce_ArrayAccess zend_ce_arrayaccess +#define spl_ce_Serializable zend_ce_serializable + +extern PHPAPI zend_class_entry *spl_ce_RecursiveIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveIteratorIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveTreeIterator; +extern PHPAPI zend_class_entry *spl_ce_FilterIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveFilterIterator; +extern PHPAPI zend_class_entry *spl_ce_ParentIterator; +extern PHPAPI zend_class_entry *spl_ce_SeekableIterator; +extern PHPAPI zend_class_entry *spl_ce_LimitIterator; +extern PHPAPI zend_class_entry *spl_ce_CachingIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveCachingIterator; +extern PHPAPI zend_class_entry *spl_ce_OuterIterator; +extern PHPAPI zend_class_entry *spl_ce_IteratorIterator; +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; +extern PHPAPI zend_class_entry *spl_ce_Countable; +extern PHPAPI zend_class_entry *spl_ce_CallbackFilterIterator; +extern PHPAPI zend_class_entry *spl_ce_RecursiveCallbackFilterIterator; + +PHP_MINIT_FUNCTION(spl_iterators); + +PHP_FUNCTION(iterator_to_array); +PHP_FUNCTION(iterator_count); +PHP_FUNCTION(iterator_apply); + +typedef enum { + DIT_Default = 0, + DIT_FilterIterator = DIT_Default, + DIT_RecursiveFilterIterator = DIT_Default, + DIT_ParentIterator = DIT_Default, + DIT_LimitIterator, + DIT_CachingIterator, + DIT_RecursiveCachingIterator, + DIT_IteratorIterator, + DIT_NoRewindIterator, + DIT_InfiniteIterator, + DIT_AppendIterator, +#if HAVE_PCRE || HAVE_BUNDLED_PCRE + DIT_RegexIterator, + DIT_RecursiveRegexIterator, +#endif + DIT_CallbackFilterIterator, + DIT_RecursiveCallbackFilterIterator, + DIT_Unknown = ~0 +} dual_it_type; + +typedef enum { + RIT_Default = 0, + RIT_RecursiveIteratorIterator = RIT_Default, + RIT_RecursiveTreeIterator, + RIT_Unknow = ~0 +} recursive_it_it_type; + +enum { + /* public */ + CIT_CALL_TOSTRING = 0x00000001, + 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, + REGIT_INVERTED = 0x00000002 +}; + +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_cbfilter_it_intern { + zend_fcall_info fci; + zend_fcall_info_cache fcc; +} _spl_cbfilter_it_intern; + +typedef struct _spl_dual_it_object { + zend_object std; + struct { + zval *zobject; + zend_class_entry *ce; + zend_object *object; + zend_object_iterator *iterator; + } inner; + struct { + zval *data; + char *str_key; + uint str_key_len; + ulong int_key; + int key_type; /* HASH_KEY_IS_STRING or HASH_KEY_IS_LONG */ + int pos; + } current; + dual_it_type dit_type; + union { + struct { + long offset; + long count; + } limit; + struct { + 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; + uint regex_len; + } regex; +#endif + _spl_cbfilter_it_intern *cbfilter; + } 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 */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c new file mode 100644 index 0000000..5d89566 --- /dev/null +++ b/ext/spl/spl_observer.c @@ -0,0 +1,1341 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + | Etienne Kneuss <colder@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "ext/standard/php_var.h" +#include "ext/standard/php_smart_str.h" +#include "zend_interfaces.h" +#include "zend_exceptions.h" + +#include "php_spl.h" +#include "spl_functions.h" +#include "spl_engine.h" +#include "spl_observer.h" +#include "spl_iterators.h" +#include "spl_array.h" +#include "spl_exceptions.h" + +SPL_METHOD(SplObserver, update); +SPL_METHOD(SplSubject, attach); +SPL_METHOD(SplSubject, detach); +SPL_METHOD(SplSubject, notify); + +ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0) + ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_SplObserver[] = { + SPL_ABSTRACT_ME(SplObserver, update, arginfo_SplObserver_update) + {NULL, NULL, NULL} +}; + +ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0) + ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_void, 0) +ZEND_END_ARG_INFO(); + +/*ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1) +ZEND_END_ARG_INFO();*/ + +static const zend_function_entry spl_funcs_SplSubject[] = { + SPL_ABSTRACT_ME(SplSubject, attach, arginfo_SplSubject_attach) + SPL_ABSTRACT_ME(SplSubject, detach, arginfo_SplSubject_attach) + SPL_ABSTRACT_ME(SplSubject, notify, arginfo_SplSubject_void) + {NULL, NULL, NULL} +}; + +PHPAPI zend_class_entry *spl_ce_SplObserver; +PHPAPI zend_class_entry *spl_ce_SplSubject; +PHPAPI zend_class_entry *spl_ce_SplObjectStorage; +PHPAPI zend_class_entry *spl_ce_MultipleIterator; + +PHPAPI zend_object_handlers spl_handler_SplObjectStorage; + +typedef struct _spl_SplObjectStorage { /* {{{ */ + zend_object std; + HashTable storage; + long index; + HashPosition pos; + long flags; + zend_function *fptr_get_hash; + HashTable *debug_info; +} spl_SplObjectStorage; /* }}} */ + +/* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */ +typedef struct _spl_SplObjectStorageElement { + zval* obj; + zval* inf; +} spl_SplObjectStorageElement; /* }}} */ + +void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object; + + zend_object_std_dtor(&intern->std TSRMLS_CC); + + zend_hash_destroy(&intern->storage); + + if (intern->debug_info != NULL) { + zend_hash_destroy(intern->debug_info); + efree(intern->debug_info); + } + + efree(object); +} /* }}} */ + +static char *spl_object_storage_get_hash(spl_SplObjectStorage *intern, zval *this, zval *obj, int *hash_len_ptr TSRMLS_DC) { + if (intern->fptr_get_hash) { + zval *rv; + zend_call_method_with_1_params(&this, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, obj); + if (rv) { + if (Z_TYPE_P(rv) == IS_STRING) { + int hash_len = Z_STRLEN_P(rv); + char *hash = emalloc((hash_len+1)*sizeof(char)); + strncpy(hash, Z_STRVAL_P(rv), hash_len); + hash[hash_len] = 0; + + zval_ptr_dtor(&rv); + if (hash_len_ptr) { + *hash_len_ptr = hash_len; + } + return hash; + } else { + zend_throw_exception(spl_ce_RuntimeException, "Hash needs to be a string", 0 TSRMLS_CC); + + zval_ptr_dtor(&rv); + return NULL; + } + } else { + return NULL; + } + } else { + int hash_len = sizeof(zend_object_value); + +#if HAVE_PACKED_OBJECT_VALUE + + if (hash_len_ptr) { + *hash_len_ptr = hash_len; + } + + return (char*)&Z_OBJVAL_P(obj); +#else + char *hash = emalloc(hash_len + 1); + + zend_object_value zvalue; + memset(&zvalue, 0, sizeof(zend_object_value)); + zvalue.handle = Z_OBJ_HANDLE_P(obj); + zvalue.handlers = Z_OBJ_HT_P(obj); + + memcpy(hash, (char *)&zvalue, hash_len); + hash[hash_len] = 0; + + if (hash_len_ptr) { + *hash_len_ptr = hash_len; + } + + return hash; +#endif + } +} + +static void spl_object_storage_free_hash(spl_SplObjectStorage *intern, char *hash) { + if (intern->fptr_get_hash) { + efree(hash); + } else { +#if HAVE_PACKED_OBJECT_VALUE + /* Nothing to do */ +#else + efree(hash); +#endif + } +} + +static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{ */ +{ + zval_ptr_dtor(&element->obj); + zval_ptr_dtor(&element->inf); +} /* }}} */ + +spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, char *hash, int hash_len TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorageElement *element; + if (zend_hash_find(&intern->storage, hash, hash_len, (void**)&element) == SUCCESS) { + return element; + } else { + return NULL; + } +} /* }}} */ + +void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *this, zval *obj, zval *inf TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorageElement *pelement, element; + + int hash_len; + char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC); + if (!hash) { + return; + } + + pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC); + + if (inf) { + Z_ADDREF_P(inf); + } else { + ALLOC_INIT_ZVAL(inf); + } + if (pelement) { + zval_ptr_dtor(&pelement->inf); + pelement->inf = inf; + spl_object_storage_free_hash(intern, hash); + return; + } + Z_ADDREF_P(obj); + element.obj = obj; + element.inf = inf; + zend_hash_update(&intern->storage, hash, hash_len, &element, sizeof(spl_SplObjectStorageElement), NULL); + spl_object_storage_free_hash(intern, hash); +} /* }}} */ + +int spl_object_storage_detach(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */ +{ + int hash_len, ret = FAILURE; + char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC); + if (!hash) { + return ret; + } + ret = zend_hash_del(&intern->storage, hash, hash_len); + spl_object_storage_free_hash(intern, hash); + + return ret; +} /* }}}*/ + +void spl_object_storage_addall(spl_SplObjectStorage *intern, zval *this, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */ + HashPosition pos; + spl_SplObjectStorageElement *element; + + zend_hash_internal_pointer_reset_ex(&other->storage, &pos); + while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) { + spl_object_storage_attach(intern, this, element->obj, element->inf TSRMLS_CC); + zend_hash_move_forward_ex(&other->storage, &pos); + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; +} /* }}} */ + +static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + spl_SplObjectStorage *intern; + zend_class_entry *parent = class_type; + + intern = emalloc(sizeof(spl_SplObjectStorage)); + memset(intern, 0, sizeof(spl_SplObjectStorage)); + *obj = intern; + + zend_object_std_init(&intern->std, class_type TSRMLS_CC); + object_properties_init(&intern->std, class_type); + + zend_hash_init(&intern->storage, 0, NULL, (void (*)(void *))spl_object_storage_dtor, 0); + + retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage, NULL TSRMLS_CC); + retval.handlers = &spl_handler_SplObjectStorage; + + if (orig) { + spl_SplObjectStorage *other = (spl_SplObjectStorage*)zend_object_store_get_object(orig TSRMLS_CC); + spl_object_storage_addall(intern, orig, other TSRMLS_CC); + } + + while (parent) { + if (parent == spl_ce_SplObjectStorage) { + if (class_type != spl_ce_SplObjectStorage) { + zend_hash_find(&class_type->function_table, "gethash", sizeof("gethash"), (void **) &intern->fptr_get_hash); + if (intern->fptr_get_hash->common.scope == spl_ce_SplObjectStorage) { + intern->fptr_get_hash = NULL; + } + } + break; + } + + parent = parent->parent; + } + + return retval; +} +/* }}} */ + +/* {{{ spl_object_storage_clone */ +static zend_object_value spl_object_storage_clone(zval *zobject TSRMLS_DC) +{ + zend_object_value new_obj_val; + zend_object *old_object; + zend_object *new_object; + zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); + spl_SplObjectStorage *intern; + + old_object = zend_objects_get_address(zobject TSRMLS_CC); + new_obj_val = spl_object_storage_new_ex(old_object->ce, &intern, zobject TSRMLS_CC); + new_object = &intern->std; + + zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); + + return new_obj_val; +} +/* }}} */ + +static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC); + spl_SplObjectStorageElement *element; + HashTable *props; + HashPosition pos; + zval *tmp, *storage; + char md5str[33]; + int name_len; + char *zname; + + *is_temp = 0; + + props = Z_OBJPROP_P(obj); + zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata")); + + if (intern->debug_info == NULL) { + ALLOC_HASHTABLE(intern->debug_info); + ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(props) + 1, 0); + } + + if (intern->debug_info->nApplyCount == 0) { + zend_hash_copy(intern->debug_info, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + + MAKE_STD_ZVAL(storage); + array_init(storage); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) { + php_spl_object_hash(element->obj, md5str TSRMLS_CC); + MAKE_STD_ZVAL(tmp); + array_init(tmp); + /* Incrementing the refcount of obj and inf would confuse the garbage collector. + * Prefer to null the destructor */ + Z_ARRVAL_P(tmp)->pDestructor = NULL; + add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj); + add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf); + add_assoc_zval_ex(storage, md5str, 33, tmp); + zend_hash_move_forward_ex(&intern->storage, &pos); + } + + zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC); + zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL); + efree(zname); + } + + return intern->debug_info; +} +/* }}} */ + +/* overriden for garbage collection + * This is very hacky */ +static HashTable *spl_object_storage_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC); + spl_SplObjectStorageElement *element; + HashTable *props; + HashPosition pos; + zval *gcdata_arr = NULL, + **gcdata_arr_pp; + + props = std_object_handlers.get_properties(obj TSRMLS_CC); + + *table = NULL; + *n = 0; + + /* clean \x00gcdata, as it may be out of date */ + if (zend_hash_find(props, "\x00gcdata", sizeof("\x00gcdata"), (void**) &gcdata_arr_pp) == SUCCESS) { + gcdata_arr = *gcdata_arr_pp; + zend_hash_clean(Z_ARRVAL_P(gcdata_arr)); + } + + if (gcdata_arr == NULL) { + MAKE_STD_ZVAL(gcdata_arr); + array_init(gcdata_arr); + /* don't decrease refcount of members when destroying */ + Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL; + + /* name starts with \x00 to make tampering in user-land more difficult */ + zend_hash_add(props, "\x00gcdata", sizeof("\x00gcdata"), &gcdata_arr, sizeof(gcdata_arr), NULL); + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) { + add_next_index_zval(gcdata_arr, element->obj); + add_next_index_zval(gcdata_arr, element->inf); + zend_hash_move_forward_ex(&intern->storage, &pos); + } + + return props; +} +/* }}} */ + +static int spl_object_storage_compare_info(spl_SplObjectStorageElement *e1, spl_SplObjectStorageElement *e2 TSRMLS_DC) /* {{{ */ +{ + zval result; + + if (compare_function(&result, e1->inf, e2->inf TSRMLS_CC) == FAILURE) { + return 1; + } + + return Z_LVAL(result); +} +/* }}} */ + +static int spl_object_storage_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ +{ + zend_object *zo1 = (zend_object *)zend_object_store_get_object(o1 TSRMLS_CC); + zend_object *zo2 = (zend_object *)zend_object_store_get_object(o2 TSRMLS_CC); + + if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) { + return 1; + } + + return zend_hash_compare(&((spl_SplObjectStorage *)zo1)->storage, &((spl_SplObjectStorage *)zo2)->storage, (compare_func_t) spl_object_storage_compare_info, 0 TSRMLS_CC); +} +/* }}} */ + +/* {{{ spl_array_object_new */ +static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC) +{ + spl_SplObjectStorage *tmp; + return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC); +} +/* }}} */ + +int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */ +{ + int hash_len, found; + char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC); + if (!hash) { + return 0; + } + + found = zend_hash_exists(&intern->storage, hash, hash_len); + spl_object_storage_free_hash(intern, hash); + return found; +} /* }}} */ + +/* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL) + Attaches an object to the storage if not yet contained */ +SPL_METHOD(SplObjectStorage, attach) +{ + zval *obj, *inf = NULL; + + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) { + return; + } + spl_object_storage_attach(intern, getThis(), obj, inf TSRMLS_CC); +} /* }}} */ + +/* {{{ proto void SplObjectStorage::detach($obj) + Detaches an object from the storage */ +SPL_METHOD(SplObjectStorage, detach) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + spl_object_storage_detach(intern, getThis(), obj TSRMLS_CC); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; +} /* }}} */ + +/* {{{ proto string SplObjectStorage::getHash($object) + Returns the hash of an object */ +SPL_METHOD(SplObjectStorage, getHash) +{ + zval *obj; + char *hash; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + hash = emalloc(33); + php_spl_object_hash(obj, hash TSRMLS_CC); + + RETVAL_STRING(hash, 0); + +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::offsetGet($object) + Returns associated information for a stored object */ +SPL_METHOD(SplObjectStorage, offsetGet) +{ + zval *obj; + spl_SplObjectStorageElement *element; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + char *hash; + int hash_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + hash = spl_object_storage_get_hash(intern, getThis(), obj, &hash_len TSRMLS_CC); + if (!hash) { + return; + } + + element = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC); + spl_object_storage_free_hash(intern, hash); + + if (!element) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found"); + } else { + RETURN_ZVAL(element->inf,1, 0); + } +} /* }}} */ + +/* {{{ proto bool SplObjectStorage::addAll(SplObjectStorage $os) + Add all elements contained in $os */ +SPL_METHOD(SplObjectStorage, addAll) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_SplObjectStorage *other; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) { + return; + } + + other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC); + + spl_object_storage_addall(intern, getThis(), other TSRMLS_CC); + + RETURN_LONG(zend_hash_num_elements(&intern->storage)); +} /* }}} */ + +/* {{{ proto bool SplObjectStorage::removeAll(SplObjectStorage $os) + Remove all elements contained in $os */ +SPL_METHOD(SplObjectStorage, removeAll) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_SplObjectStorage *other; + spl_SplObjectStorageElement *element; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) { + return; + } + + other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC); + + zend_hash_internal_pointer_reset(&other->storage); + while (zend_hash_get_current_data(&other->storage, (void **)&element) == SUCCESS) { + if (spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC) == FAILURE) { + zend_hash_move_forward(&other->storage); + } + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; + + RETURN_LONG(zend_hash_num_elements(&intern->storage)); +} /* }}} */ + +/* {{{ proto bool SplObjectStorage::removeAllExcept(SplObjectStorage $os) + Remove elements not common to both this SplObjectStorage instance and $os */ +SPL_METHOD(SplObjectStorage, removeAllExcept) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC); + spl_SplObjectStorage *other; + spl_SplObjectStorageElement *element; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) { + return; + } + + other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC); + + zend_hash_internal_pointer_reset(&intern->storage); + while (zend_hash_get_current_data(&intern->storage, (void **)&element) == SUCCESS) { + if (!spl_object_storage_contains(other, getThis(), element->obj TSRMLS_CC)) { + spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC); + } + zend_hash_move_forward(&intern->storage); + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; + + RETURN_LONG(zend_hash_num_elements(&intern->storage)); +} +/* }}} */ + +/* {{{ proto bool SplObjectStorage::contains($obj) + Determine whethe an object is contained in the storage */ +SPL_METHOD(SplObjectStorage, contains) +{ + zval *obj; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + RETURN_BOOL(spl_object_storage_contains(intern, getThis(), obj TSRMLS_CC)); +} /* }}} */ + +/* {{{ proto int SplObjectStorage::count() + Determine number of objects in storage */ +SPL_METHOD(SplObjectStorage, count) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(zend_hash_num_elements(&intern->storage)); +} /* }}} */ + +/* {{{ proto void SplObjectStorage::rewind() + Rewind to first position */ +SPL_METHOD(SplObjectStorage, rewind) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + intern->index = 0; +} /* }}} */ + +/* {{{ proto bool SplObjectStorage::valid() + Returns whether current position is valid */ +SPL_METHOD(SplObjectStorage, valid) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS); +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::key() + Returns current key */ +SPL_METHOD(SplObjectStorage, key) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + RETURN_LONG(intern->index); +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::current() + Returns current element */ +SPL_METHOD(SplObjectStorage, current) +{ + spl_SplObjectStorageElement *element; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) { + return; + } + RETVAL_ZVAL(element->obj, 1, 0); +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::getInfo() + Returns associated information to current element */ +SPL_METHOD(SplObjectStorage, getInfo) +{ + spl_SplObjectStorageElement *element; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) { + return; + } + RETVAL_ZVAL(element->inf, 1, 0); +} /* }}} */ + +/* {{{ proto mixed SplObjectStorage::setInfo(mixed $inf) + Sets associated information of current element to $inf */ +SPL_METHOD(SplObjectStorage, setInfo) +{ + spl_SplObjectStorageElement *element; + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + zval *inf; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &inf) == FAILURE) { + return; + } + + if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) { + return; + } + zval_ptr_dtor(&element->inf); + element->inf = inf; + Z_ADDREF_P(inf); +} /* }}} */ + +/* {{{ proto void SplObjectStorage::next() + Moves position forward */ +SPL_METHOD(SplObjectStorage, next) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + intern->index++; +} /* }}} */ + +/* {{{ proto string SplObjectStorage::serialize() + Serializes storage */ +SPL_METHOD(SplObjectStorage, serialize) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + spl_SplObjectStorageElement *element; + zval members, *pmembers, *flags; + HashPosition pos; + php_serialize_data_t var_hash; + smart_str buf = {0}; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + PHP_VAR_SERIALIZE_INIT(var_hash); + + /* storage */ + smart_str_appendl(&buf, "x:", 2); + MAKE_STD_ZVAL(flags); + ZVAL_LONG(flags, zend_hash_num_elements(&intern->storage)); + php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC); + zval_ptr_dtor(&flags); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &pos); + + while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) { + if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &pos) == FAILURE) { + smart_str_free(&buf); + PHP_VAR_SERIALIZE_DESTROY(var_hash); + RETURN_NULL(); + } + php_var_serialize(&buf, &element->obj, &var_hash TSRMLS_CC); + smart_str_appendc(&buf, ','); + php_var_serialize(&buf, &element->inf, &var_hash TSRMLS_CC); + smart_str_appendc(&buf, ';'); + zend_hash_move_forward_ex(&intern->storage, &pos); + } + + /* members */ + smart_str_appendl(&buf, "m:", 2); + INIT_PZVAL(&members); + Z_ARRVAL(members) = zend_std_get_properties(getThis() TSRMLS_CC); + Z_TYPE(members) = IS_ARRAY; + pmembers = &members; + php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */ + + /* done */ + PHP_VAR_SERIALIZE_DESTROY(var_hash); + + if (buf.c) { + RETURN_STRINGL(buf.c, buf.len, 0); + } else { + RETURN_NULL(); + } + +} /* }}} */ + +/* {{{ proto void SplObjectStorage::unserialize(string serialized) + Unserializes storage */ +SPL_METHOD(SplObjectStorage, unserialize) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + char *buf; + int buf_len; + const unsigned char *p, *s; + php_unserialize_data_t var_hash; + zval *pentry, *pmembers, *pcount = NULL, *pinf; + long count; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { + return; + } + + if (buf_len == 0) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty"); + return; + } + + /* storage */ + s = p = (const unsigned char*)buf; + PHP_VAR_UNSERIALIZE_INIT(var_hash); + + if (*p!= 'x' || *++p != ':') { + goto outexcept; + } + ++p; + + ALLOC_INIT_ZVAL(pcount); + if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) { + goto outexcept; + } + + --p; /* for ';' */ + count = Z_LVAL_P(pcount); + + while(count-- > 0) { + spl_SplObjectStorageElement *pelement; + char *hash; + int hash_len; + + if (*p != ';') { + goto outexcept; + } + ++p; + if(*p != 'O' && *p != 'C' && *p != 'r') { + goto outexcept; + } + ALLOC_INIT_ZVAL(pentry); + if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&pentry); + goto outexcept; + } + if(Z_TYPE_P(pentry) != IS_OBJECT) { + zval_ptr_dtor(&pentry); + goto outexcept; + } + ALLOC_INIT_ZVAL(pinf); + if (*p == ',') { /* new version has inf */ + ++p; + if (!php_var_unserialize(&pinf, &p, s + buf_len, &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&pinf); + goto outexcept; + } + } + + hash = spl_object_storage_get_hash(intern, getThis(), pentry, &hash_len TSRMLS_CC); + if (!hash) { + zval_ptr_dtor(&pentry); + zval_ptr_dtor(&pinf); + goto outexcept; + } + pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC); + spl_object_storage_free_hash(intern, hash); + if(pelement) { + if(pelement->inf) { + var_push_dtor(&var_hash, &pelement->inf); + } + if(pelement->obj) { + var_push_dtor(&var_hash, &pelement->obj); + } + } + spl_object_storage_attach(intern, getThis(), pentry, pinf TSRMLS_CC); + zval_ptr_dtor(&pentry); + zval_ptr_dtor(&pinf); + } + + if (*p != ';') { + goto outexcept; + } + ++p; + + /* members */ + if (*p!= 'm' || *++p != ':') { + goto outexcept; + } + ++p; + + ALLOC_INIT_ZVAL(pmembers); + if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&pmembers); + goto outexcept; + } + + /* copy members */ + if (!intern->std.properties) { + rebuild_object_properties(&intern->std); + } + zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *)); + zval_ptr_dtor(&pmembers); + + /* done reading $serialized */ + if (pcount) { + zval_ptr_dtor(&pcount); + } + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return; + +outexcept: + if (pcount) { + zval_ptr_dtor(&pcount); + } + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len); + return; + +} /* }}} */ + +ZEND_BEGIN_ARG_INFO(arginfo_Object, 0) + ZEND_ARG_INFO(0, object) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_attach, 0, 0, 1) + ZEND_ARG_INFO(0, object) + ZEND_ARG_INFO(0, inf) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0) + ZEND_ARG_INFO(0, serialized) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0) + ZEND_ARG_INFO(0, info) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO(arginfo_getHash, 0) + ZEND_ARG_INFO(0, object) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, object) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_splobject_void, 0) +ZEND_END_ARG_INFO() + +static const zend_function_entry spl_funcs_SplObjectStorage[] = { + SPL_ME(SplObjectStorage, attach, arginfo_attach, 0) + SPL_ME(SplObjectStorage, detach, arginfo_Object, 0) + SPL_ME(SplObjectStorage, contains, arginfo_Object, 0) + SPL_ME(SplObjectStorage, addAll, arginfo_Object, 0) + SPL_ME(SplObjectStorage, removeAll, arginfo_Object, 0) + SPL_ME(SplObjectStorage, removeAllExcept, arginfo_Object, 0) + SPL_ME(SplObjectStorage, getInfo, arginfo_splobject_void,0) + SPL_ME(SplObjectStorage, setInfo, arginfo_setInfo, 0) + SPL_ME(SplObjectStorage, getHash, arginfo_getHash, 0) + /* Countable */ + SPL_ME(SplObjectStorage, count, arginfo_splobject_void,0) + /* Iterator */ + SPL_ME(SplObjectStorage, rewind, arginfo_splobject_void,0) + SPL_ME(SplObjectStorage, valid, arginfo_splobject_void,0) + SPL_ME(SplObjectStorage, key, arginfo_splobject_void,0) + SPL_ME(SplObjectStorage, current, arginfo_splobject_void,0) + SPL_ME(SplObjectStorage, next, arginfo_splobject_void,0) + /* Serializable */ + SPL_ME(SplObjectStorage, unserialize, arginfo_Serialized, 0) + SPL_ME(SplObjectStorage, serialize, arginfo_splobject_void,0) + /* ArrayAccess */ + SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0) + SPL_MA(SplObjectStorage, offsetSet, SplObjectStorage, attach, arginfo_attach, 0) + SPL_MA(SplObjectStorage, offsetUnset, SplObjectStorage, detach, arginfo_offsetGet, 0) + SPL_ME(SplObjectStorage, offsetGet, arginfo_offsetGet, 0) + {NULL, NULL, NULL} +}; + +typedef enum { + MIT_NEED_ANY = 0, + MIT_NEED_ALL = 1, + MIT_KEYS_NUMERIC = 0, + MIT_KEYS_ASSOC = 2 +} MultipleIteratorFlags; + +#define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT 1 +#define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY 2 + +/* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC]) + Iterator that iterates over several iterators one after the other */ +SPL_METHOD(MultipleIterator, __construct) +{ + spl_SplObjectStorage *intern; + long flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC; + zend_error_handling error_handling; + + zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) { + zend_restore_error_handling(&error_handling TSRMLS_CC); + return; + } + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + intern->flags = flags; + zend_restore_error_handling(&error_handling TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto int MultipleIterator::getFlags() + Return current flags */ +SPL_METHOD(MultipleIterator, getFlags) +{ + spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + RETURN_LONG(intern->flags); +} +/* }}} */ + +/* {{{ proto int MultipleIterator::setFlags(int flags) + Set flags */ +SPL_METHOD(MultipleIterator, setFlags) +{ + spl_SplObjectStorage *intern; + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) { + return; + } +} +/* }}} */ + +/* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException + Attach a new iterator */ +SPL_METHOD(MultipleIterator, attachIterator) +{ + spl_SplObjectStorage *intern; + zval *iterator = NULL, *info = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) { + return; + } + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (info != NULL) { + spl_SplObjectStorageElement *element; + zval compare_result; + + if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING) { + zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC); + return; + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) { + is_identical_function(&compare_result, info, element->inf TSRMLS_CC); + if (Z_LVAL(compare_result)) { + zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC); + return; + } + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } + } + + spl_object_storage_attach(intern, getThis(), iterator, info TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void MultipleIterator::rewind() + Rewind all attached iterator instances */ +SPL_METHOD(MultipleIterator, rewind) +{ + spl_SplObjectStorage *intern; + spl_SplObjectStorageElement *element; + zval *it; + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL); + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } +} +/* }}} */ + +/* {{{ proto void MultipleIterator::next() + Move all attached iterator instances forward */ +SPL_METHOD(MultipleIterator, next) +{ + spl_SplObjectStorage *intern; + spl_SplObjectStorageElement *element; + zval *it; + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL); + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } +} +/* }}} */ + +/* {{{ proto bool MultipleIterator::valid() + Return whether all or one sub iterator is valid depending on flags */ +SPL_METHOD(MultipleIterator, valid) +{ + spl_SplObjectStorage *intern; + spl_SplObjectStorageElement *element; + zval *it, *retval = NULL; + long expect, valid; + + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (!zend_hash_num_elements(&intern->storage)) { + RETURN_FALSE; + } + + expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0; + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval); + + if (retval) { + valid = Z_LVAL_P(retval); + zval_ptr_dtor(&retval); + } else { + valid = 0; + } + + if (expect != valid) { + RETURN_BOOL(!expect); + } + + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } + + RETURN_BOOL(expect); +} +/* }}} */ + +static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */ +{ + spl_SplObjectStorageElement *element; + zval *it, *retval = NULL; + int valid = 1, num_elements; + + num_elements = zend_hash_num_elements(&intern->storage); + if (num_elements < 1) { + RETURN_FALSE; + } + + array_init_size(return_value, num_elements); + + zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos); + while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) { + it = element->obj; + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval); + + if (retval) { + valid = Z_LVAL_P(retval); + zval_ptr_dtor(&retval); + } else { + valid = 0; + } + + if (valid) { + if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) { + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval); + } else { + zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key, "key", &retval); + } + if (!retval) { + zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC); + return; + } + } else if (intern->flags & MIT_NEED_ALL) { + if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) { + zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC); + } else { + zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC); + } + return; + } else { + ALLOC_INIT_ZVAL(retval); + } + + if (intern->flags & MIT_KEYS_ASSOC) { + switch (Z_TYPE_P(element->inf)) { + case IS_LONG: + add_index_zval(return_value, Z_LVAL_P(element->inf), retval); + break; + case IS_STRING: + add_assoc_zval_ex(return_value, Z_STRVAL_P(element->inf), Z_STRLEN_P(element->inf)+1U, retval); + break; + default: + zval_ptr_dtor(&retval); + zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC); + return; + } + } else { + add_next_index_zval(return_value, retval); + } + + zend_hash_move_forward_ex(&intern->storage, &intern->pos); + } +} +/* }}} */ + +/* {{{ proto array current() throws RuntimeException throws InvalidArgumentException + Return an array of all registered Iterator instances current() result */ +SPL_METHOD(MultipleIterator, current) +{ + spl_SplObjectStorage *intern; + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto array MultipleIterator::key() + Return an array of all registered Iterator instances key() result */ +SPL_METHOD(MultipleIterator, key) +{ + spl_SplObjectStorage *intern; + intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC); +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) + ZEND_ARG_INFO(0, infos) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1) + ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0) +ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_setflags, 0, 0, 1) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO(); + +static const zend_function_entry spl_funcs_MultipleIterator[] = { + SPL_ME(MultipleIterator, __construct, arginfo_MultipleIterator_setflags, 0) + SPL_ME(MultipleIterator, getFlags, arginfo_splobject_void, 0) + SPL_ME(MultipleIterator, setFlags, arginfo_MultipleIterator_setflags, 0) + SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0) + SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0) + SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0) + SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0) + /* Iterator */ + SPL_ME(MultipleIterator, rewind, arginfo_splobject_void, 0) + SPL_ME(MultipleIterator, valid, arginfo_splobject_void, 0) + SPL_ME(MultipleIterator, key, arginfo_splobject_void, 0) + SPL_ME(MultipleIterator, current, arginfo_splobject_void, 0) + SPL_ME(MultipleIterator, next, arginfo_splobject_void, 0) + {NULL, NULL, NULL} +}; + +/* {{{ PHP_MINIT_FUNCTION(spl_observer) */ +PHP_MINIT_FUNCTION(spl_observer) +{ + REGISTER_SPL_INTERFACE(SplObserver); + REGISTER_SPL_INTERFACE(SplSubject); + + REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage); + memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + + spl_handler_SplObjectStorage.get_debug_info = spl_object_storage_debug_info; + spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects; + spl_handler_SplObjectStorage.clone_obj = spl_object_storage_clone; + spl_handler_SplObjectStorage.get_gc = spl_object_storage_get_gc; + + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable); + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator); + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable); + REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess); + + REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator); + REGISTER_SPL_ITERATOR(MultipleIterator); + + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY", MIT_NEED_ANY); + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL", MIT_NEED_ALL); + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC); + REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC", MIT_KEYS_ASSOC); + + return SUCCESS; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/spl_observer.h b/ext/spl/spl_observer.h new file mode 100644 index 0000000..e93e304 --- /dev/null +++ b/ext/spl/spl_observer.h @@ -0,0 +1,43 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifndef SPL_OBSERVER_H +#define SPL_OBSERVER_H + +#include "php.h" +#include "php_spl.h" + +extern PHPAPI zend_class_entry *spl_ce_SplObserver; +extern PHPAPI zend_class_entry *spl_ce_SplSubject; +extern PHPAPI zend_class_entry *spl_ce_SplObjectStorage; +extern PHPAPI zend_class_entry *spl_ce_MultipleIterator; + +PHP_MINIT_FUNCTION(spl_observer); + +#endif /* SPL_OBSERVER_H */ + +/* + * Local Variables: + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim600: fdm=marker + * vim: noet sw=4 ts=4 + */ diff --git a/ext/spl/tests/ArrayObject_unserialize_empty_string.phpt b/ext/spl/tests/ArrayObject_unserialize_empty_string.phpt new file mode 100644 index 0000000..75d8a41 --- /dev/null +++ b/ext/spl/tests/ArrayObject_unserialize_empty_string.phpt @@ -0,0 +1,16 @@ +--TEST-- +ArrayObject: test that you cannot unserialize a empty string +--CREDITS-- +Havard Eide <nucleuz@gmail.com> +#PHPTestFest2009 Norway 2009-06-09 \o/ +--FILE-- +<?php +$a = new ArrayObject(array()); +$a->unserialize(""); +?> +--EXPECTF-- +Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Empty serialized string cannot be empty' in %s.php:%d +Stack trace: +#0 %s(%d): ArrayObject->unserialize('') +#1 {main} + thrown in %s.php on line %d diff --git a/ext/spl/tests/CallbackFilterIteratorTest-002.phpt b/ext/spl/tests/CallbackFilterIteratorTest-002.phpt new file mode 100644 index 0000000..cbad2e3 --- /dev/null +++ b/ext/spl/tests/CallbackFilterIteratorTest-002.phpt @@ -0,0 +1,50 @@ +--TEST-- +CallbackFilterIterator 002 +--FILE-- +<?php + +set_error_handler(function($errno, $errstr){ + echo $errstr . "\n"; + return true; +}); + +try { + new CallbackFilterIterator(); +} catch(InvalidArgumentException $e) { + echo $e->getMessage() . "\n"; +} + +try { + new CallbackFilterIterator(null); +} catch(InvalidArgumentException $e) { + echo $e->getMessage() . "\n"; +} + +try { + new CallbackFilterIterator(new ArrayIterator(array()), null); +} catch(InvalidArgumentException $e) { + echo $e->getMessage() . "\n"; +} + +try { + new CallbackFilterIterator(new ArrayIterator(array()), array()); +} catch(InvalidArgumentException $e) { + echo $e->getMessage() . "\n"; +} + +$it = new CallbackFilterIterator(new ArrayIterator(array(1)), function() { + throw new Exception("some message"); +}); +try { + foreach($it as $e); +} catch(Exception $e) { + echo $e->getMessage() . "\n"; +} + +--EXPECT-- +CallbackFilterIterator::__construct() expects exactly 2 parameters, 0 given +Argument 1 passed to CallbackFilterIterator::__construct() must implement interface Iterator, null given +CallbackFilterIterator::__construct() expects exactly 2 parameters, 1 given +CallbackFilterIterator::__construct() expects parameter 2 to be a valid callback, no array or string given +CallbackFilterIterator::__construct() expects parameter 2 to be a valid callback, array must have exactly two members +some message diff --git a/ext/spl/tests/CallbackFilterIteratorTest.phpt b/ext/spl/tests/CallbackFilterIteratorTest.phpt new file mode 100644 index 0000000..36bc770 --- /dev/null +++ b/ext/spl/tests/CallbackFilterIteratorTest.phpt @@ -0,0 +1,133 @@ +--TEST-- +CallbackFilterIterator +--FILE-- +<?php + +class A { + function test($value, $key, $inner) { + return test($value, $key, $inner); + } +} + +class B { + static function test($value, $key, $inner) { + return test($value, $key, $inner); + } +} + +function test($value, $key, $inner) { + printf("%s / %s / %d / %d\n" + , $value + , $key + , $value == $inner->current() + , $key == $inner->key() + ); + return $value === 1 || $value === 4; +} + +$tests = array( + 'instance method' => function() { return array(new A, 'test'); }, + 'static method' => function() { return array('B', 'test'); }, + 'static method (2)' => function() { return 'B::test'; }, + 'function' => function() { return 'test'; }, + 'anonymous function' => function() { return function($value, $key, $inner) { return test($value, $key, $inner); }; }, +); + +foreach($tests as $name => $test) { + + $callback = $test(); + $it = new ArrayIterator(range(1, 5)); + $it = new CallbackFilterIterator($it, $callback); + + echo " = $name =\n"; + + foreach($it as $value) { + echo "=> $value\n"; + } + + // same test, with no reference to callback + + $it = new ArrayIterator(range(1, 5)); + $it = new CallbackFilterIterator($it, $test()); + unset($callback); + + foreach($it as $value) { + echo "=> $value\n"; + } +} +--EXPECT-- += instance method = +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 + = static method = +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 + = static method (2) = +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 + = function = +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 + = anonymous function = +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 1 / 1 / 1 +3 / 2 / 1 / 1 +4 / 3 / 1 / 1 +=> 4 +5 / 4 / 1 / 1 diff --git a/ext/spl/tests/DirectoryIterator_by_reference.phpt b/ext/spl/tests/DirectoryIterator_by_reference.phpt new file mode 100644 index 0000000..06127ec --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_by_reference.phpt @@ -0,0 +1,14 @@ +--TEST-- +DirectoryIterator: test that you cannot use iterator with reference +--CREDITS-- +Havard Eide <nucleuz@gmail.com> +#PHPTestFest2009 Norway 2009-06-09 \o/ +--FILE-- +<?php +$it = new DirectoryIterator(__DIR__); +foreach( $it as &$file ) { + echo $file . "\n"; +} +?> +--EXPECTF-- +Fatal error: An iterator cannot be used with foreach by reference in %s on line %d diff --git a/ext/spl/tests/DirectoryIterator_empty_constructor.phpt b/ext/spl/tests/DirectoryIterator_empty_constructor.phpt new file mode 100644 index 0000000..da5276c --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_empty_constructor.phpt @@ -0,0 +1,15 @@ +--TEST-- +DirectoryIterator: Test empty value to DirectoryIterator constructor +--CREDITS-- +Havard Eide <nucleuz@gmail.com> +#PHPTestFest2009 Norway 2009-06-09 \o/ +--FILE-- +<?php +$it = new DirectoryIterator(""); +?> +--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'Directory name must not be empty.' in %s:%d +Stack trace: +#0 %s(%d): DirectoryIterator->__construct('') +#1 {main} + thrown in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt b/ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt new file mode 100644 index 0000000..ed1f473 --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getBasename_basic_test.phpt @@ -0,0 +1,23 @@ +--TEST-- +DirectoryIterator::getBasename() - Basic Test +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename'); + mkdir($targetDir); + touch($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt'); + $dir = new DirectoryIterator($targetDir.DIRECTORY_SEPARATOR); + while(!$dir->isFile()) { + $dir->next(); + } + echo $dir->getBasename('.txt'); +?> +--CLEAN-- +<?php + $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename'); + unlink($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt'); + rmdir($targetDir); +?> +--EXPECTF-- +getBasename_test diff --git a/ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt b/ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt new file mode 100644 index 0000000..b2df8a5 --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getBasename_pass_array.phpt @@ -0,0 +1,23 @@ +--TEST-- +DirectoryIterator::getBasename() - Pass unexpected array +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename'); + mkdir($targetDir); + touch($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt'); + $dir = new DirectoryIterator($targetDir.DIRECTORY_SEPARATOR); + while(!$dir->isFile()) { + $dir->next(); + } + echo $dir->getBasename(array()); +?> +--CLEAN-- +<?php + $targetDir = __DIR__.DIRECTORY_SEPARATOR.md5('directoryIterator::getbasename'); + unlink($targetDir.DIRECTORY_SEPARATOR.'getBasename_test.txt'); + rmdir($targetDir); +?> +--EXPECTF-- +Warning: DirectoryIterator::getBasename() expects parameter 1 to be %binary_string_optional%, array given in %s on line %d diff --git a/ext/spl/tests/DirectoryIterator_getExtension_basic.phpt b/ext/spl/tests/DirectoryIterator_getExtension_basic.phpt new file mode 100644 index 0000000..7398d4b --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getExtension_basic.phpt @@ -0,0 +1,57 @@ +--TEST-- +SPL: DirectoryIterator::getExtension() basic test +--SKIPIF-- +<?php +if (substr(PHP_OS, 0, 3) == 'WIN') { + die('skip.. only for Unix'); +} +?> +--FILE-- +<?php +$dir = __DIR__ . DIRECTORY_SEPARATOR . md5('DirectoryIterator::getExtension') . DIRECTORY_SEPARATOR; +mkdir($dir); + +$files = array('test.txt', 'test.extension', 'test..', 'test.', 'test'); +foreach ($files as $file) { + touch($dir . $file); +} + +$dit_exts = array(); +$nfo_exts = array(); +$skip = array('.', '..'); + +foreach (new DirectoryIterator($dir) as $file) { + if (in_array($file->getFilename(), $skip)) { + continue; + } + $dit_exts[] = $file->getExtension(); + $nfo_exts[] = pathinfo($file->getFilename(), PATHINFO_EXTENSION); +} +var_dump($dit_exts === $nfo_exts); +sort($dit_exts); +var_dump($dit_exts); +?> +--CLEAN-- +<?php +$dir = __DIR__ . DIRECTORY_SEPARATOR . md5('DirectoryIterator::getExtension') . DIRECTORY_SEPARATOR; +$files = array('test.txt', 'test.extension', 'test..', 'test.', 'test'); +foreach ($files as $file) { + unlink($dir . $file); +} +rmdir($dir); +?> +--EXPECTF-- +bool(true) +array(5) { + [0]=> + string(0) "" + [1]=> + string(0) "" + [2]=> + string(0) "" + [3]=> + string(9) "extension" + [4]=> + string(3) "txt" +} + diff --git a/ext/spl/tests/DirectoryIterator_getGroup_basic.phpt b/ext/spl/tests/DirectoryIterator_getGroup_basic.phpt new file mode 100644 index 0000000..0c75bf4 --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getGroup_basic.phpt @@ -0,0 +1,29 @@ +--TEST-- +SPL: DirectoryIterator test getGroup +--SKIPIF-- +<?php +if (posix_geteuid() == 0) die('SKIP Cannot run test as root.'); +--CREDITS-- +Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20 +--FILE-- +<?php +$dirname = 'DirectoryIterator_getGroup_basic'; +mkdir($dirname); +$dir = new DirectoryIterator($dirname); +$expected = filegroup($dirname); +$actual = $dir->getGroup(); +var_dump($expected == $actual); +?> +--CLEAN-- +<?php +$dirname = 'DirectoryIterator_getGroup_basic'; +rmdir($dirname); +?> +--EXPECTF-- +bool(true) diff --git a/ext/spl/tests/DirectoryIterator_getInode_basic.phpt b/ext/spl/tests/DirectoryIterator_getInode_basic.phpt new file mode 100644 index 0000000..4fd7e8d --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getInode_basic.phpt @@ -0,0 +1,29 @@ +--TEST--
+SPL: Spl Directory Iterator test getInode
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +mkdir('test_dir_ptfi'); +$dirIterator = new DirectoryIterator('test_dir_ptfi'); +var_dump(decoct($dirIterator->getInode())); + +?> +--CLEAN-- +<?php +rmdir('test_dir_ptfi'); +?>
+--EXPECTF--
+string(%d) "%d" diff --git a/ext/spl/tests/DirectoryIterator_getInode_error.phpt b/ext/spl/tests/DirectoryIterator_getInode_error.phpt new file mode 100644 index 0000000..c3641f9 --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getInode_error.phpt @@ -0,0 +1,28 @@ +--TEST--
+SPL: Spl File Info test getInode
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +$fileInfo = new SplFileInfo('not_existing'); +var_dump($fileInfo->getInode()); +?> +
+--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getInode(): stat failed for %s' in %s +Stack trace: +#0 %s: SplFileInfo->getInode() +#1 {main} + thrown in %s diff --git a/ext/spl/tests/DirectoryIterator_getOwner_basic.phpt b/ext/spl/tests/DirectoryIterator_getOwner_basic.phpt new file mode 100644 index 0000000..a1092c2 --- /dev/null +++ b/ext/spl/tests/DirectoryIterator_getOwner_basic.phpt @@ -0,0 +1,29 @@ +--TEST-- +SPL: DirectoryIterator test getOwner +--SKIPIF-- +<?php +if (posix_geteuid() == 0) die('SKIP Cannot run test as root.'); +--CREDITS-- +Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20 +--FILE-- +<?php +$dirname = 'DirectoryIterator_getOwner_basic'; +mkdir($dirname); +$dir = new DirectoryIterator($dirname); +$expected = fileowner($dirname); +$actual = $dir->getOwner(); +var_dump($expected == $actual); +?> +--CLEAN-- +<?php +$dirname = 'DirectoryIterator_getOwner_basic'; +rmdir($dirname); +?> +--EXPECTF-- +bool(true) diff --git a/ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt b/ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt new file mode 100644 index 0000000..f55afd8 --- /dev/null +++ b/ext/spl/tests/RecursiveCallbackFilterIteratorTest.phpt @@ -0,0 +1,138 @@ +--TEST-- +RecursiveCallbackFilterIterator +--FILE-- +<?php + +class A { + function test($value, $key, $inner) { + return test($value, $key, $inner); + } +} + +class B { + static function test($value, $key, $inner) { + return test($value, $key, $inner); + } +} + +function test($value, $key, $inner) { + if ($inner->hasChildren()) { + return true; + } + printf("%s / %s / %d / %d\n" + , print_r($value, true) + , $key + , $value == $inner->current() + , $key == $inner->key() + ); + return $value === 1 || $value === 4; +} + +$tests = array( + 'instance method' => function() { return array(new A, 'test'); }, + 'static method' => function() { return array('B', 'test'); }, + 'static method (2)' => function() { return 'B::test'; }, + 'function' => function() { return 'test'; }, + 'anonymous function' => function() { return function($value, $key, $inner) { return test($value, $key, $inner); }; }, +); + +foreach($tests as $name => $test) { + + $callback = $test(); + $it = new RecursiveArrayIterator(array(1, array(2, 3), array(4, 5))); + $it = new RecursiveCallbackFilterIterator($it, $callback); + $it = new RecursiveIteratorIterator($it); + + echo " = $name =\n"; + + foreach($it as $value) { + echo "=> $value\n"; + } + + // same test, with no reference to callback + + $it = new RecursiveArrayIterator(array(1, array(2, 3), array(4, 5))); + $it = new RecursiveCallbackFilterIterator($it, $test()); + $it = new RecursiveIteratorIterator($it); + unset($callback); + + foreach($it as $value) { + echo "=> $value\n"; + } +} +--EXPECT-- += instance method = +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 + = static method = +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 + = static method (2) = +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 + = function = +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 + = anonymous function = +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 +1 / 0 / 1 / 1 +=> 1 +2 / 0 / 1 / 1 +3 / 1 / 1 / 1 +4 / 0 / 1 / 1 +=> 4 +5 / 1 / 1 / 1 diff --git a/ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt b/ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt new file mode 100644 index 0000000..f0b2b01 --- /dev/null +++ b/ext/spl/tests/RecursiveDirectoryIterator_getSubPath_basic.phpt @@ -0,0 +1,50 @@ +--TEST-- +RecursiveDirectoryIterator::getBasePath() - basic test +--CREDITS-- +Pawel Krynicki <pawel [dot] krynicki [at] xsolve [dot] pl> +#testfest AmsterdamPHP 2012-06-23 +--FILE-- +<?php +$depth0 = "depth0"; +$depth1 = 'depth1'; +$depth2 = 'depth2'; +$targetDir = __DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . $depth1 . DIRECTORY_SEPARATOR . $depth2; +mkdir($targetDir, 0777, true); +touch($targetDir . DIRECTORY_SEPARATOR . 'getSubPath_test.tmp'); +$iterator = new RecursiveDirectoryIterator(__DIR__ . DIRECTORY_SEPARATOR . $depth0); +$it = new RecursiveIteratorIterator($iterator); + +$list = []; +while($it->valid()) { + $list[] = $it->getSubPath(); + $it->next(); +} +asort($list); +foreach ($list as $item) { + echo $item . "\n"; +} +?> +--CLEAN-- +<?php +function rrmdir($dir) { + foreach(glob($dir . '/*') as $file) { + if(is_dir($file)) { + rrmdir($file); + } else { + unlink($file); + } + } + + rmdir($dir); +} + +$targetDir = __DIR__.DIRECTORY_SEPARATOR . "depth0"; +rrmdir($targetDir); +?> + +--EXPECTF-- +depth1 +depth1 +depth1%cdepth2 +depth1%cdepth2 +depth1%cdepth2 diff --git a/ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt b/ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt new file mode 100644 index 0000000..7b12672 --- /dev/null +++ b/ext/spl/tests/RecursiveDirectoryIterator_getSubPathname_basic.phpt @@ -0,0 +1,56 @@ +--TEST-- +RecursiveDirectoryIterator::getBasePathname() - basic test +--CREDITS-- +Pawel Krynicki <pawel [dot] krynicki [at] xsolve [dot] pl> +#testfest AmsterdamPHP 2012-06-23 +--FILE-- +<?php +$depth0 = "depth0"; +$depth1 = "depth1"; +$depth2 = "depth2"; +$targetDir = __DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . $depth1 . DIRECTORY_SEPARATOR . $depth2; +mkdir($targetDir, 0777, true); +touch($targetDir . DIRECTORY_SEPARATOR . 'getSubPathname_test_2.tmp'); +touch(__DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . $depth1 . DIRECTORY_SEPARATOR . 'getSubPathname_test_3.tmp'); +touch(__DIR__ . DIRECTORY_SEPARATOR . $depth0 . DIRECTORY_SEPARATOR . 'getSubPathname_test_1.tmp'); +$iterator = new RecursiveDirectoryIterator(__DIR__ . DIRECTORY_SEPARATOR . $depth0); +$it = new RecursiveIteratorIterator($iterator); + +$list = []; +$it->rewind(); //see https://bugs.php.net/bug.php?id=62914 +while($it->valid()) { + $list[] = $it->getSubPathname(); + $it->next(); +} +asort($list); +foreach ($list as $item) { + echo $item . "\n"; +} +?> +--CLEAN-- +<?php +function rrmdir($dir) { + foreach(glob($dir . '/*') as $file) { + if(is_dir($file)) { + rrmdir($file); + } else { + unlink($file); + } + } + + rmdir($dir); +} + +$targetDir = __DIR__ . DIRECTORY_SEPARATOR . "depth0"; +rrmdir($targetDir); +?> +--EXPECTF-- +. +.. +depth1%c. +depth1%c.. +depth1%cdepth2%c. +depth1%cdepth2%c.. +depth1%cdepth2%cgetSubPathname_test_2.tmp +depth1%cgetSubPathname_test_3.tmp +getSubPathname_test_1.tmp diff --git a/ext/spl/tests/SplArray_fromArray.phpt b/ext/spl/tests/SplArray_fromArray.phpt new file mode 100644 index 0000000..1144f5f --- /dev/null +++ b/ext/spl/tests/SplArray_fromArray.phpt @@ -0,0 +1,17 @@ +--TEST-- +Check that SplArray::fromArray will not allow integer overflows +--CREDITS-- +Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009 +--FILE-- +<?php +$array = array(PHP_INT_MAX => 'foo'); +$splArray = new SplFixedArray(); + +try { + $splArray->fromArray($array); +} catch (Exception $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +integer overflow detected
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt new file mode 100644 index 0000000..36b186d --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_array.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::bottom() - pass in an unexpected array parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->bottom(array()); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt new file mode 100644 index 0000000..94312a0 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_float.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::bottom() - pass in an unexpected float parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->bottom(3.14159); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt new file mode 100644 index 0000000..651f1e4 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_integer.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::bottom() - pass in an unexpected integer parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->bottom(45); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt new file mode 100644 index 0000000..efc6b8a --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_bottom_pass_null.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::bottom() - pass in an unexpected null parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->bottom(null); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::bottom() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_count.phpt b/ext/spl/tests/SplDoublyLinkedList_count.phpt new file mode 100644 index 0000000..72b029c --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_count.phpt @@ -0,0 +1,12 @@ +--TEST-- +Check that SplDoublyLinkedList::count fails if parameter passed in +--CREDITS-- +Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009 +--FILE-- +<?php +$list = new SplDoublyLinkedList(); + +$c = $list->count('foo'); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::count() expects exactly 0 parameters, 1 given in %s on line 4 diff --git a/ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt b/ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt new file mode 100644 index 0000000..36c72de --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_count_param_SplDoublyLinkedList.phpt @@ -0,0 +1,11 @@ +--TEST-- +Create a SplDoublyLinkedList, call count() and pass a SplDoublyLinkedList object as the parameter. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$dll = new SplDoublyLinkedList(2); +$dll->count(new SplDoublyLinkedList(2)); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::count() expects exactly 0 parameters, 1 given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_current.phpt b/ext/spl/tests/SplDoublyLinkedList_current.phpt new file mode 100644 index 0000000..3e13a6b --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_current.phpt @@ -0,0 +1,11 @@ +--TEST-- +SplDoublyLinkedList getIteratorMode +--CREDITS-- +PHPNW Testfest 2009 - Lorna Mitchell +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +var_dump($list->current()); +?> +--EXPECT-- +NULL diff --git a/ext/spl/tests/SplDoublyLinkedList_current_empty.phpt b/ext/spl/tests/SplDoublyLinkedList_current_empty.phpt new file mode 100644 index 0000000..558504b --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_current_empty.phpt @@ -0,0 +1,13 @@ +--TEST-- +Run current() function on an empty SplDoublyLinkedList. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +var_dump($list->current()); + +?> +--EXPECT-- +NULL
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_debug-info.phpt b/ext/spl/tests/SplDoublyLinkedList_debug-info.phpt new file mode 100644 index 0000000..3164b42 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_debug-info.phpt @@ -0,0 +1,29 @@ +--TEST-- +Check that SplDoublyLinkedList returns debug info when print_r is used. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + // Add some items to the list + $dll->push(1); + $dll->push(2); + $dll->push(3); + + // Check the debug info + print_r($dll); +?> +--EXPECT-- +SplDoublyLinkedList Object +( + [flags:SplDoublyLinkedList:private] => 0 + [dllist:SplDoublyLinkedList:private] => Array + ( + [0] => 1 + [1] => 2 + [2] => 3 + ) + +) diff --git a/ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt new file mode 100644 index 0000000..d1bfb46 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplDoublyLinkedList getIteratorMode +--CREDITS-- +PHPNW Testfest 2009 - Lorna Mitchell +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$list->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_KEEP); +echo $list->getIteratorMode(); +?> +--EXPECT-- +0 diff --git a/ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt new file mode 100644 index 0000000..cb43bee --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_getIteratorMode_error.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplDoublyLinkedList getIteratorMode with an unexpected parameter +--CREDITS-- +PHPNW Testfest 2009 - Lorna Mitchell +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$list->getIteratorMode(24); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::getIteratorMode() expects exactly 0 parameters, 1 given in %s on line %d + diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt new file mode 100644 index 0000000..8d7aaf8 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty-with-parameter.phpt @@ -0,0 +1,14 @@ +--TEST-- +Check that SplDoublyLinkedList->isEmpty() returns an error message when a parameter is passed. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + var_dump($dll->isEmpty("test")); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::isEmpty() expects exactly 0 parameters, %d given in %s +NULL
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt new file mode 100644 index 0000000..f129385 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_empty.phpt @@ -0,0 +1,13 @@ +--TEST-- +Check that SplDoublyLinkedList->isEmpty() correctly returns true for an empty list. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + var_dump($dll->isEmpty()); +?> +--EXPECT-- +bool(true) diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt new file mode 100644 index 0000000..6ea9198 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty-with-parameter.phpt @@ -0,0 +1,20 @@ +--TEST-- +Check that SplDoublyLinkedList->isEmpty() returns an error message when a parameter is passed. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + // Add some items to the list + $dll->push(1); + $dll->push(2); + $dll->push(3); + //var_dump($dll); + + var_dump($dll->isEmpty("test")); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::isEmpty() expects exactly 0 parameters, %d given in %s +NULL
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt new file mode 100644 index 0000000..cac1866 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_isEmpty_not-empty.phpt @@ -0,0 +1,19 @@ +--TEST-- +Check that SplDoublyLinkedList->isEmpty() correctly returns true for a non-empty list. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + // Add some items to the list + $dll->push(1); + $dll->push(2); + $dll->push(3); + //var_dump($dll); + + var_dump($dll->isEmpty()); +?> +--EXPECT-- +bool(false) diff --git a/ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt b/ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt new file mode 100644 index 0000000..86a8456 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_lifoMode.phpt @@ -0,0 +1,23 @@ +--TEST-- +Check that SplDoublyLinkedList can traverse backwards +--CREDITS-- +Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009 +--FILE-- +<?php +$list = new SplDoublyLinkedList(); + +$list->push('o'); +$list->push('o'); +$list->push('f'); + +$list->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO); + +$list->rewind(); + +while ($tmp = $list->current()) { + echo $tmp; + $list->next(); +} +?> +--EXPECT-- +foo
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt new file mode 100644 index 0000000..f0e1b8b --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetExists_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL SplDoublyLinkedList offsetExists displays warning and returns null on no parameters +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$a = $list->offsetExists(); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::offsetExists() expects exactly 1 parameter, 0 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt new file mode 100644 index 0000000..0399b49 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetExists_success.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL SplDoublyLinkedList offsetExists returns correct values +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$list = new SplDoublyLinkedList(); + +// Push two values onto the list +$list->push('abc'); +$list->push('def'); + +// Validate that we can see the first value +if($list->offsetExists(0) === true) { + echo "PASS\n"; +} + +// Validate that we can see the second value +if($list->offsetExists(1) === true) { + echo "PASS\n"; +} + +// Check that there is no third value +if($list->offsetExists(2) === false) { + echo "PASS\n"; +} +?> +--EXPECTF-- +PASS +PASS +PASS diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt new file mode 100644 index 0000000..36c47fe --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_empty.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::offsetGet() with no parameter passed. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplDoublyLinkedList( ); + +$get = $array->offsetGet(); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::offsetGet() expects exactly 1 parameter, 0 given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt new file mode 100644 index 0000000..beffe7a --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_missing_param.phpt @@ -0,0 +1,15 @@ +--TEST-- +Tests that the offsetGet() method throws an error when no argument is sent +--CREDITS-- +PHPNW Test Fest 2009 - Rick Ogden +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +$dll->push(1); +$dll->push(2); + +var_dump($dll->offsetGet()); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::offsetGet() expects exactly 1 parameter, 0 given in %s on line %d +NULL diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt new file mode 100644 index 0000000..5df4ab5 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_array.phpt @@ -0,0 +1,18 @@ +--TEST-- +SplDoublyLinkedList::offsetGet() with 1st parameter passed as array. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplDoublyLinkedList( ); + +$get = $array->offsetGet( array( 'fail' ) ); + +?> +--EXPECTF-- +Fatal error: Uncaught exception 'OutOfRangeException' with message 'Offset invalid or out of range' in %s +Stack trace: +#0 %s +#1 {main} + thrown in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt new file mode 100644 index 0000000..fcff762 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetGet_param_string.phpt @@ -0,0 +1,18 @@ +--TEST-- +SplDoublyLinkedList::offsetGet() with 1st parameter passed as string. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplDoublyLinkedList( ); + +$get = $array->offsetGet( 'fail' ); + +?> +--EXPECTF-- +Fatal error: Uncaught exception 'OutOfRangeException' with message 'Offset invalid or out of range' in %s +Stack trace: +#0 %s +#1 {main} + thrown in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt new file mode 100644 index 0000000..2447e79 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetSet_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SplDoublyLinkedList offsetSet throws error on no parameters +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$a = $list->offsetSet(); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::offsetSet() expects exactly 2 parameters, 0 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt new file mode 100644 index 0000000..244dcd5 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetSet_one_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SplDoublyLinkedList offsetSet throws error only one parameter +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$a = $list->offsetSet(2); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::offsetSet() expects exactly 2 parameters, 1 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt new file mode 100644 index 0000000..687fcad --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_greater_than_elements.phpt @@ -0,0 +1,27 @@ +--TEST-- +Doubly Linked List - offsetUnset > number elements + +--CREDITS-- +PHPNW Test Fest 2009 - Mat Griffin + +--FILE-- +<?php +$ll = new SplDoublyLinkedList(); + +$ll->push('1'); +$ll->push('2'); +$ll->push('3'); + +try { + +$ll->offsetUnset($ll->count() + 1); + +var_dump($ll); + +} catch(Exception $e) { +echo $e->getMessage(); +} + +?> +--EXPECT-- +Offset out of range diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt new file mode 100644 index 0000000..d3d1d7d --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_negative-parameter.phpt @@ -0,0 +1,23 @@ +--TEST-- +Check that SplDoublyLinkedList->offsetUnset() returns an error message when the offset is < 0. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + // Add some items to the list + $dll->push(1); + $dll->push(2); + $dll->push(3); + + try { + $dll->offsetUnset(-1); + } + catch (Exception $e) { + echo $e->getMessage() . "\n"; + } +?> +--EXPECT-- +Offset out of range diff --git a/ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt new file mode 100644 index 0000000..aea73b9 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_offsetUnset_parameter-larger-num-elements.phpt @@ -0,0 +1,23 @@ +--TEST-- +Check that SplDoublyLinkedList->offsetUnset() returns an error message when the offset is > elements. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a new Doubly Linked List + $dll = new SplDoublyLinkedList(); + + // Add some items to the list + $dll->push(1); + $dll->push(2); + $dll->push(3); + + try { + $dll->offsetUnset(3); + } + catch (Exception $e) { + echo $e->getMessage() . "\n"; + } +?> +--EXPECT-- +Offset out of range diff --git a/ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt b/ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt new file mode 100644 index 0000000..64f3a48 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_pop_noParams.phpt @@ -0,0 +1,15 @@ +--TEST-- +Checks that the pop() method of DoublyLinkedList does not accept args. +--CREDITS-- +PHPNW Test Fest 2009 - Rick Ogden +--FILE-- +<?php +$ll = new SplDoublyLinkedList(); +$ll->push(1); +$ll->push(2); + +var_dump($ll->pop(1)); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::pop() expects exactly 0 parameters, 1 given in %s on line %d +NULL diff --git a/ext/spl/tests/SplDoublyLinkedList_pop_params.phpt b/ext/spl/tests/SplDoublyLinkedList_pop_params.phpt new file mode 100644 index 0000000..11ab343 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_pop_params.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::offsetGet() with no parameter passed. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplDoublyLinkedList( ); + +$get = $array->pop( 'param' ); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::pop() expects exactly 0 parameters, 1 given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt new file mode 100644 index 0000000..057751c --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_push_missing_parameter.phpt @@ -0,0 +1,13 @@ +--TEST-- +Check that SplDoublyLinkedList::push generate a warning and return NULL with missing param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +var_dump($dll->push()); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::push() expects exactly 1 parameter, 0 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplDoublyLinkedList_serialization.phpt b/ext/spl/tests/SplDoublyLinkedList_serialization.phpt new file mode 100644 index 0000000..7ab7d78 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_serialization.phpt @@ -0,0 +1,67 @@ +--TEST-- +Check Serialization/unserialization +--FILE-- +<?php +$q = new SplQueue(); + +$q->enqueue("a"); +$q->enqueue("b"); + +var_dump($q, $ss = serialize($q), unserialize($ss)); + +$s = new SplStack(); + +$s->push("a"); +$s->push("b"); + +var_dump($s, $ss = serialize($s), unserialize($ss)); +?> +==END== +--EXPECTF-- +object(SplQueue)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(4) + ["dllist":"SplDoublyLinkedList":private]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + } +} +string(42) "C:8:"SplQueue":22:{i:4;:s:1:"a";:s:1:"b";}" +object(SplQueue)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(4) + ["dllist":"SplDoublyLinkedList":private]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + } +} +object(SplStack)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(6) + ["dllist":"SplDoublyLinkedList":private]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + } +} +string(42) "C:8:"SplStack":22:{i:6;:s:1:"a";:s:1:"b";}" +object(SplStack)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(6) + ["dllist":"SplDoublyLinkedList":private]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "b" + } +} +==END== diff --git a/ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt b/ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt new file mode 100644 index 0000000..9bf7a32 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_setIteratorMode_param_SplDoublyLinkedList.phpt @@ -0,0 +1,11 @@ +--TEST-- +Create a SplDoublyLinkedList, call setIteratorMode() and pass a SplDoublyLinkedList object as the parameter. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$dll = new SplDoublyLinkedList(2); +$dll->setIteratorMode(new SplDoublyLinkedList(2)); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::setIteratorMode() expects parameter 1 to be long, object given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt new file mode 100644 index 0000000..2e2632d --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_array.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::top() - pass in an unexpected array +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->top(array()); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt new file mode 100644 index 0000000..0a481b8 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_float.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::top() - pass in an unexpected float parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->top(3.14159); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt new file mode 100644 index 0000000..72bdbab --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_integer.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::top() - pass in an unexpected integer parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->top(45); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt b/ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt new file mode 100644 index 0000000..6a92399 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_top_pass_null.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplDoublyLinkedList::top() - pass in an unexpected null parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php + +$list = new SplDoublyLinkedList(); +$list->push("top"); +$list->top(null); + +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::top() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt b/ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt new file mode 100644 index 0000000..18afa03 --- /dev/null +++ b/ext/spl/tests/SplDoublyLinkedList_unshift_missing_parameter.phpt @@ -0,0 +1,13 @@ +--TEST-- +Check that SplDoublyLinkedList::unshift generate a warning and return NULL with missing param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +var_dump($dll->unshift()); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::unshift() expects exactly 1 parameter, 0 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt new file mode 100644 index 0000000..4dce4db --- /dev/null +++ b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: SplDoublyLinkedList : offsetUnset - first element +--CREDITS-- +PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org> +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$list->push('oh'); +$list->push('hai'); +$list->push('thar'); +$list->offsetUnset(0); +var_dump($list); +?> +--EXPECTF-- +object(SplDoublyLinkedList)#1 (2) { + [%u|b%"flags":%u|b%"SplDoublyLinkedList":private]=> + int(0) + [%u|b%"dllist":%u|b%"SplDoublyLinkedList":private]=> + array(2) { + [0]=> + %string|unicode%(3) "hai" + [1]=> + %string|unicode%(4) "thar" + } +} diff --git a/ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt new file mode 100644 index 0000000..a42e6f9 --- /dev/null +++ b/ext/spl/tests/SplDoublylinkedlist_offsetunset_first002.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: SplDoublyLinkedList : offsetUnset - first element +--CREDITS-- +PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org> +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$list->push('oh'); +$list->push('hai'); +$list->push('thar'); +echo $list->bottom() . "\n"; +$list->offsetUnset(0); +echo $list->bottom() . "\n"; +?> +--EXPECT-- +oh +hai diff --git a/ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt b/ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt new file mode 100644 index 0000000..0f5dac1 --- /dev/null +++ b/ext/spl/tests/SplDoublylinkedlist_offsetunset_last.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: SplDoublyLinkedList : offsetUnset - last element +--CREDITS-- +PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org> +--FILE-- +<?php +$list = new SplDoublyLinkedList(); +$list->push('oh'); +$list->push('hai'); +$list->push('thar'); +$list->offsetUnset(2); +var_dump($list); +?> +--EXPECTF-- +object(SplDoublyLinkedList)#1 (2) { + [%u|b%"flags":%u|b%"SplDoublyLinkedList":private]=> + int(0) + [%u|b%"dllist":%u|b%"SplDoublyLinkedList":private]=> + array(2) { + [0]=> + %string|unicode%(2) "oh" + [1]=> + %string|unicode%(3) "hai" + } +} diff --git a/ext/spl/tests/SplFileInfo_001.phpt b/ext/spl/tests/SplFileInfo_001.phpt new file mode 100644 index 0000000..72060f0 --- /dev/null +++ b/ext/spl/tests/SplFileInfo_001.phpt @@ -0,0 +1,11 @@ +--TEST-- +Testing SplFileInfo calling the constructor twice +--FILE-- +<?php +$x = new splfileinfo(1); +$x->__construct(1); + +echo "done!\n"; +?> +--EXPECT-- +done! diff --git a/ext/spl/tests/SplFileInfo_getExtension_basic.phpt b/ext/spl/tests/SplFileInfo_getExtension_basic.phpt new file mode 100644 index 0000000..b47b6bb --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getExtension_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: SplFileInfo::getExtension() basic test +--FILE-- +<?php +$file = md5('SplFileInfo::getExtension'); +$exts = array('.txt', '.extension', '..', '.', ''); +foreach ($exts as $ext) { + touch($file . $ext); + $info = new SplFileInfo($file . $ext); + var_dump($info->getExtension(), pathinfo($file . $ext, PATHINFO_EXTENSION)); +} +?> +--CLEAN-- +<?php +$file = md5('SplFileInfo::getExtension'); +$exts = array('.txt', '.extension', '..', '.', ''); +foreach ($exts as $ext) { + unlink($file . $ext); +} +?> +--EXPECTF-- +string(3) "txt" +string(3) "txt" +string(9) "extension" +string(9) "extension" +string(0) "" +string(0) "" +string(0) "" +string(0) "" +string(0) "" +string(0) "" diff --git a/ext/spl/tests/SplFileInfo_getGroup_basic.phpt b/ext/spl/tests/SplFileInfo_getGroup_basic.phpt new file mode 100644 index 0000000..d279935 --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getGroup_basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: SplFileInfo test getGroup +--CREDITS-- +Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20 +--FILE-- +<?php +$filename = __DIR__ . "/SplFileInfo_getGroup_basic"; +touch($filename); +$fileInfo = new SplFileInfo($filename); +$expected = filegroup($filename); +$actual = $fileInfo->getGroup(); +var_dump($expected == $actual); +?> +--CLEAN-- +<?php +$filename = __DIR__ . "/SplFileInfo_getGroup_basic"; +unlink($filename); +?> +--EXPECTF-- +bool(true) diff --git a/ext/spl/tests/SplFileInfo_getGroup_error.phpt b/ext/spl/tests/SplFileInfo_getGroup_error.phpt new file mode 100644 index 0000000..f0db00d --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getGroup_error.phpt @@ -0,0 +1,28 @@ +--TEST--
+SPL: Spl File Info test getGroup
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +$fileInfo = new SplFileInfo('not_existing'); +var_dump($fileInfo->getGroup()); +?> +
+--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getGroup(): stat failed for not_existing' in %s +Stack trace: +#0 %s: SplFileInfo->getGroup() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/SplFileInfo_getInode_basic.phpt b/ext/spl/tests/SplFileInfo_getInode_basic.phpt new file mode 100644 index 0000000..902cbb3 --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getInode_basic.phpt @@ -0,0 +1,30 @@ +--TEST--
+SPL: Spl File Info test getInode
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +touch ('test_file_ptfi'); +$fileInfo = new SplFileInfo('test_file_ptfi'); +$result = shell_exec('ls -i test_file_ptfi'); +var_dump($fileInfo->getInode() == $result); + +?> +--CLEAN-- +<?php +unlink('test_file_ptfi'); +?>
+--EXPECTF--
+bool(true) diff --git a/ext/spl/tests/SplFileInfo_getInode_error.phpt b/ext/spl/tests/SplFileInfo_getInode_error.phpt new file mode 100644 index 0000000..bf8efae --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getInode_error.phpt @@ -0,0 +1,28 @@ +--TEST--
+SPL: Spl File Info test getPerms
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +$fileInfo = new SplFileInfo('not_existing'); +var_dump($fileInfo->getInode()); +?> +
+--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getInode(): stat failed for not_existing' in %s +Stack trace: +#0 %s: SplFileInfo->getInode() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/SplFileInfo_getOwner_basic.phpt b/ext/spl/tests/SplFileInfo_getOwner_basic.phpt new file mode 100644 index 0000000..3df8e48 --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getOwner_basic.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: SplFileInfo test getOwner +--CREDITS-- +Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20 +--FILE-- +<?php +$filename = __DIR__ . "/SplFileInfo_getOwner_basic"; +touch($filename); +$fileInfo = new SplFileInfo($filename); +$expected = fileowner($filename); +$actual = $fileInfo->getOwner(); +var_dump($expected == $actual); +?> +--CLEAN-- +<?php +$filename = __DIR__ . "/SplFileInfo_getOwner_basic"; +unlink($filename); +?> +--EXPECTF-- +bool(true) diff --git a/ext/spl/tests/SplFileInfo_getOwner_error.phpt b/ext/spl/tests/SplFileInfo_getOwner_error.phpt new file mode 100644 index 0000000..d5d4678 --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getOwner_error.phpt @@ -0,0 +1,28 @@ +--TEST--
+SPL: Spl File Info test getOwner
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +$fileInfo = new SplFileInfo('not_existing'); +var_dump($fileInfo->getOwner()); +?> +
+--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getOwner(): stat failed for not_existing' in %s +Stack trace: +#0 %s: SplFileInfo->getOwner() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/SplFileInfo_getPerms_basic.phpt b/ext/spl/tests/SplFileInfo_getPerms_basic.phpt new file mode 100644 index 0000000..e9b7bea --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getPerms_basic.phpt @@ -0,0 +1,30 @@ +--TEST--
+SPL: Spl File Info test getPerms
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +touch ('test_file_ptfi'); +chmod('test_file_ptfi', 0557); +$fileInfo = new SplFileInfo('test_file_ptfi'); +var_dump($fileInfo->getPerms() == 0100557); + +?> +--CLEAN-- +<?php +unlink('test_file_ptfi'); +?>
+--EXPECTF--
+bool(true) diff --git a/ext/spl/tests/SplFileInfo_getPerms_error.phpt b/ext/spl/tests/SplFileInfo_getPerms_error.phpt new file mode 100644 index 0000000..8e05cdf --- /dev/null +++ b/ext/spl/tests/SplFileInfo_getPerms_error.phpt @@ -0,0 +1,28 @@ +--TEST--
+SPL: Spl File Info test getPerms
+--CREDITS--
+Cesare D'Amico <cesare.damico@gruppovolta.it> +Andrea Giorgini <agiorg@gmail.com> +Filippo De Santis <fd@ideato.it> +Daniel Londero <daniel.londero@gmail.com> +Francesco Trucchia <ft@ideato.it> +Jacopo Romei <jacopo@sviluppoagile.it> +#Test Fest Cesena (Italy) on 2009-06-20
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms");
+?>
+--FILE--
+<?php
+ +//file +$fileInfo = new SplFileInfo('not_existing'); +var_dump($fileInfo->getPerms() == 0100557); +?> +
+--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileInfo::getPerms(): stat failed for %s' in %s +Stack trace: +#0 %s: SplFileInfo->getPerms() +#1 {main} + thrown in %s diff --git a/ext/spl/tests/SplFileObject_current_basic.phpt b/ext/spl/tests/SplFileObject_current_basic.phpt new file mode 100644 index 0000000..d3f4802 --- /dev/null +++ b/ext/spl/tests/SplFileObject_current_basic.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: SplFileObject::current basic +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +echo $s->current(); + +?> +--EXPECT-- +<?php diff --git a/ext/spl/tests/SplFileObject_current_error001.phpt b/ext/spl/tests/SplFileObject_current_error001.phpt new file mode 100644 index 0000000..23c1266 --- /dev/null +++ b/ext/spl/tests/SplFileObject_current_error001.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplFileObject::current variation error +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +$s->seek(2); + +echo $s->current('foo'); +?> +--EXPECTF-- +Warning: SplFileObject::current() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFileObject_current_variation001.phpt b/ext/spl/tests/SplFileObject_current_variation001.phpt new file mode 100644 index 0000000..0cc588a --- /dev/null +++ b/ext/spl/tests/SplFileObject_current_variation001.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: SplFileObject::current variation +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +$s->seek(2); + +echo $s->current(); +echo $s->current(); +?> +--EXPECT-- +//line 3 +//line 3 diff --git a/ext/spl/tests/SplFileObject_fflush_basic_001.phpt b/ext/spl/tests/SplFileObject_fflush_basic_001.phpt new file mode 100644 index 0000000..2d8a9c8 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fflush_basic_001.phpt @@ -0,0 +1,38 @@ +--TEST-- +SplFileObject::fflush function - basic test +--FILE-- +<?php +/* + * test a successful flush +*/ +$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv'); +var_dump($obj->fflush()); + +/* + * test a unsuccessful flush +*/ +//create a basic stream class +class VariableStream { + var $position; + var $varname; + + function stream_open($path, $mode, $options, &$opened_path) + { + return true; + } + + function url_stat() { + } +} +stream_wrapper_register("SPLtest", "VariableStream"); +$ftruncate_test = ""; +//end creating stream + +//open an SplFileObject using the above test stream +$obj = New SplFileObject("SPLtest://ftruncate_test"); +var_dump($obj->fflush()); + +?> +--EXPECTF-- +bool(true) +bool(false) diff --git a/ext/spl/tests/SplFileObject_fgetcsv_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_basic.phpt new file mode 100644 index 0000000..abfe5f2 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +SplFileObject::fgetcsv default path +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fputcsv($fp, array( + 'field1', + 'field2', + 'field3', + 5 +)); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv()); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +array(4) { + [0]=> + string(6) "field1" + [1]=> + string(6) "field2" + [2]=> + string(6) "field3" + [3]=> + string(1) "5" +} diff --git a/ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt new file mode 100644 index 0000000..32705f0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +SplFileObject::fgetcsv with alternative delimeter +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fputcsv($fp, array( + 'field1', + 'field2', + 'field3', + 5 +), '|'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv('|')); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +array(4) { + [0]=> + string(6) "field1" + [1]=> + string(6) "field2" + [2]=> + string(6) "field3" + [3]=> + string(1) "5" +} diff --git a/ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt new file mode 100644 index 0000000..942c761 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_delimiter_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +SplFileObject::fgetcsv with alternative delimeter +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fputcsv($fp, array( + 'field1', + 'field2', + 'field3', + 5 +), '|'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv('invalid')); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::fgetcsv(): delimiter must be a character in %s on line %d +bool(false) diff --git a/ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt new file mode 100644 index 0000000..ee24972 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +SplFileObject::fgetcsv with alternative delimeter +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fputcsv($fp, array( + 'field1', + 'field2', + 'field3', + 5 +), ',', '"'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv(',', '"')); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +array(4) { + [0]=> + string(6) "field1" + [1]=> + string(6) "field2" + [2]=> + string(6) "field3" + [3]=> + string(1) "5" +} diff --git a/ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt new file mode 100644 index 0000000..5430e53 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_enclosure_error.phpt @@ -0,0 +1,23 @@ +--TEST-- +SplFileObject::fgetcsv with alternative delimeter +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fputcsv($fp, array( + 'field1', + 'field2', + 'field3', + 5 +), ',', '"'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv(',', 'invalid')); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::fgetcsv(): enclosure must be a character in %s on line %d +bool(false) diff --git a/ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt b/ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt new file mode 100644 index 0000000..96c0290 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_escape_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +SplFileObject::fgetcsv with alternative delimeter +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fwrite($fp, '"aaa","b""bb","ccc"'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv(',', '"', '"')); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +array(3) { + [0]=> + string(3) "aaa" + [1]=> + string(4) "b"bb" + [2]=> + string(3) "ccc" +} diff --git a/ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt b/ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt new file mode 100644 index 0000000..c628ac0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_escape_default.phpt @@ -0,0 +1,24 @@ +--TEST-- +SplFileObject::fgetcsv with default escape character +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fwrite($fp, '"aa\"","bb","\"c"'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv()); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +array(3) { + [0]=> + string(4) "aa\"" + [1]=> + string(2) "bb" + [2]=> + string(3) "\"c" +} diff --git a/ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt b/ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt new file mode 100644 index 0000000..a570318 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fgetcsv_escape_error.phpt @@ -0,0 +1,18 @@ +--TEST-- +SplFileObject::fgetcsv with alternative delimeter +--FILE-- +<?php +$fp = fopen('SplFileObject__fgetcsv.csv', 'w+'); +fwrite($fp, '"aaa","b""bb","ccc"'); +fclose($fp); + +$fo = new SplFileObject('SplFileObject__fgetcsv.csv'); +var_dump($fo->fgetcsv(',', '"', 'invalid')); +?> +--CLEAN-- +<?php +unlink('SplFileObject__fgetcsv.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::fgetcsv(): escape must be a character in %s on line %d +bool(false) diff --git a/ext/spl/tests/SplFileObject_fpassthru_basic.phpt b/ext/spl/tests/SplFileObject_fpassthru_basic.phpt new file mode 100644 index 0000000..55b7481 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fpassthru_basic.phpt @@ -0,0 +1,13 @@ +--TEST-- +SplFileObject::fpassthru function - basic functionality test +--FILE-- +<?php +$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv'); +$obj->fpassthru(); +?> +--EXPECT-- +first,second,third +1,2,3 +4,5,6 +7,8,9 +0,0,0 diff --git a/ext/spl/tests/SplFileObject_fputcsv.phpt b/ext/spl/tests/SplFileObject_fputcsv.phpt new file mode 100644 index 0000000..66fdbfd --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv.phpt @@ -0,0 +1,106 @@ +--TEST-- +SplFileObject::fputcsv(): functionality tests +--FILE-- +<?php +$file = __DIR__ . '/SplFileObject_fputcsv.csv'; +$fo = new SplFileObject($file, 'w'); + +$list = array ( + 0 => 'aaa,bbb', + 1 => 'aaa,"bbb"', + 2 => '"aaa","bbb"', + 3 => 'aaa,bbb', + 4 => '"aaa",bbb', + 5 => '"aaa", "bbb"', + 6 => ',', + 7 => 'aaa,', + 8 => ',"aaa"', + 9 => '"",""', + 10 => '"""""",', + 11 => '""""",aaa', + 12 => 'aaa,bbb ', + 13 => 'aaa,"bbb "', + 14 => 'aaa"aaa","bbb"bbb', + 15 => 'aaa"aaa""",bbb', + 16 => 'aaa,"\\"bbb,ccc', + 17 => 'aaa"\\"a","bbb"', + 18 => '"\\"","aaa"', + 19 => '"\\""",aaa', +); + +foreach ($list as $v) { + $fo->fputcsv(explode(',', $v)); +} +unset($fo); + +$res = file($file); +foreach($res as &$val) +{ + $val = substr($val, 0, -1); +} +echo '$list = ';var_export($res);echo ";\n"; + +$fp = fopen($file, "r"); +$res = array(); +while($l=fgetcsv($fp)) +{ + $res[] = join(',',$l); +} +fclose($fp); + +echo '$list = ';var_export($res);echo ";\n"; + +?> +===DONE=== +<?php exit(0); ?> +--CLEAN-- +<?php +$file = __DIR__ . '/SplFileObject_fputcsv.csv'; +unlink($file); +?> +--EXPECT-- +$list = array ( + 0 => 'aaa,bbb', + 1 => 'aaa,"""bbb"""', + 2 => '"""aaa""","""bbb"""', + 3 => 'aaa,bbb', + 4 => '"""aaa""",bbb', + 5 => '"""aaa"""," ""bbb"""', + 6 => ',', + 7 => 'aaa,', + 8 => ',"""aaa"""', + 9 => '"""""",""""""', + 10 => '"""""""""""""",', + 11 => '"""""""""""",aaa', + 12 => 'aaa,"bbb "', + 13 => 'aaa,"""bbb """', + 14 => '"aaa""aaa""","""bbb""bbb"', + 15 => '"aaa""aaa""""""",bbb', + 16 => 'aaa,"""\\"bbb",ccc', + 17 => '"aaa""\\"a""","""bbb"""', + 18 => '"""\\"""","""aaa"""', + 19 => '"""\\"""""",aaa', +); +$list = array ( + 0 => 'aaa,bbb', + 1 => 'aaa,"bbb"', + 2 => '"aaa","bbb"', + 3 => 'aaa,bbb', + 4 => '"aaa",bbb', + 5 => '"aaa", "bbb"', + 6 => ',', + 7 => 'aaa,', + 8 => ',"aaa"', + 9 => '"",""', + 10 => '"""""",', + 11 => '""""",aaa', + 12 => 'aaa,bbb ', + 13 => 'aaa,"bbb "', + 14 => 'aaa"aaa","bbb"bbb', + 15 => 'aaa"aaa""",bbb', + 16 => 'aaa,"\\"bbb,ccc', + 17 => 'aaa"\\"a","bbb"', + 18 => '"\\"","aaa"', + 19 => '"\\""",aaa', +); +===DONE=== diff --git a/ext/spl/tests/SplFileObject_fputcsv_002.phpt b/ext/spl/tests/SplFileObject_fputcsv_002.phpt new file mode 100644 index 0000000..db17493 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_002.phpt @@ -0,0 +1,42 @@ +--TEST-- +SplFileObject::fputcsv(): Checking data after calling the function +--FILE-- +<?php +$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w'); + +$data = array(1, 2, 'foo', 'haha', array(4, 5, 6), 1.3, null); + +$fo->fputcsv($data); + +var_dump($data); +?> +--CLEAN-- +<?php +$file = __DIR__ . '/SplFileObject_fputcsv.csv'; +unlink($file); +?> +--EXPECTF-- +Notice: Array to string conversion in %s on line %d +array(7) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + string(3) "foo" + [3]=> + string(4) "haha" + [4]=> + array(3) { + [0]=> + int(4) + [1]=> + int(5) + [2]=> + int(6) + } + [5]=> + float(1.3) + [6]=> + NULL +} diff --git a/ext/spl/tests/SplFileObject_fputcsv_error.phpt b/ext/spl/tests/SplFileObject_fputcsv_error.phpt new file mode 100644 index 0000000..8368e42 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_error.phpt @@ -0,0 +1,35 @@ +--TEST-- +SplFileObject::fputcsv(): error conditions +--FILE-- +<?php +$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w'); + +echo "*** Testing error conditions ***\n"; +// zero argument +echo "-- Testing fputcsv() with zero argument --\n"; +var_dump( $fo->fputcsv() ); + +// more than expected no. of args +echo "-- Testing fputcsv() with more than expected number of arguments --\n"; +$fields = array("fld1", "fld2"); +$delim = ";"; +$enclosure ="\""; +var_dump( $fo->fputcsv($fields, $delim, $enclosure, $fo) ); + +echo "Done\n"; +--CLEAN-- +<?php +$file = __DIR__ . '/SplFileObject_fputcsv.csv'; +unlink($file); +?> +--EXPECTF-- +*** Testing error conditions *** +-- Testing fputcsv() with zero argument -- + +Warning: SplFileObject::fputcsv() expects at least 1 parameter, 0 given in %s on line %d +NULL +-- Testing fputcsv() with more than expected number of arguments -- + +Warning: SplFileObject::fputcsv() expects at most 3 parameters, 4 given in %s on line %d +NULL +Done diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation1.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation1.phpt new file mode 100644 index 0000000..6780b24 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation1.phpt @@ -0,0 +1,826 @@ +--TEST-- +Test fputcsv() : usage variations - with all parameters specified +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when all its parameters are provided */ + +echo "*** Testing fputcsv() : with all parameters specified ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water','fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation1.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + + var_dump( $fo->fputcsv($csv_field, $delimiter, $enclosure) ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with all parameters specified *** + +-- file opened in r+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in a+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in w+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in x+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in r+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in r+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in r+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in a+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in a+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in a+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in w+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in w+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in w+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in x+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in x+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in x+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in r+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in r+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in r+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in a+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in a+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in a+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in w+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in w+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in w+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in x+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in x+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in x+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation10.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation10.phpt new file mode 100644 index 0000000..08a2461 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation10.phpt @@ -0,0 +1,327 @@ +--TEST-- +SplFileObject::fputcsv(): Usage variations -- with line without any CSV fields +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when the field has no CSV format */ + +echo "*** Testing fputcsv() : with no CSV format in the field ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ + +$fields = array( array('water_fruit\n'), + array("water_fruit\n"), + array("") + ); + +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation10.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($fields as $field) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $csv_field = $field; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field) ); + + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with no CSV format in the field *** + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) ""water_fruit\n" +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) ""water_fruit\n" +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) ""water_fruit\n" +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) ""water_fruit\n" +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) ""water_fruit\n" +" + +-- file opened in r+ -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in r+b -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in r+t -- +int(15) +int(15) +bool(false) +string(%d) ""water_fruit +" +" + +-- file opened in a+ -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in a+b -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in a+t -- +int(15) +int(15) +bool(false) +string(%d) ""water_fruit +" +" + +-- file opened in w+ -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in w+b -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in w+t -- +int(15) +int(15) +bool(false) +string(%d) ""water_fruit +" +" + +-- file opened in x+ -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in x+b -- +int(15) +int(15) +bool(false) +string(15) ""water_fruit +" +" + +-- file opened in x+t -- +int(15) +int(15) +bool(false) +string(%d) ""water_fruit +" +" + +-- file opened in r+ -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in r+b -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in r+t -- +int(1) +int(1) +bool(false) +string(%d) " +" + +-- file opened in a+ -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in a+b -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in a+t -- +int(1) +int(1) +bool(false) +string(%d) " +" + +-- file opened in w+ -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in w+b -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in w+t -- +int(1) +int(1) +bool(false) +string(%d) " +" + +-- file opened in x+ -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in x+b -- +int(1) +int(1) +bool(false) +string(1) " +" + +-- file opened in x+t -- +int(1) +int(1) +bool(false) +string(%d) " +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation11.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation11.phpt new file mode 100644 index 0000000..c85dd0a --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation11.phpt @@ -0,0 +1,826 @@ +--TEST-- +SplFileObject::fputcsv(): Usage variations -- with default enclosure value +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when default enclosure value is provided */ + +echo "*** Testing fputcsv() : with default enclosure value ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water,fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation11.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field, $delimiter) ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with default enclosure value *** + +-- file opened in r+ -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in r+b -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in r+t -- +int(14) +int(14) +bool(false) +string(%d) ""water,fruit" +" + +-- file opened in a+ -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in a+b -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in a+t -- +int(14) +int(14) +bool(false) +string(%d) ""water,fruit" +" + +-- file opened in w+ -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in w+b -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in w+t -- +int(14) +int(14) +bool(false) +string(%d) ""water,fruit" +" + +-- file opened in x+ -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in x+b -- +int(14) +int(14) +bool(false) +string(14) ""water,fruit" +" + +-- file opened in x+t -- +int(14) +int(14) +bool(false) +string(%d) ""water,fruit" +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) ""&water&:&fruit&" +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) ""&water&:&fruit&" +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) ""&water&:&fruit&" +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) ""&water&:&fruit&" +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) ""&water&:&fruit&" +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) ""=water===fruit=" +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) ""=water===fruit=" +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) ""=water===fruit=" +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) ""=water===fruit=" +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) ""=water===fruit=" +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) ""-water--fruit-air" +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) ""-water--fruit-air" +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) ""-water--fruit-air" +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) ""-water--fruit-air" +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) ""-water--fruit-air" +" + +-- file opened in r+ -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in r+b -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in r+t -- +int(24) +int(24) +bool(false) +string(%d) ""-water---fruit---air-" +" + +-- file opened in a+ -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in a+b -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in a+t -- +int(24) +int(24) +bool(false) +string(%d) ""-water---fruit---air-" +" + +-- file opened in w+ -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in w+b -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in w+t -- +int(24) +int(24) +bool(false) +string(%d) ""-water---fruit---air-" +" + +-- file opened in x+ -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in x+b -- +int(24) +int(24) +bool(false) +string(24) ""-water---fruit---air-" +" + +-- file opened in x+t -- +int(24) +int(24) +bool(false) +string(%d) ""-water---fruit---air-" +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation12.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation12.phpt new file mode 100644 index 0000000..8bb47d3 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation12.phpt @@ -0,0 +1,827 @@ +--TEST-- +SplFileObject::fputcsv(): Usage variations -- with default enclosure and different delimiter +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when default enclosure value and delimiter value + other than that in the field is provided */ + +echo "*** Testing fputcsv() : with default enclosure and different delimiter value ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water,fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation12.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field, '+') ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with default enclosure and different delimiter value *** + +-- file opened in r+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in a+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in w+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in x+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation13.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation13.phpt new file mode 100644 index 0000000..b7c2a63 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation13.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test fputcsv() : usage variations - with default enclosure & delimiter of two chars +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when default enclosure value and delimiter + of two chars is provided */ + +echo "*** Testing fputcsv() : with default enclosure & delimiter of two chars ***\n"; + +$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w'); + +var_dump($fo->fputcsv(array('water', 'fruit'), ',,', '"')); + +unset($fo); + +echo "Done\n"; +?> +--CLEAN-- +<?php +$file = __DIR__ . '/SplFileObject_fputcsv.csv'; +unlink($file); +?> +--EXPECTF-- +*** Testing fputcsv() : with default enclosure & delimiter of two chars *** + +Warning: SplFileObject::fputcsv(): delimiter must be a character in %s on line %d +bool(false) +Done diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation14.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation14.phpt new file mode 100644 index 0000000..f8cda0e --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation14.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test fputcsv() : usage variations - with enclosure & delimiter of two chars +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when default enclosure value and delimiter + of two chars is provided and file is opened in read only mode */ + +echo "*** Testing fputcsv() : with enclosure & delimiter of two chars and file opened in read mode ***\n"; + +$fo = new SplFileObject(__DIR__ . '/SplFileObject_fputcsv.csv', 'w'); + +var_dump($fo->fputcsv(array('water', 'fruit'), ',,', '""')); + +unset($fo); + +echo "Done\n"; +?> +--CLEAN-- +<?php +$file = __DIR__ . '/SplFileObject_fputcsv.csv'; +unlink($file); +?> +--EXPECTF-- +*** Testing fputcsv() : with enclosure & delimiter of two chars and file opened in read mode *** + +Warning: SplFileObject::fputcsv(): enclosure must be a character in %s on line %d +bool(false) +Done diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation5.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation5.phpt new file mode 100644 index 0000000..9c4c01f --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation5.phpt @@ -0,0 +1,826 @@ +--TEST-- +Test fputcsv() : usage variations - with default arguments value +--FILE-- +<?php + +/* Testing fputcsv() to write to a file when default arguments values are considered */ + +echo "*** Testing fputcsv() : with default arguments value ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water','fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation5.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field) ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with default arguments value *** + +-- file opened in r+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in a+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in w+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in x+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) ""^water^ ^fruit^" +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) ""^water^ ^fruit^" +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) ""&""""""""&:&""&:,:"":&,&:,,,," +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) ""&""""""""&:&""&:,:"":&,&:,,,," +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation6.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation6.phpt new file mode 100644 index 0000000..6cbb880 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation6.phpt @@ -0,0 +1,829 @@ +--TEST-- +Test fputcsv() : usage variations - with different delimiter and enclosure +--FILE-- +<?php + +/* + Testing fputcsv() to write to a file when delimiter are different from those + present in the field to be written to the file + */ + +echo "*** Testing fputcsv() : with different delimiter and enclosure ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water,fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation6.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field, '+', '%') ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with different delimiter and enclosure *** + +-- file opened in r+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in r+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in a+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in a+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in w+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in w+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in x+ -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+b -- +int(12) +int(12) +bool(false) +string(12) "water,fruit +" + +-- file opened in x+t -- +int(12) +int(12) +bool(false) +string(%d) "water,fruit +" + +-- file opened in r+ -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in r+b -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in r+t -- +int(15) +int(15) +bool(false) +string(%d) ""water","fruit +" + +-- file opened in a+ -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in a+b -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in a+t -- +int(15) +int(15) +bool(false) +string(%d) ""water","fruit +" + +-- file opened in w+ -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in w+b -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in w+t -- +int(15) +int(15) +bool(false) +string(%d) ""water","fruit +" + +-- file opened in x+ -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in x+b -- +int(15) +int(15) +bool(false) +string(15) ""water","fruit +" + +-- file opened in x+t -- +int(15) +int(15) +bool(false) +string(%d) ""water","fruit +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) ""water","fruit" +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) ""water","fruit" +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) ""water","fruit" +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) ""water","fruit" +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) ""water","fruit" +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "%^water^ ^fruit^% +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "%^water^ ^fruit^% +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "%^water^ ^fruit^% +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "%^water^ ^fruit^% +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "%^water^ ^fruit^% +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) "&water&:&fruit& +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) "&water&:&fruit& +" + +-- file opened in r+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in r+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in r+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in a+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in a+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in a+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in w+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in w+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in w+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in x+ -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in x+b -- +int(16) +int(16) +bool(false) +string(16) "=water===fruit= +" + +-- file opened in x+t -- +int(16) +int(16) +bool(false) +string(%d) "=water===fruit= +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "-water--fruit-air +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "-water--fruit-air +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "-water---fruit---air- +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "-water---fruit---air- +" + +-- file opened in r+ -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in r+b -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in r+t -- +int(24) +int(24) +bool(false) +string(%d) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in a+ -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in a+b -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in a+t -- +int(24) +int(24) +bool(false) +string(%d) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in w+ -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in w+b -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in w+t -- +int(24) +int(24) +bool(false) +string(%d) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in x+ -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in x+b -- +int(24) +int(24) +bool(false) +string(24) "&""""&:&"&:,:":&,&:,,,, +" + +-- file opened in x+t -- +int(24) +int(24) +bool(false) +string(%d) "&""""&:&"&:,:":&,&:,,,, +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation7.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation7.phpt new file mode 100644 index 0000000..ceb438a --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation7.phpt @@ -0,0 +1,829 @@ +--TEST-- +Test fputcsv() : usage variations - with different delimiter and same enclosure +--FILE-- +<?php + +/* + Testing fputcsv() to write to a file when enclosure is same but delimiter is different from those + present in the field to be written to the file + */ + +echo "*** Testing fputcsv() : with different delimiter and same enclosure ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water','fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation7.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field, '+', $enclosure) ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with different delimiter and same enclosure *** + +-- file opened in r+ -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in r+b -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in r+t -- +int(12) +int(12) +bool(false) +string(%d) "water+fruit +" + +-- file opened in a+ -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in a+b -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in a+t -- +int(12) +int(12) +bool(false) +string(%d) "water+fruit +" + +-- file opened in w+ -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in w+b -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in w+t -- +int(12) +int(12) +bool(false) +string(%d) "water+fruit +" + +-- file opened in x+ -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in x+b -- +int(12) +int(12) +bool(false) +string(12) "water+fruit +" + +-- file opened in x+t -- +int(12) +int(12) +bool(false) +string(%d) "water+fruit +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) """"water"",""fruit" +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) """"water"",""fruit" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) """"water"",""fruit""" +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) """"water"",""fruit""" +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "^^^water^^ ^^fruit^^^ +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "^^^water^^ ^^fruit^^^ +" + +-- file opened in r+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in r+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in r+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in a+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in a+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in a+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in w+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in w+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in w+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in x+ -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in x+b -- +int(22) +int(22) +bool(false) +string(22) "&&&water&&:&&fruit&&& +" + +-- file opened in x+t -- +int(22) +int(22) +bool(false) +string(%d) "&&&water&&:&&fruit&&& +" + +-- file opened in r+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in r+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in r+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in a+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in a+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in a+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in w+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in w+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in w+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in x+ -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in x+b -- +int(23) +int(23) +bool(false) +string(23) "===water======fruit=== +" + +-- file opened in x+t -- +int(23) +int(23) +bool(false) +string(%d) "===water======fruit=== +" + +-- file opened in r+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in r+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in r+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in a+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in a+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in a+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in w+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in w+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in w+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in x+ -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in x+b -- +int(24) +int(24) +bool(false) +string(24) "---water----fruit--air- +" + +-- file opened in x+t -- +int(24) +int(24) +bool(false) +string(%d) "---water----fruit--air- +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) "---water------fruit------air--- +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) "---water------fruit------air--- +" + +-- file opened in r+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in r+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in r+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in a+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in a+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in a+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in w+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in w+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in w+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in x+ -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in x+b -- +int(32) +int(32) +bool(false) +string(32) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" + +-- file opened in x+t -- +int(32) +int(32) +bool(false) +string(%d) "&&&""""&&:&&"&&:,:":&&,&&:,,,,& +" +Done + diff --git a/ext/spl/tests/SplFileObject_fputcsv_variation8.phpt b/ext/spl/tests/SplFileObject_fputcsv_variation8.phpt new file mode 100644 index 0000000..f1a8cbf --- /dev/null +++ b/ext/spl/tests/SplFileObject_fputcsv_variation8.phpt @@ -0,0 +1,829 @@ +--TEST-- +Test fputcsv() : usage variations - with same delimiter and different enclosure +--FILE-- +<?php + +/* + Testing fputcsv() to write to a file when delimiter is same but enclosure is different from those + present in the field to be written to the file + */ + +echo "*** Testing fputcsv() : with same delimiter and different enclosure ***\n"; + +/* the array is with three elements in it. Each element should be read as + 1st element is delimiter, 2nd element is enclosure + and 3rd element is csv fields +*/ +$csv_lists = array ( + array(',', '"', array('water,fruit') ), + array(',', '"', array('"water","fruit') ), + array(',', '"', array('"water","fruit"') ), + array(' ', '^', array('^water^ ^fruit^')), + array(':', '&', array('&water&:&fruit&')), + array('=', '=', array('=water===fruit=')), + array('-', '-', array('-water--fruit-air')), + array('-', '-', array('-water---fruit---air-')), + array(':', '&', array('&""""&:&"&:,:":&,&:,,,,')) + +); +$file_path = dirname(__FILE__); +$file = "$file_path/fputcsv_variation8.tmp"; + +$file_modes = array ("r+", "r+b", "r+t", + "a+", "a+b", "a+t", + "w+", "w+b", "w+t", + "x+", "x+b", "x+t"); + +$loop_counter = 1; +foreach ($csv_lists as $csv_list) { + for($mode_counter = 0; $mode_counter < count($file_modes); $mode_counter++) { + + echo "\n-- file opened in $file_modes[$mode_counter] --\n"; + // create the file and add the content with has csv fields + if ( strstr($file_modes[$mode_counter], "r") ) { + $fo = new SplFileObject($file, 'w'); + } else { + $fo = new SplFileObject($file, $file_modes[$mode_counter]); + } + $delimiter = $csv_list[0]; + $enclosure = $csv_list[1]; + $csv_field = $csv_list[2]; + + // write to a file in csv format + var_dump( $fo->fputcsv($csv_field, $delimiter, '+') ); + // check the file pointer position and eof + var_dump( $fo->ftell() ); + var_dump( $fo->eof() ); + //close the file + unset($fo); + + // print the file contents + var_dump( file_get_contents($file) ); + + //delete file + unlink($file); + } //end of mode loop +} // end of foreach + +echo "Done\n"; +?> +--EXPECTF-- +*** Testing fputcsv() : with same delimiter and different enclosure *** + +-- file opened in r+ -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in r+b -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in r+t -- +int(14) +int(14) +bool(false) +string(%d) "+water,fruit+ +" + +-- file opened in a+ -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in a+b -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in a+t -- +int(14) +int(14) +bool(false) +string(%d) "+water,fruit+ +" + +-- file opened in w+ -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in w+b -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in w+t -- +int(14) +int(14) +bool(false) +string(%d) "+water,fruit+ +" + +-- file opened in x+ -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in x+b -- +int(14) +int(14) +bool(false) +string(14) "+water,fruit+ +" + +-- file opened in x+t -- +int(14) +int(14) +bool(false) +string(%d) "+water,fruit+ +" + +-- file opened in r+ -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in r+b -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in r+t -- +int(17) +int(17) +bool(false) +string(%d) "+"water","fruit+ +" + +-- file opened in a+ -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in a+b -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in a+t -- +int(17) +int(17) +bool(false) +string(%d) "+"water","fruit+ +" + +-- file opened in w+ -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in w+b -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in w+t -- +int(17) +int(17) +bool(false) +string(%d) "+"water","fruit+ +" + +-- file opened in x+ -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in x+b -- +int(17) +int(17) +bool(false) +string(17) "+"water","fruit+ +" + +-- file opened in x+t -- +int(17) +int(17) +bool(false) +string(%d) "+"water","fruit+ +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "+"water","fruit"+ +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "+"water","fruit"+ +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "+"water","fruit"+ +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "+"water","fruit"+ +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "+"water","fruit"+ +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "+^water^ ^fruit^+ +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "+^water^ ^fruit^+ +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "+^water^ ^fruit^+ +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "+^water^ ^fruit^+ +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "+^water^ ^fruit^+ +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "+&water&:&fruit&+ +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "+&water&:&fruit&+ +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "+&water&:&fruit&+ +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "+&water&:&fruit&+ +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "+&water&:&fruit&+ +" + +-- file opened in r+ -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in r+b -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in r+t -- +int(18) +int(18) +bool(false) +string(%d) "+=water===fruit=+ +" + +-- file opened in a+ -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in a+b -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in a+t -- +int(18) +int(18) +bool(false) +string(%d) "+=water===fruit=+ +" + +-- file opened in w+ -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in w+b -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in w+t -- +int(18) +int(18) +bool(false) +string(%d) "+=water===fruit=+ +" + +-- file opened in x+ -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in x+b -- +int(18) +int(18) +bool(false) +string(18) "+=water===fruit=+ +" + +-- file opened in x+t -- +int(18) +int(18) +bool(false) +string(%d) "+=water===fruit=+ +" + +-- file opened in r+ -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in r+b -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in r+t -- +int(20) +int(20) +bool(false) +string(%d) "+-water--fruit-air+ +" + +-- file opened in a+ -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in a+b -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in a+t -- +int(20) +int(20) +bool(false) +string(%d) "+-water--fruit-air+ +" + +-- file opened in w+ -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in w+b -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in w+t -- +int(20) +int(20) +bool(false) +string(%d) "+-water--fruit-air+ +" + +-- file opened in x+ -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in x+b -- +int(20) +int(20) +bool(false) +string(20) "+-water--fruit-air+ +" + +-- file opened in x+t -- +int(20) +int(20) +bool(false) +string(%d) "+-water--fruit-air+ +" + +-- file opened in r+ -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in r+b -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in r+t -- +int(24) +int(24) +bool(false) +string(%d) "+-water---fruit---air-+ +" + +-- file opened in a+ -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in a+b -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in a+t -- +int(24) +int(24) +bool(false) +string(%d) "+-water---fruit---air-+ +" + +-- file opened in w+ -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in w+b -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in w+t -- +int(24) +int(24) +bool(false) +string(%d) "+-water---fruit---air-+ +" + +-- file opened in x+ -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in x+b -- +int(24) +int(24) +bool(false) +string(24) "+-water---fruit---air-+ +" + +-- file opened in x+t -- +int(24) +int(24) +bool(false) +string(%d) "+-water---fruit---air-+ +" + +-- file opened in r+ -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in r+b -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in r+t -- +int(26) +int(26) +bool(false) +string(%d) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in a+ -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in a+b -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in a+t -- +int(26) +int(26) +bool(false) +string(%d) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in w+ -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in w+b -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in w+t -- +int(26) +int(26) +bool(false) +string(%d) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in x+ -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in x+b -- +int(26) +int(26) +bool(false) +string(26) "+&""""&:&"&:,:":&,&:,,,,+ +" + +-- file opened in x+t -- +int(26) +int(26) +bool(false) +string(%d) "+&""""&:&"&:,:":&,&:,,,,+ +" +Done + diff --git a/ext/spl/tests/SplFileObject_fscanf_basic.phpt b/ext/spl/tests/SplFileObject_fscanf_basic.phpt new file mode 100644 index 0000000..5279039 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fscanf_basic.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplFileObject::fscanf function - basic functionality test +--FILE-- +<?php +$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv'); +var_dump($obj->fscanf('%s')); +?> +--EXPECT-- +array(1) { + [0]=> + string(18) "first,second,third" +} diff --git a/ext/spl/tests/SplFileObject_fseek_error_001.phpt b/ext/spl/tests/SplFileObject_fseek_error_001.phpt new file mode 100644 index 0000000..0efeb98 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fseek_error_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplFileObject::fseek function - parameters test +--FILE-- +<?php +$obj = New SplFileObject(__FILE__); +$obj->fseek(1,2,3); +$obj->fseek(); +?> +--EXPECTF-- +Warning: SplFileObject::fseek() expects at most 2 parameters, 3 given %s + +Warning: SplFileObject::fseek() expects at least 1 parameter, 0 given %s diff --git a/ext/spl/tests/SplFileObject_ftruncate_error_001.phpt b/ext/spl/tests/SplFileObject_ftruncate_error_001.phpt new file mode 100644 index 0000000..a2eef60 --- /dev/null +++ b/ext/spl/tests/SplFileObject_ftruncate_error_001.phpt @@ -0,0 +1,32 @@ +--TEST-- +SplFileObject::ftruncate function - truncating with stream that does not support truncation +--FILE-- +<?php + +//create a basic stream class +class VariableStream { + var $position; + var $varname; + + function stream_open($path, $mode, $options, &$opened_path) + { + return true; + } + + function url_stat() { + } +} +stream_wrapper_register("SPLtest", "VariableStream"); +$ftruncate_test = ""; +//end creating stream + +//open an SplFileObject using the above test stream +$obj = New SplFileObject("SPLtest://ftruncate_test"); +try { + $obj->ftruncate(1); +} catch (LogicException $e) { + echo($e->getMessage()); +} +?> +--EXPECTF-- +Can't truncate file %s diff --git a/ext/spl/tests/SplFileObject_fwrite_error_001.phpt b/ext/spl/tests/SplFileObject_fwrite_error_001.phpt new file mode 100644 index 0000000..296a1f3 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fwrite_error_001.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplFileObject::fpassthru function - parameters test +--FILE-- +<?php +$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv'); +$obj->fwrite(); +$obj->fwrite('6,6,6',25,null); +?> +--EXPECTF-- +Warning: SplFileObject::fwrite() expects at least 1 parameter, 0 given in %s + +Warning: SplFileObject::fwrite() expects at most 2 parameters, 3 given in %s diff --git a/ext/spl/tests/SplFileObject_fwrite_variation_001.phpt b/ext/spl/tests/SplFileObject_fwrite_variation_001.phpt new file mode 100644 index 0000000..61741a8 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fwrite_variation_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +SplFileObject::fwrite function - writing with two parameters length < input string length +--FILE-- +<?php +$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_001.txt'; +if(file_exists($file)) { + unlink($file); +} +$obj = New SplFileObject($file,'w'); +$obj->fwrite('test_write',4); +var_dump(file_get_contents($file)); +?> +--CLEAN-- +<?php +$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_001.txt'; +if(file_exists($file)) { + unlink($file); +} +?> +--EXPECT-- +string(4) "test" diff --git a/ext/spl/tests/SplFileObject_fwrite_variation_002.phpt b/ext/spl/tests/SplFileObject_fwrite_variation_002.phpt new file mode 100644 index 0000000..31399a0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_fwrite_variation_002.phpt @@ -0,0 +1,21 @@ +--TEST-- +SplFileObject::fwrite function - writing with two parameters, length > input string length +--FILE-- +<?php +$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_002.txt'; +if(file_exists($file)) { + unlink($file); +} +$obj = New SplFileObject($file,'w'); +$obj->fwrite('test_write',12); +var_dump(file_get_contents($file)); +?> +--CLEAN-- +<?php +$file = dirname(__FILE__).'/SplFileObject_fwrite_variation_002.txt'; +if(file_exists($file)) { + unlink($file); +} +?> +--EXPECT-- +string(10) "test_write" diff --git a/ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt b/ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt new file mode 100644 index 0000000..e21f08f --- /dev/null +++ b/ext/spl/tests/SplFileObject_getCsvControl_basic_001.phpt @@ -0,0 +1,15 @@ +--TEST-- +SplFileObject::getCsvControl function - basic test +--FILE-- +<?php +$obj = New SplFileObject(dirname(__FILE__).'/SplFileObject_testinput.csv'); +var_dump($obj->getCsvControl()); + +?> +--EXPECTF-- +array(2) { + [0]=> + %unicode|string%(1) "," + [1]=> + %unicode|string%(1) """ +} diff --git a/ext/spl/tests/SplFileObject_getchildren_basic.phpt b/ext/spl/tests/SplFileObject_getchildren_basic.phpt new file mode 100644 index 0000000..065e8ea --- /dev/null +++ b/ext/spl/tests/SplFileObject_getchildren_basic.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplFileObject::getchildren basic +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +var_dump($s->getChildren()); + +?> +--EXPECT-- +NULL diff --git a/ext/spl/tests/SplFileObject_getchildren_error001.phpt b/ext/spl/tests/SplFileObject_getchildren_error001.phpt new file mode 100644 index 0000000..9c17a82 --- /dev/null +++ b/ext/spl/tests/SplFileObject_getchildren_error001.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplFileObject::getchildren error 001 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->getChildren('string'); + +?> +--EXPECTF-- +Warning: SplFileObject::getChildren() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFileObject_getflags_basic.phpt b/ext/spl/tests/SplFileObject_getflags_basic.phpt new file mode 100644 index 0000000..5addadf --- /dev/null +++ b/ext/spl/tests/SplFileObject_getflags_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject::getFlags basic +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php + +file_put_contents('testdata.csv', 'eerste;tweede;derde'); + +$fo = new SplFileObject('testdata.csv'); + +$fo->setFlags(SplFileObject::DROP_NEW_LINE); +var_dump($fo->getFlags()); +?> +--CLEAN-- +<?php +unlink('testdata.csv'); +?> +--EXPECT-- +int(1) diff --git a/ext/spl/tests/SplFileObject_getflags_error001.phpt b/ext/spl/tests/SplFileObject_getflags_error001.phpt new file mode 100644 index 0000000..1602f88 --- /dev/null +++ b/ext/spl/tests/SplFileObject_getflags_error001.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: SplFileObject::getFlags error 001 +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php + +file_put_contents('testdata.csv', 'eerste;tweede;derde'); + + +$fo = new SplFileObject('testdata.csv'); +$fo->setFlags(SplFileObject::READ_CSV); + +$fo->setFlags(SplFileObject::DROP_NEW_LINE); + +var_dump($fo->getFlags()); + +?> +--CLEAN-- +<?php +unlink('testdata.csv'); +?> +--EXPECT-- +int(1) diff --git a/ext/spl/tests/SplFileObject_getflags_error002.phpt b/ext/spl/tests/SplFileObject_getflags_error002.phpt new file mode 100644 index 0000000..e2c8255 --- /dev/null +++ b/ext/spl/tests/SplFileObject_getflags_error002.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: SplFileObject::getFlags error 001 +--CREDITS-- +Erwin Poeze <erwin.poeze@gmail.com> +--FILE-- +<?php + +file_put_contents('testdata.csv', 'eerste;tweede;derde'); + +$fo = new SplFileObject('testdata.csv'); +$fo->setFlags(SplFileObject::READ_CSV); + +$fo->getFlags('fake'); + +?> +--CLEAN-- +<?php +unlink('testdata.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::getFlags() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFileObject_getflags_variation001.phpt b/ext/spl/tests/SplFileObject_getflags_variation001.phpt new file mode 100644 index 0000000..640de03 --- /dev/null +++ b/ext/spl/tests/SplFileObject_getflags_variation001.phpt @@ -0,0 +1,29 @@ +--TEST-- +SPL: SplFileObject::getFlags +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php + +$fo = new SplFileObject(__FILE__); + +$fo->setFlags(SplFileObject::DROP_NEW_LINE); +var_dump($fo->getFlags()); + +$fo->setFlags(SplFileObject::READ_AHEAD); +var_dump($fo->getFlags()); + +$fo->setFlags(SplFileObject::SKIP_EMPTY); +var_dump($fo->getFlags()); + +$fo->setFlags(SplFileObject::READ_CSV); +var_dump($fo->getFlags()); + +?> +--EXPECT-- +int(1) +int(2) +int(4) +int(8) diff --git a/ext/spl/tests/SplFileObject_haschildren_basic.phpt b/ext/spl/tests/SplFileObject_haschildren_basic.phpt new file mode 100644 index 0000000..1ce00bf --- /dev/null +++ b/ext/spl/tests/SplFileObject_haschildren_basic.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplFileObject::haschildren basic +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +var_dump($s->hasChildren()); + +?> +--EXPECT-- +bool(false) diff --git a/ext/spl/tests/SplFileObject_haschildren_error001.phpt b/ext/spl/tests/SplFileObject_haschildren_error001.phpt new file mode 100644 index 0000000..0c4e1de --- /dev/null +++ b/ext/spl/tests/SplFileObject_haschildren_error001.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplFileObject::haschildren error 001 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->hasChildren('string'); + +?> +--EXPECTF-- +Warning: SplFileObject::hasChildren() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFileObject_key_basic.phpt b/ext/spl/tests/SplFileObject_key_basic.phpt new file mode 100644 index 0000000..4081d31 --- /dev/null +++ b/ext/spl/tests/SplFileObject_key_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplFileObject::key basic +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(3); +echo $s->key(); +?> +--EXPECT-- +3 diff --git a/ext/spl/tests/SplFileObject_key_error001.phpt b/ext/spl/tests/SplFileObject_key_error001.phpt new file mode 100644 index 0000000..b0834f0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_key_error001.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject::key error +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(12); +$s->next(); +var_dump($s->key()); +var_dump($s->valid()); +?> +--EXPECT-- +int(13) +bool(false) diff --git a/ext/spl/tests/SplFileObject_key_error002.phpt b/ext/spl/tests/SplFileObject_key_error002.phpt new file mode 100644 index 0000000..8fc9b7f --- /dev/null +++ b/ext/spl/tests/SplFileObject_key_error002.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject::key error +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(120); +$s->next(); +var_dump($s->key()); +var_dump($s->valid()); +?> +--EXPECT-- +int(13) +bool(false) diff --git a/ext/spl/tests/SplFileObject_key_error003.phpt b/ext/spl/tests/SplFileObject_key_error003.phpt new file mode 100644 index 0000000..7568cf5 --- /dev/null +++ b/ext/spl/tests/SplFileObject_key_error003.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: SplFileObject::key error +--CREDITS-- +Erwin Poeze <erwin.poeze AT gmail.com> +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +$s->key(3); +?> +--EXPECTF-- +Warning: SplFileObject::key() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFileObject_next_basic.phpt b/ext/spl/tests/SplFileObject_next_basic.phpt new file mode 100644 index 0000000..59dc7ab --- /dev/null +++ b/ext/spl/tests/SplFileObject_next_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject::next basic +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +echo $s->current(); +$s->next(); + +echo $s->current(); + +?> +--EXPECT-- +<?php +//line 2 diff --git a/ext/spl/tests/SplFileObject_next_variation001.phpt b/ext/spl/tests/SplFileObject_next_variation001.phpt new file mode 100644 index 0000000..34771dd --- /dev/null +++ b/ext/spl/tests/SplFileObject_next_variation001.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: SplFileObject::next variation 001 +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(13); +echo $s->current(); + +$s->next(); +echo $s->current(); +var_dump($s->valid()); +?> +--EXPECT-- +?> +bool(false) diff --git a/ext/spl/tests/SplFileObject_next_variation002.phpt b/ext/spl/tests/SplFileObject_next_variation002.phpt new file mode 100644 index 0000000..d48ff8c --- /dev/null +++ b/ext/spl/tests/SplFileObject_next_variation002.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: SplFileObject::next variation 002, read ahead +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +$s->seek(2); +echo $s->current(); +$s->next(); +echo $s->current(); + +$s->setFlags(SplFileObject::READ_AHEAD); + +$s->seek(2); +echo $s->current(); +$s->next(); +echo $s->current(); +?> +--EXPECT-- +//line 3 +//line 4 +//line 3 +//line 4 diff --git a/ext/spl/tests/SplFileObject_rewind_basic.phpt b/ext/spl/tests/SplFileObject_rewind_basic.phpt new file mode 100644 index 0000000..331c587 --- /dev/null +++ b/ext/spl/tests/SplFileObject_rewind_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: SplFileObject::rewind basic +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(3); + +$s->rewind(); +echo $s->current(); +?> +--EXPECT-- +<?php diff --git a/ext/spl/tests/SplFileObject_rewind_error001.phpt b/ext/spl/tests/SplFileObject_rewind_error001.phpt new file mode 100644 index 0000000..bdb3301 --- /dev/null +++ b/ext/spl/tests/SplFileObject_rewind_error001.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: SplFileObject::rewind() with a parameter. +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php + +file_put_contents('testdata.csv', 'eerste;tweede;derde'); + +$fo = new SplFileObject('testdata.csv'); + +$fo->rewind( "invalid" ); + +?> +--EXPECTF-- +Warning: SplFileObject::rewind() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFileObject_rewind_variation001.phpt b/ext/spl/tests/SplFileObject_rewind_variation001.phpt new file mode 100644 index 0000000..d835c44 --- /dev/null +++ b/ext/spl/tests/SplFileObject_rewind_variation001.phpt @@ -0,0 +1,28 @@ +--TEST-- +SPL: SplFileObject::rewind variation 001 +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(15); +echo $s->current(); +$s->next(); +echo $s->current(); +var_dump($s->valid()); +$s->rewind(); +var_dump($s->valid()); +echo $s->current(); +?> +--EXPECT-- +?> +bool(false) +bool(true) +<?php diff --git a/ext/spl/tests/SplFileObject_seek_basic.phpt b/ext/spl/tests/SplFileObject_seek_basic.phpt new file mode 100644 index 0000000..7106f70 --- /dev/null +++ b/ext/spl/tests/SplFileObject_seek_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplFileObject::seek basic +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(2); +echo $s->current(); +?> +--EXPECT-- +//line 3 diff --git a/ext/spl/tests/SplFileObject_seek_error002.phpt b/ext/spl/tests/SplFileObject_seek_error002.phpt new file mode 100644 index 0000000..057c8d3 --- /dev/null +++ b/ext/spl/tests/SplFileObject_seek_error002.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: SplFileObject::seek error 001 +--CREDITS-- +Ricardo Oedietram <ricardo@odracir.nl> +Erwin Poeze <erwin.poeze@gmail.com> +#PFZ June PHP TestFest 2012 +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); + +$s->seek(20); +echo $s->current(); +?> +--EXPECT-- diff --git a/ext/spl/tests/SplFileObject_seek_error_001.phpt b/ext/spl/tests/SplFileObject_seek_error_001.phpt new file mode 100644 index 0000000..bcf44b0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_seek_error_001.phpt @@ -0,0 +1,19 @@ +--TEST-- +SplFileObject::seek function - test parameters +--FILE-- +<?php +$obj = New SplFileObject(__FILE__); +$obj->seek(1,2); +$obj->seek(); +try { + $obj->seek(-1); +} catch (LogicException $e) { + echo($e->getMessage()); +} +?> +--EXPECTF-- + +Warning: SplFileObject::seek() expects exactly 1 parameter, 2 given in %s + +Warning: SplFileObject::seek() expects exactly 1 parameter, 0 given in %s +Can't seek file %s to negative line %s diff --git a/ext/spl/tests/SplFileObject_setCsvControl_basic.phpt b/ext/spl/tests/SplFileObject_setCsvControl_basic.phpt new file mode 100644 index 0000000..b263060 --- /dev/null +++ b/ext/spl/tests/SplFileObject_setCsvControl_basic.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: SplFileObject::setCsvControl basic +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +file_put_contents('csv_control_data.csv', +<<<CDATA +'groene appelen'|10 +'gele bananen'|20 +'rode kersen'|30 +CDATA +); +$s = new SplFileObject('csv_control_data.csv'); +$s->setFlags(SplFileObject::READ_CSV); +$s->setCsvControl('|', '\'', '/'); +foreach ($s as $row) { + list($fruit, $quantity) = $row; + echo "$fruit : $quantity\n"; +} +?> +--CLEAN-- +<?php +unlink('csv_control_data.csv'); +?> +--EXPECT-- +groene appelen : 10 +gele bananen : 20 +rode kersen : 30 + diff --git a/ext/spl/tests/SplFileObject_setCsvControl_error001.phpt b/ext/spl/tests/SplFileObject_setCsvControl_error001.phpt new file mode 100644 index 0000000..f582a4a --- /dev/null +++ b/ext/spl/tests/SplFileObject_setCsvControl_error001.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: SplFileObject::setCsvControl error 001 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +file_put_contents('csv_control_data.csv', +<<<CDATA +'groene appelen'|10 +'gele bananen'|20 +'rode kersen'|30 +CDATA +); +$s = new SplFileObject('csv_control_data.csv'); +$s->setFlags(SplFileObject::READ_CSV); +$s->setCsvControl('||'); +?> +--CLEAN-- +<?php +unlink('csv_control_data.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::setCsvControl(): delimiter must be a character in %s on line %d + diff --git a/ext/spl/tests/SplFileObject_setCsvControl_error002.phpt b/ext/spl/tests/SplFileObject_setCsvControl_error002.phpt new file mode 100644 index 0000000..bcfd9c4 --- /dev/null +++ b/ext/spl/tests/SplFileObject_setCsvControl_error002.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: SplFileObject::setCsvControl error 002 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +file_put_contents('csv_control_data.csv', +<<<CDATA +'groene appelen'|10 +'gele bananen'|20 +'rode kersen'|30 +CDATA +); +$s = new SplFileObject('csv_control_data.csv'); +$s->setFlags(SplFileObject::READ_CSV); +$s->setCsvControl('|', 'two'); +?> +--CLEAN-- +<?php +unlink('csv_control_data.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::setCsvControl(): enclosure must be a character in %s on line %d + diff --git a/ext/spl/tests/SplFileObject_setCsvControl_error003.phpt b/ext/spl/tests/SplFileObject_setCsvControl_error003.phpt new file mode 100644 index 0000000..8b1f54d --- /dev/null +++ b/ext/spl/tests/SplFileObject_setCsvControl_error003.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: SplFileObject::setCsvControl error 003 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--INI-- +include_path=. +--FILE-- +<?php +file_put_contents('csv_control_data.csv', +<<<CDATA +'groene appelen'|10 +'gele bananen'|20 +'rode kersen'|30 +CDATA +); +$s = new SplFileObject('csv_control_data.csv'); +$s->setFlags(SplFileObject::READ_CSV); +$s->setCsvControl('|', '\'', 'three'); +?> +--CLEAN-- +<?php +unlink('csv_control_data.csv'); +?> +--EXPECTF-- +Warning: SplFileObject::setCsvControl(): escape must be a character in %s on line %d + diff --git a/ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt b/ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt new file mode 100644 index 0000000..7aaf8a3 --- /dev/null +++ b/ext/spl/tests/SplFileObject_setCsvControl_variation001.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: SplFileObject::setCsvControl variation 001 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +file_put_contents('csv_control_data.csv', +<<<CDATA +"groene appelen",10 +"gele bananen",20 +"rode kersen",30 +CDATA +); +$s = new SplFileObject('csv_control_data.csv'); +$s->setFlags(SplFileObject::READ_CSV); +$s->setCsvControl(); +foreach ($s as $row) { + list($fruit, $quantity) = $row; + echo "$fruit : $quantity\n"; +} +?> +--CLEAN-- +<?php +unlink('csv_control_data.csv'); +?> +--EXPECT-- +groene appelen : 10 +gele bananen : 20 +rode kersen : 30 + diff --git a/ext/spl/tests/SplFileObject_testinput.csv b/ext/spl/tests/SplFileObject_testinput.csv new file mode 100644 index 0000000..41a9e31 --- /dev/null +++ b/ext/spl/tests/SplFileObject_testinput.csv @@ -0,0 +1,5 @@ +first,second,third +1,2,3 +4,5,6 +7,8,9 +0,0,0 diff --git a/ext/spl/tests/SplFixedArray__construct_param_array.phpt b/ext/spl/tests/SplFixedArray__construct_param_array.phpt new file mode 100644 index 0000000..d63d7cc --- /dev/null +++ b/ext/spl/tests/SplFixedArray__construct_param_array.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplFixedArray::__construct() with array passed as integer. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( array("string", 1) ); + +?> +--EXPECTF-- +Warning: SplFixedArray::__construct() expects parameter 1 to be long, array given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray__construct_param_float.phpt b/ext/spl/tests/SplFixedArray__construct_param_float.phpt new file mode 100644 index 0000000..670a109 --- /dev/null +++ b/ext/spl/tests/SplFixedArray__construct_param_float.phpt @@ -0,0 +1,14 @@ +--TEST-- +SplFixedArray::__construct() with float passed as parameter. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( 3.141 ); + +echo $array->getSize(); + +?> +--EXPECT-- +3
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray__construct_param_null.phpt b/ext/spl/tests/SplFixedArray__construct_param_null.phpt new file mode 100644 index 0000000..3b1543d --- /dev/null +++ b/ext/spl/tests/SplFixedArray__construct_param_null.phpt @@ -0,0 +1,16 @@ +--TEST-- +SplFixedArray::__construct() with null passed as parameter. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( NULL ); + +print_r( $array ); + +?> +--EXPECTF-- +SplFixedArray Object +( +)
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray__construct_param_string.phpt b/ext/spl/tests/SplFixedArray__construct_param_string.phpt new file mode 100644 index 0000000..3a7e734 --- /dev/null +++ b/ext/spl/tests/SplFixedArray__construct_param_string.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplFixedArray::__construct() with string passed as parameter. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( "string" ); + +?> +--EXPECTF-- +Warning: SplFixedArray::__construct() expects parameter 1 to be long, %unicode_string_optional% given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt b/ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt new file mode 100644 index 0000000..6582f84 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_construct_param_SplFixedArray.phpt @@ -0,0 +1,13 @@ +--TEST-- +Create an SplFixedArray using an SplFixedArray object. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = new SplFixedArray(new SplFixedArray(3)); +var_dump($array); +?> +--EXPECTF-- +Warning: SplFixedArray::__construct() expects parameter 1 to be long, object given in %s on line %d +object(SplFixedArray)#1 (0) { +}
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray_count_checkParams.phpt b/ext/spl/tests/SplFixedArray_count_checkParams.phpt new file mode 100644 index 0000000..5cbe2e8 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_count_checkParams.phpt @@ -0,0 +1,16 @@ +--TEST-- +Makes sure that an integer cannot be passed into the count() method of the splFixedArray. +--CREDITS-- +PHPNW Test Fest 2009 - Rick Ogden +--FILE-- +<?php +$ar = new SplFixedArray(3); +$ar[0] = 1; +$ar[1] = 2; +$ar[2] = 3; + +echo $ar->count(3); +?> +--EXPECTF-- +Warning: SplFixedArray::count() expects exactly 0 parameters, 1 given in %s on line %d + diff --git a/ext/spl/tests/SplFixedArray_count_param_int.phpt b/ext/spl/tests/SplFixedArray_count_param_int.phpt new file mode 100644 index 0000000..108bb2d --- /dev/null +++ b/ext/spl/tests/SplFixedArray_count_param_int.phpt @@ -0,0 +1,11 @@ +--TEST-- +Creates array, uses the count function to get the size of the array, but passes a parameter. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = new SplFixedArray(5); +echo $array->count(3); +?> +--EXPECTF-- +Warning: SplFixedArray::count() expects exactly 0 parameters, 1 given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray_current_param.phpt b/ext/spl/tests/SplFixedArray_current_param.phpt new file mode 100644 index 0000000..71f5d3a --- /dev/null +++ b/ext/spl/tests/SplFixedArray_current_param.phpt @@ -0,0 +1,24 @@ +--TEST-- +SplFixedArray::current() with a parameter. *BUG* +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( 3 ); + +$array[0] = "Hello"; +$array[1] = "world"; +$array[2] = "elePHPant"; + +foreach ( $array as $value ) { + echo $array->current( array("this","should","not","execute") ); +} + +?> +--EXPECTF-- +Warning: SplFixedArray::current() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: SplFixedArray::current() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: SplFixedArray::current() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt new file mode 100644 index 0000000..36ecf46 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_001.phpt @@ -0,0 +1,10 @@ +--TEST-- +pass an integer into fromArray() +--CREDITS-- +PHPNW Testfest 2009 - Lorna Mitchell +--FILE-- +<?php +echo SplFixedArray::fromArray(17954); +?> +--EXPECTF-- +Warning: SplFixedArray::fromArray() expects parameter 1 to be array, integer given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt new file mode 100644 index 0000000..ba81428 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_fromArray_invalid_parameter_002.phpt @@ -0,0 +1,10 @@ +--TEST-- +pass a string into fromArray() +--CREDITS-- +PHPNW Testfest 2009 - Lorna Mitchell +--FILE-- +<?php +echo SplFixedArray::fromArray('hello'); +?> +--EXPECTF-- +Warning: SplFixedArray::fromArray() expects parameter 1 to be array, %unicode_string_optional% given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_fromarray_indexes.phpt b/ext/spl/tests/SplFixedArray_fromarray_indexes.phpt new file mode 100644 index 0000000..034d457 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_fromarray_indexes.phpt @@ -0,0 +1,22 @@ +--TEST-- +Create a SplFixedArray from an array using the fromArray() function use the default behaviour of preserve the indexes. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = SplFixedArray::fromArray(array(1 => 1, + 2 => '2', + 3 => false)); +var_dump($array); +?> +--EXPECTF-- +object(SplFixedArray)#1 (4) { + [0]=> + NULL + [1]=> + int(1) + [2]=> + %string|unicode%(1) "2" + [3]=> + bool(false) +} diff --git a/ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt b/ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt new file mode 100644 index 0000000..ecae2ab --- /dev/null +++ b/ext/spl/tests/SplFixedArray_fromarray_non_indexes.phpt @@ -0,0 +1,21 @@ +--TEST-- +Create a SplFixedArray from an array using the fromArray() function don't try to preserve the indexes. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = SplFixedArray::fromArray(array(1 => 1, + 2 => '2', + 3 => false), + false); +var_dump($array); +?> +--EXPECTF-- +object(SplFixedArray)#1 (3) { + [0]=> + int(1) + [1]=> + %string|unicode%(1) "2" + [2]=> + bool(false) +} diff --git a/ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt b/ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt new file mode 100644 index 0000000..80d9669 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_fromarray_param_boolean.phpt @@ -0,0 +1,10 @@ +--TEST-- +Tries to create a SplFixedArray using a boolean value. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = SplFixedArray::fromArray(true); +?> +--EXPECTF-- +Warning: SplFixedArray::fromArray() expects parameter 1 to be array, boolean given in %s on line %d
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt b/ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt new file mode 100644 index 0000000..f57fe78 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_fromarray_param_multiarray.phpt @@ -0,0 +1,17 @@ +--TEST-- +Tries to create a SplFixedArray using the fromArray() function and a multi dimentional array. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = SplFixedArray::fromArray(array(array('1'))); +var_dump($array); +?> +--EXPECTF-- +object(SplFixedArray)#1 (1) { + [0]=> + array(1) { + [0]=> + %string|unicode%(1) "1" + } +} diff --git a/ext/spl/tests/SplFixedArray_getSize_pass_param.phpt b/ext/spl/tests/SplFixedArray_getSize_pass_param.phpt new file mode 100644 index 0000000..ef4f40c --- /dev/null +++ b/ext/spl/tests/SplFixedArray_getSize_pass_param.phpt @@ -0,0 +1,12 @@ +--TEST-- +SplFixedArray::getSize() pass a parameter when none are expected +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php +$fixed_array = new SplFixedArray(2); +echo "*test* ".$fixed_array->getSize(3); +?> +--EXPECTF-- +Warning: SplFixedArray::getSize() expects exactly 0 parameters, 1 given in %s on line %d +*test* diff --git a/ext/spl/tests/SplFixedArray_key_param.phpt b/ext/spl/tests/SplFixedArray_key_param.phpt new file mode 100644 index 0000000..300e6df --- /dev/null +++ b/ext/spl/tests/SplFixedArray_key_param.phpt @@ -0,0 +1,24 @@ +--TEST-- +SplFixedArray::key() with a parameter passed. This is a bug and an error should be called. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( 3 ); + +$array[0] = "Hello"; +$array[1] = "world"; +$array[2] = "elePHPant"; + +foreach ( $array as $value ) { + echo $array->key( array("this","should","not","execute") ); +} + +?> +--EXPECTF-- +Warning: SplFixedArray::key() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: SplFixedArray::key() expects exactly 0 parameters, 1 given in %s on line %d + +Warning: SplFixedArray::key() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_key_setsize.phpt b/ext/spl/tests/SplFixedArray_key_setsize.phpt new file mode 100644 index 0000000..97e4811 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_key_setsize.phpt @@ -0,0 +1,20 @@ +--TEST-- +SplFixedArray::key() when the array has a size higher than the amount of values specified. +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( 4 ); + +$array[0] = "Hello"; +$array[1] = "world"; +$array[2] = "elePHPant"; + +foreach ( $array as $value ) { + echo $array->key( ); +} + +?> +--EXPECT-- +0123
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray_next_param.phpt b/ext/spl/tests/SplFixedArray_next_param.phpt new file mode 100644 index 0000000..5e8cb63 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_next_param.phpt @@ -0,0 +1,18 @@ +--TEST-- +SplFixedArray::next() with a parameter. *BUG* +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( 4 ); + +$array[0] = "Hello"; +$array[1] = "world"; +$array[2] = "elePHPant"; + +$array->next( "invalid" ); + +?> +--EXPECTF-- +Warning: SplFixedArray::next() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt new file mode 100644 index 0000000..76ee2f5 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetExists_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL FixedArray offsetExists throws error only one parameter +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +$a = $array->offsetExists(); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplFixedArray::offsetExists() expects exactly 1 parameter, 0 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt b/ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt new file mode 100644 index 0000000..9bfda34 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetExists_less_than_zero.phpt @@ -0,0 +1,13 @@ +--TEST-- +SPL FixedArray offsetExists behaviour on a negative index +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +if($array->offsetExists(-10) === false) { + echo 'PASS'; +} +?> +--EXPECT-- +PASS diff --git a/ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt new file mode 100644 index 0000000..71a1bf8 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetGet_invalid_parameter.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL FixedArray offsetGet throws error on no parameter +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +$array[0] = 'a'; +$a = $array->offsetGet(); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplFixedArray::offsetGet() expects exactly 1 parameter, 0 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt new file mode 100644 index 0000000..4e43a52 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetSet_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL FixedArray offsetSet throws error on no parameters +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +$a = $array->offsetSet(); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplFixedArray::offsetSet() expects exactly 2 parameters, 0 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt new file mode 100644 index 0000000..c19cd01 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetSet_one_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL FixedArray offsetSet throws error only one parameter +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +$a = $array->offsetSet(2); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplFixedArray::offsetSet() expects exactly 2 parameters, 1 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt b/ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt new file mode 100644 index 0000000..40a372b --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetUnset_invalid_parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL FixedArray offsetUnset throws error on no parameter +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +$a = $array->offsetUnset(); +if(is_null($a)) { + echo 'PASS'; +} +?> +--EXPECTF-- +Warning: SplFixedArray::offsetUnset() expects exactly 1 parameter, 0 given in %s on line %d +PASS diff --git a/ext/spl/tests/SplFixedArray_offsetUnset_string.phpt b/ext/spl/tests/SplFixedArray_offsetUnset_string.phpt new file mode 100644 index 0000000..21976b5 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_offsetUnset_string.phpt @@ -0,0 +1,33 @@ +--TEST-- +Check removing an item from an array when the offset is not an integer. +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a fixed array + $fixedArray = new SplFixedArray(5); + + // Fill it up + for ($i=0; $i < 5; $i++) { + $fixedArray[$i] = "PHPNW Testfest"; + } + + // remove an item + $fixedArray->offsetUnset("4"); + + var_dump($fixedArray); + +?> +--EXPECTF-- +object(SplFixedArray)#1 (5) { + [0]=> + %string|unicode%(14) "PHPNW Testfest" + [1]=> + %string|unicode%(14) "PHPNW Testfest" + [2]=> + %string|unicode%(14) "PHPNW Testfest" + [3]=> + %string|unicode%(14) "PHPNW Testfest" + [4]=> + NULL +} diff --git a/ext/spl/tests/SplFixedArray_rewind_param.phpt b/ext/spl/tests/SplFixedArray_rewind_param.phpt new file mode 100644 index 0000000..7002efb --- /dev/null +++ b/ext/spl/tests/SplFixedArray_rewind_param.phpt @@ -0,0 +1,18 @@ +--TEST-- +SplFixedArray::rewind() with a parameter. *BUG* +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +$array = new SplFixedArray( 4 ); + +$array[0] = "Hello"; +$array[1] = "world"; +$array[2] = "elePHPant"; + +$array->rewind( "invalid" ); + +?> +--EXPECTF-- +Warning: SplFixedArray::rewind() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt b/ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt new file mode 100644 index 0000000..a460747 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setSize_filled_to_smaller.phpt @@ -0,0 +1,22 @@ +--TEST-- +Create array, fills it with and resizes it to lower value. +--CREDITS-- +Philip Norton philipnorton42@gmail.com +--FILE-- +<?php +$array = new SplFixedArray(5); +$array[0] = 1; +$array[1] = 1; +$array[2] = 1; +$array[3] = 1; +$array[4] = 1; +$array->setSize(2); +var_dump($array); +?> +--EXPECT-- +object(SplFixedArray)#1 (2) { + [0]=> + int(1) + [1]=> + int(1) +}
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray_setSize_param_array.phpt b/ext/spl/tests/SplFixedArray_setSize_param_array.phpt new file mode 100644 index 0000000..269a45d --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setSize_param_array.phpt @@ -0,0 +1,18 @@ +--TEST-- +SplFixedArray::setSize() with an array parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php +$fixed_array = new SplFixedArray(2); +$fixed_array->setSize(array()); +var_dump($fixed_array); +?> +--EXPECTF-- +Warning: SplFixedArray::setSize() expects parameter 1 to be long, array given in %s on line %d +object(SplFixedArray)#1 (2) { + [0]=> + NULL + [1]=> + NULL +} diff --git a/ext/spl/tests/SplFixedArray_setSize_param_float.phpt b/ext/spl/tests/SplFixedArray_setSize_param_float.phpt new file mode 100644 index 0000000..c65686c --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setSize_param_float.phpt @@ -0,0 +1,19 @@ +--TEST-- +SplFixedArray::setSize() with a float param +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php +$fixed_array = new SplFixedArray(2); +$fixed_array->setSize(3.14159); +var_dump($fixed_array); +?> +--EXPECTF-- +object(SplFixedArray)#1 (3) { + [0]=> + NULL + [1]=> + NULL + [2]=> + NULL +} diff --git a/ext/spl/tests/SplFixedArray_setSize_param_null.phpt b/ext/spl/tests/SplFixedArray_setSize_param_null.phpt new file mode 100644 index 0000000..ddb37be --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setSize_param_null.phpt @@ -0,0 +1,13 @@ +--TEST-- +SplFixedArray::setSize() with a null parameter +--CREDITS-- +PHPNW Testfest 2009 - Adrian Hardy +--FILE-- +<?php +$fixed_array = new SplFixedArray(2); +$fixed_array->setSize(null); +var_dump($fixed_array); +?> +--EXPECT-- +object(SplFixedArray)#1 (0) { +} diff --git a/ext/spl/tests/SplFixedArray_setSize_reduce.phpt b/ext/spl/tests/SplFixedArray_setSize_reduce.phpt new file mode 100644 index 0000000..eb8e1d9 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setSize_reduce.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL FixedArray can reduce size of array +--CREDITS-- +PHPNW TestFest 2009 - Ben Longden +--FILE-- +<?php +$array = new SplFixedArray(5); +$array[0] = 'a'; +$array[1] = 'b'; +$array[2] = 'c'; +$array[3] = 'd'; +$array[4] = 'e'; +$array->setSize(3); +print_r($array); +?> +--EXPECT-- +SplFixedArray Object +( + [0] => a + [1] => b + [2] => c +) diff --git a/ext/spl/tests/SplFixedArray_setsize_001.phpt b/ext/spl/tests/SplFixedArray_setsize_001.phpt new file mode 100644 index 0000000..925912c --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setsize_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: FixedArray: setsize - populate array, then shrink +--CREDITS-- +PHPNW TestFest2009 - Rowan Merewood <rowan@merewood.org> +--FILE-- +<?php +$array = new SplFixedArray(5); +$array[0] = 'one'; +$array[1] = 'two'; +$array[2] = 'three'; +$array[3] = 'four'; +$array[4] = 'five'; +$array->setSize(2); +var_dump($array); +?> +--EXPECTF-- +object(SplFixedArray)#1 (2) { + [0]=> + %string|unicode%(3) "one" + [1]=> + %string|unicode%(3) "two" +} diff --git a/ext/spl/tests/SplFixedArray_setsize_grow.phpt b/ext/spl/tests/SplFixedArray_setsize_grow.phpt new file mode 100644 index 0000000..418d1ac --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setsize_grow.phpt @@ -0,0 +1,30 @@ +--TEST-- +SplFixedArray::setSize() grow +--CREDITS-- +PHPNW Test Fest 2009 - Jordan Hatch +--FILE-- +<?php + +echo "\n"; + +$array = new SplFixedArray(2); + +$array[0] = "Value 1"; +$array[1] = "Value 2"; + +$array->setSize(4); + +$array[2] = "Value 3"; +$array[3] = "Value 4"; + +print_r($array); + +?> +--EXPECT-- +SplFixedArray Object +( + [0] => Value 1 + [1] => Value 2 + [2] => Value 3 + [3] => Value 4 +)
\ No newline at end of file diff --git a/ext/spl/tests/SplFixedArray_setsize_shrink.phpt b/ext/spl/tests/SplFixedArray_setsize_shrink.phpt new file mode 100644 index 0000000..2130cf8 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_setsize_shrink.phpt @@ -0,0 +1,28 @@ +--TEST-- +shrink a full array of integers +--CREDITS-- +PHPNW Testfest 2009 - Lorna Mitchell +--FILE-- +<?php +$array = new SplFixedArray(5); +$array[0] = 1; +$array[1] = 1; +$array[2] = 1; +$array[3] = 1; +$array[4] = 1; + +$array->setSize(4); +var_dump($array); + +?> +--EXPECT-- +object(SplFixedArray)#1 (4) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(1) + [3]=> + int(1) +} diff --git a/ext/spl/tests/SplFixedArray_toArray_with-params.phpt b/ext/spl/tests/SplFixedArray_toArray_with-params.phpt new file mode 100644 index 0000000..8864362 --- /dev/null +++ b/ext/spl/tests/SplFixedArray_toArray_with-params.phpt @@ -0,0 +1,19 @@ +--TEST-- +Check that passing a parameter to toArray() produces a correct error +--CREDITS-- +PHPNW Testfest 2009 - Paul Court ( g@rgoyle.com ) +--FILE-- +<?php + // Create a fixed array + $fixedArray = new SplFixedArray(5); + + // Fill it up + for ($i=0; $i < 5; $i++) { + $fixedArray[$i] = "PHPNW Testfest"; + } + + // Test count() returns correct error when parameters are passed. + $fixedArray->count(1); +?> +--EXPECTF-- +Warning: SplFixedArray::count() expects exactly 0 parameters, %d given in %s on line %d diff --git a/ext/spl/tests/SplHeap_count_invalid_parameter.phpt b/ext/spl/tests/SplHeap_count_invalid_parameter.phpt new file mode 100644 index 0000000..727790e --- /dev/null +++ b/ext/spl/tests/SplHeap_count_invalid_parameter.phpt @@ -0,0 +1,47 @@ +--TEST-- +Check that SplHeap::count generate a warning and returns NULL when param passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + new stdClass, + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $h = new SplMaxHeap(); + + var_dump($h->count($input)); +} + +?> +--EXPECTF-- +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplHeap_extract_invalid_parameter.phpt b/ext/spl/tests/SplHeap_extract_invalid_parameter.phpt new file mode 100644 index 0000000..ba03976 --- /dev/null +++ b/ext/spl/tests/SplHeap_extract_invalid_parameter.phpt @@ -0,0 +1,47 @@ +--TEST-- +Check that SplHeap::extract generate a warning and returns NULL when param passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + new stdClass, + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $h = new SplMaxHeap(); + + var_dump($h->extract($input)); +} + +?> +--EXPECTF-- +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplHeap_insert_invalid_parameter.phpt b/ext/spl/tests/SplHeap_insert_invalid_parameter.phpt new file mode 100644 index 0000000..86c6b63 --- /dev/null +++ b/ext/spl/tests/SplHeap_insert_invalid_parameter.phpt @@ -0,0 +1,16 @@ +--TEST-- +Check that SplHeap::insert generate a warning and returns NULL when $value is missing +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$h = new SplMaxHeap(); + +var_dump($h->insert()); + +?> +--EXPECTF-- +Warning: SplHeap::insert() expects exactly 1 parameter, 0 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplHeap_isEmpty.phpt b/ext/spl/tests/SplHeap_isEmpty.phpt new file mode 100644 index 0000000..e179dbc --- /dev/null +++ b/ext/spl/tests/SplHeap_isEmpty.phpt @@ -0,0 +1,15 @@ +--TEST-- +Check that SplHeap::isEmpty standard success test +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$h = new SplMaxHeap(); + +var_dump($h->isEmpty()); + +?> +--EXPECTF-- +bool(true) + diff --git a/ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt b/ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt new file mode 100644 index 0000000..021aff4 --- /dev/null +++ b/ext/spl/tests/SplHeap_isEmpty_invalid_parameter.phpt @@ -0,0 +1,47 @@ +--TEST-- +Check that SplHeap::isEmpty generate a warning and returns NULL when param passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + new stdClass, + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $h = new SplMaxHeap(); + + var_dump($h->isEmpty($input)); +} + +?> +--EXPECTF-- +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt new file mode 100644 index 0000000..62605b1 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_addAll_invalid_parameter.phpt @@ -0,0 +1,43 @@ +--TEST-- +Check that SplObjectStorage::addAll generate a warning and returns NULL when passed non-object param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + var_dump($s->addAll($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, array given in %s on line %d +NULL + +Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, %unicode_string_optional% given in %s on line %d +NULL + +Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, integer given in %s on line %d +NULL + +Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, double given in %s on line %d +NULL + +Warning: SplObjectStorage::addAll() expects parameter 1 to be SplObjectStorage, null given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt new file mode 100644 index 0000000..d984429 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_attach_invalid_parameter.phpt @@ -0,0 +1,20 @@ +--TEST-- +Check that SplObjectStorage::attach generates a warning and returns NULL when bad params are passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); + +var_dump($s->attach(true)); +var_dump($s->attach(new stdClass, true, true)); + +?> +--EXPECTF-- +Warning: SplObjectStorage::attach() expects parameter 1 to be object, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::attach() expects at most 2 parameters, 3 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt new file mode 100644 index 0000000..f523928 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_contains_invalid_parameter.phpt @@ -0,0 +1,43 @@ +--TEST-- +Check that SplObjectStorage::contains generate a warning and returns NULL when passed non-object param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + var_dump($s->contains($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::contains() expects parameter 1 to be object, array given in %s on line %d +NULL + +Warning: SplObjectStorage::contains() expects parameter 1 to be object, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::contains() expects parameter 1 to be object, %unicode_string_optional% given in %s on line %d +NULL + +Warning: SplObjectStorage::contains() expects parameter 1 to be object, integer given in %s on line %d +NULL + +Warning: SplObjectStorage::contains() expects parameter 1 to be object, double given in %s on line %d +NULL + +Warning: SplObjectStorage::contains() expects parameter 1 to be object, null given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_current_empty_storage.phpt b/ext/spl/tests/SplObjectStorage_current_empty_storage.phpt new file mode 100644 index 0000000..65fa691 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_current_empty_storage.phpt @@ -0,0 +1,15 @@ +--TEST-- +Check that SplObjectStorage::current returns NULL when storage is empty +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); + +var_dump($s->current()); + +?> +--EXPECT-- +NULL + diff --git a/ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt new file mode 100644 index 0000000..83b79fc --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_detach_invalid_parameter.phpt @@ -0,0 +1,43 @@ +--TEST-- +Check that SplObjectStorage::detach generate a warning and returns NULL when passed non-object param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + var_dump($s->detach($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::detach() expects parameter 1 to be object, array given in %s on line %d +NULL + +Warning: SplObjectStorage::detach() expects parameter 1 to be object, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::detach() expects parameter 1 to be object, %unicode_string_optional% given in %s on line %d +NULL + +Warning: SplObjectStorage::detach() expects parameter 1 to be object, integer given in %s on line %d +NULL + +Warning: SplObjectStorage::detach() expects parameter 1 to be object, double given in %s on line %d +NULL + +Warning: SplObjectStorage::detach() expects parameter 1 to be object, null given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_getHash.phpt b/ext/spl/tests/SplObjectStorage_getHash.phpt new file mode 100644 index 0000000..f309b3d --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_getHash.phpt @@ -0,0 +1,60 @@ +--TEST-- +SplObjectStorage::getHash implementation +--FILE-- +<?php +$s = new SplObjectStorage(); +$o1 = new Stdclass; +$o2 = new Stdclass; +$s[$o1] = "some_value\n"; +echo $s->offsetGet($o1); + +class MySplObjectStorage extends SplObjectStorage { + public function getHash($obj) { + return 2; + } +} + +try { + $s1 = new MySplObjectStorage; + $s1[$o1] = "foo"; +} catch(Exception $e) { + echo "caught\n"; +} + +class MySplObjectStorage2 extends SplObjectStorage { + public function getHash($obj) { + throw new Exception("foo"); + return "asd"; + } +} + +try { + $s2 = new MySplObjectStorage2; + $s2[$o2] = "foo"; +} catch(Exception $e) { + echo "caught\n"; +} + +class MySplObjectStorage3 extends SplObjectStorage { + public function getHash($obj) { + return "asd"; + } +} + +$s3 = new MySplObjectStorage3; +$s3[$o1] = $o1; +var_dump($s3[$o1]); +$s3[$o2] = $o2; + +var_dump($s3[$o1] === $s3[$o2]); + +?> +===DONE=== +--EXPECT-- +some_value +caught +caught +object(stdClass)#2 (0) { +} +bool(true) +===DONE=== diff --git a/ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt b/ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt new file mode 100644 index 0000000..e6c4de8 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_getInfo_empty_storage.phpt @@ -0,0 +1,15 @@ +--TEST-- +Check that SplObjectStorage::getInfo returns NULL when storage is empty +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); + +var_dump($s->getInfo()); + +?> +--EXPECT-- +NULL + diff --git a/ext/spl/tests/SplObjectStorage_offsetGet.phpt b/ext/spl/tests/SplObjectStorage_offsetGet.phpt new file mode 100644 index 0000000..e73f6b1 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_offsetGet.phpt @@ -0,0 +1,17 @@ +--TEST-- +Standard success for SplObjectStorage::offsetGet +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); +$o1 = new stdClass(); +$s[$o1] = 'some_value'; + +echo $s->offsetGet($o1); + +?> +--EXPECT-- +some_value + diff --git a/ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt new file mode 100644 index 0000000..3f8bd43 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_offsetGet_invalid_parameter.phpt @@ -0,0 +1,45 @@ +--TEST-- +Check that SplObjectStorage::offsetGet generate a warning and return NULL when passed non-object param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + $o1 = new stdClass(); + $s[$o1] = 'some_value'; + + var_dump($s->offsetGet($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, array given in %s on line %d +NULL + +Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, %unicode_string_optional% given in %s on line %d +NULL + +Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, integer given in %s on line %d +NULL + +Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, double given in %s on line %d +NULL + +Warning: SplObjectStorage::offsetGet() expects parameter 1 to be object, null given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt b/ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt new file mode 100644 index 0000000..72b032c --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_offsetGet_missing_object.phpt @@ -0,0 +1,20 @@ +--TEST-- +Check that SplObjectStorage::offsetGet throws exception when non-existing object is requested +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); +$o1 = new stdClass(); + +try { + $s->offsetGet($o1); +} catch (UnexpectedValueException $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Object not found + diff --git a/ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt b/ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt new file mode 100644 index 0000000..7c8cb75 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_removeAllExcept_basic.phpt @@ -0,0 +1,27 @@ +--TEST-- +Check that SplObjectStorage::removeUncommon functions when receiving proper input +--CREDITS-- +Matthew Turland (me@matthewturland.com) +--FILE-- +<?php + + $a = (object) 'a'; + $b = (object) 'b'; + $c = (object) 'c'; + + $foo = new SplObjectStorage; + $foo->attach($a); + $foo->attach($b); + + $bar = new SplObjectStorage; + $bar->attach($b); + $bar->attach($c); + + $foo->removeAllExcept($bar); + var_dump($foo->contains($a)); + var_dump($foo->contains($b)); + +?> +--EXPECT-- +bool(false) +bool(true) diff --git a/ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt new file mode 100644 index 0000000..62e0dde --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_removeAllExcept_invalid_parameter.phpt @@ -0,0 +1,44 @@ +--TEST-- +Check that SplObjectStorage::removeAllExcept generate a warning and returns NULL when passed non-object param +--CREDITS-- +Matthew Turland (me@matthewturland.com) +Based on work done at PHPNW Testfest 2009 by Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + var_dump($s->removeAllExcept($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, array given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, %unicode_string_optional% given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, integer given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, double given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAllExcept() expects parameter 1 to be SplObjectStorage, null given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt new file mode 100644 index 0000000..ffd3398 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_removeAll_invalid_parameter.phpt @@ -0,0 +1,43 @@ +--TEST-- +Check that SplObjectStorage::removeAll generate a warning and returns NULL when passed non-object param +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + var_dump($s->removeAll($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, array given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, boolean given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, %unicode_string_optional% given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, integer given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, double given in %s on line %d +NULL + +Warning: SplObjectStorage::removeAll() expects parameter 1 to be SplObjectStorage, null given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt b/ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt new file mode 100644 index 0000000..c8c3cd1 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_setInfo_empty_storage.phpt @@ -0,0 +1,15 @@ +--TEST-- +Check that SplObjectStorage::setInfo returns NULL when storage is empty +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); + +var_dump($s->setInfo('some_value')); + +?> +--EXPECT-- +NULL + diff --git a/ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt b/ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt new file mode 100644 index 0000000..52f8f9b --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_setInfo_invalid_parameter.phpt @@ -0,0 +1,16 @@ +--TEST-- +Check that SplObjectStorage::setInfo returns NULL when no param is passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); + +var_dump($s->setInfo()); + +?> +--EXPECTF-- +Warning: SplObjectStorage::setInfo() expects exactly 1 parameter, 0 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt new file mode 100644 index 0000000..a525317 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_unserialize_bad.phpt @@ -0,0 +1,45 @@ +--TEST-- +SPL: Test that serialized blob contains unique elements (CVE-2010-2225) +--FILE-- +<?php + +$badblobs = array( +'x:i:2;i:0;,i:1;;i:0;,i:2;;m:a:0:{}', +'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};R:2;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}', +'x:i:3;O:8:"stdClass":0:{},O:8:"stdClass":0:{};r:2;,i:1;;O:8:"stdClass":0:{},r:2;;m:a:0:{}', +); +foreach($badblobs as $blob) { +try { + $so = new SplObjectStorage(); + $so->unserialize($blob); + var_dump($so); +} catch(UnexpectedValueException $e) { + echo $e->getMessage()."\n"; +} +} +--EXPECTF-- +Error at offset 6 of 34 bytes +Error at offset 46 of 89 bytes +object(SplObjectStorage)#2 (1) { + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#3 (0) { + } + ["inf"]=> + int(1) + } + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#1 (0) { + } + ["inf"]=> + object(stdClass)#3 (0) { + } + } + } +} + diff --git a/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt new file mode 100644 index 0000000..dcf43e2 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter1.phpt @@ -0,0 +1,27 @@ +--TEST-- +Check that SplObjectStorage::unserialize returns NULL when non-string param is passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + array(), + new stdClass(), +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + var_dump($s->unserialize($input)); +} + +?> +--EXPECTF-- +Warning: SplObjectStorage::unserialize() expects parameter 1 to be %binary_string_optional%, array given in %s on line %d +NULL + +Warning: SplObjectStorage::unserialize() expects parameter 1 to be %binary_string_optional%, object given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt new file mode 100644 index 0000000..be2bb33 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter2.phpt @@ -0,0 +1,34 @@ +--TEST-- +Check that SplObjectStorage::unserialize throws exception when numeric value passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + 12345, + 1.2345, + PHP_INT_MAX, + 'x:rubbish', // rubbish after the 'x:' prefix + 'x:i:2;O:8:"stdClass":0:{},s:5:"value";;m:a:0:{}', +); + +foreach($data_provider as $input) { + + $s = new SplObjectStorage(); + + try { + $s->unserialize($input); + } catch(UnexpectedValueException $e) { + echo $e->getMessage() . PHP_EOL; + } +} + +?> +--EXPECTF-- +Error at offset %d of %d bytes +Error at offset %d of %d bytes +Error at offset %d of %d bytes +Error at offset %d of %d bytes +Error at offset %d of %d bytes + diff --git a/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt new file mode 100644 index 0000000..4c2dd75 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_unserialize_invalid_parameter3.phpt @@ -0,0 +1,19 @@ +--TEST-- +Check that SplObjectStorage::unserialize throws exception when NULL passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$s = new SplObjectStorage(); + +try { + $s->unserialize(NULL); +} catch(UnexpectedValueException $e) { + echo $e->getMessage(); +} + +?> +--EXPECTF-- +Empty serialized string cannot be empty + diff --git a/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt new file mode 100644 index 0000000..e96a82a --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_unserialize_nested.phpt @@ -0,0 +1,47 @@ +--TEST-- +SPL: Test unserializing tested & linked storage +--FILE-- +<?php +$o = new StdClass(); +$a = new StdClass(); + +$o->a = $a; + +$so = new SplObjectStorage(); + +$so[$o] = 1; +$so[$a] = 2; + +$s = serialize($so); +echo $s."\n"; + +$so1 = unserialize($s); +var_dump($so1); + +--EXPECTF-- +C:16:"SplObjectStorage":76:{x:i:2;O:8:"stdClass":1:{s:1:"a";O:8:"stdClass":0:{}},i:1;;r:4;,i:2;;m:a:0:{}} +object(SplObjectStorage)#4 (1) { + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#5 (1) { + ["a"]=> + object(stdClass)#6 (0) { + } + } + ["inf"]=> + int(1) + } + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#6 (0) { + } + ["inf"]=> + int(2) + } + } +} + diff --git a/ext/spl/tests/SplObjectStorage_var_dump.phpt b/ext/spl/tests/SplObjectStorage_var_dump.phpt new file mode 100644 index 0000000..0439f46 --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_var_dump.phpt @@ -0,0 +1,23 @@ +--TEST-- +SPL: SplObjectStorage: recursive var_dump +--FILE-- +<?php +$o = new SplObjectStorage(); + +$o[new StdClass] = $o; + +var_dump($o); +--EXPECTF-- +object(SplObjectStorage)#%d (1) { + ["storage":"SplObjectStorage":private]=> + array(1) { + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#%d (0) { + } + ["inf"]=> + *RECURSION* + } + } +} diff --git a/ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt b/ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt new file mode 100644 index 0000000..7dda782 --- /dev/null +++ b/ext/spl/tests/SplPriorityQueue_extract_invalid_parameter.phpt @@ -0,0 +1,47 @@ +--TEST-- +Check that SplPriorityQueue::extract generate a warning and returns NULL when param passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$data_provider = array( + new stdClass, + array(), + true, + "string", + 12345, + 1.2345, + NULL +); + +foreach($data_provider as $input) { + + $h = new SplPriorityQueue(); + + var_dump($h->extract($input)); +} + +?> +--EXPECTF-- +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt b/ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt new file mode 100644 index 0000000..7d7b589 --- /dev/null +++ b/ext/spl/tests/SplPriorityQueue_insert_invalid_parameter.phpt @@ -0,0 +1,16 @@ +--TEST-- +Check that SplPriorityQueue::insert generate a warning and returns NULL when rubbish params are passed +--CREDITS-- +PHPNW Testfest 2009 - Simon Westcott (swestcott@gmail.com) +--FILE-- +<?php + +$h = new SplPriorityQueue(); + +var_dump($h->insert(NULL)); + +?> +--EXPECTF-- +Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 1 given in %s on line %d +NULL + diff --git a/ext/spl/tests/SplQueue_setIteratorMode.phpt b/ext/spl/tests/SplQueue_setIteratorMode.phpt new file mode 100644 index 0000000..172a1d9 --- /dev/null +++ b/ext/spl/tests/SplQueue_setIteratorMode.phpt @@ -0,0 +1,15 @@ +--TEST-- +Check that SplQueue can't be set to LIFO +--CREDITS-- +Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009 +--FILE-- +<?php +$queue = new SplQueue(); +try { + $queue->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO); +} catch (Exception $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen diff --git a/ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt b/ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt new file mode 100644 index 0000000..c3071f2 --- /dev/null +++ b/ext/spl/tests/SplQueue_setIteratorMode_param_lifo.phpt @@ -0,0 +1,19 @@ +--TEST-- +SplQueue setIteratorMode to LIFO produces fail condition in try/catch +--CREDITS-- +PHPNW Test Fest 2009 - Jeremy Coates jeremy@phpnw.org.uk +--FILE-- +<?php + +try { + + $dll = new SplQueue(); + $dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO); + +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen diff --git a/ext/spl/tests/SplStack_setIteratorMode.phpt b/ext/spl/tests/SplStack_setIteratorMode.phpt new file mode 100644 index 0000000..d70105e --- /dev/null +++ b/ext/spl/tests/SplStack_setIteratorMode.phpt @@ -0,0 +1,15 @@ +--TEST-- +Check that SplStack can't be set to FIFO +--CREDITS-- +Rob Knight <themanhimself@robknight.org.uk> PHPNW Test Fest 2009 +--FILE-- +<?php +$stack = new SplStack(); +try { + $stack->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO); +} catch (Exception $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +Iterators' LIFO/FIFO modes for SplStack/SplQueue objects are frozen diff --git a/ext/spl/tests/SplTempFileObject_constructor_basic.phpt b/ext/spl/tests/SplTempFileObject_constructor_basic.phpt new file mode 100644 index 0000000..b2e640c --- /dev/null +++ b/ext/spl/tests/SplTempFileObject_constructor_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL SplTempFileObject constructor sets correct defaults when pass 0 arguments +--FILE-- +<?php +var_dump(new SplTempFileObject()); +?> +--EXPECTF-- +object(SplTempFileObject)#1 (5) { + ["pathName":"SplFileInfo":private]=> + string(10) "php://temp" + ["fileName":"SplFileInfo":private]=> + string(10) "php://temp" + ["openMode":"SplFileObject":private]=> + string(1) "w" + ["delimiter":"SplFileObject":private]=> + string(1) "," + ["enclosure":"SplFileObject":private]=> + string(1) """ +} diff --git a/ext/spl/tests/SplTempFileObject_constructor_error.phpt b/ext/spl/tests/SplTempFileObject_constructor_error.phpt new file mode 100644 index 0000000..d2717ac --- /dev/null +++ b/ext/spl/tests/SplTempFileObject_constructor_error.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL SplTempFileObject constructor sets correct defaults when pass 0 arguments +--FILE-- +<?php +new SplTempFileObject('invalid'); +?> +--EXPECTF-- +Fatal error: Uncaught exception 'RuntimeException' with message 'SplTempFileObject::__construct() expects parameter 1 to be long, string given' in %s +Stack trace: +#0 %s: SplTempFileObject->__construct('invalid') +#1 {main} + thrown in %s diff --git a/ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt b/ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt new file mode 100644 index 0000000..2ef1b2c --- /dev/null +++ b/ext/spl/tests/SplTempFileObject_constructor_maxmemory_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL SplTempFileObject constructor sets correct values when passed fixed memory size +--FILE-- +<?php +var_dump(new SplTempFileObject(1024)); +?> +--EXPECTF-- +object(SplTempFileObject)#1 (5) { + ["pathName":"SplFileInfo":private]=> + string(25) "php://temp/maxmemory:1024" + ["fileName":"SplFileInfo":private]=> + string(25) "php://temp/maxmemory:1024" + ["openMode":"SplFileObject":private]=> + string(1) "w" + ["delimiter":"SplFileObject":private]=> + string(1) "," + ["enclosure":"SplFileObject":private]=> + string(1) """ +} diff --git a/ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt b/ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt new file mode 100644 index 0000000..9fe5892 --- /dev/null +++ b/ext/spl/tests/SplTempFileObject_constructor_memory_lt1_variation.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL SplTempFileObject constructor sets correct defaults when passed a negative value +--FILE-- +<?php +var_dump(new SplTempFileObject(-1)); +?> +--EXPECTF-- +object(SplTempFileObject)#1 (5) { + ["pathName":"SplFileInfo":private]=> + string(12) "php://memory" + ["fileName":"SplFileInfo":private]=> + string(12) "php://memory" + ["openMode":"SplFileObject":private]=> + string(1) "w" + ["delimiter":"SplFileObject":private]=> + string(1) "," + ["enclosure":"SplFileObject":private]=> + string(1) """ +} diff --git a/ext/spl/tests/arrayObject___construct_basic1.phpt b/ext/spl/tests/arrayObject___construct_basic1.phpt new file mode 100644 index 0000000..f192cca --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_basic1.phpt @@ -0,0 +1,52 @@ +--TEST-- +SPL: ArrayObject::__construct basic usage. +--FILE-- +<?php +echo "--> No arguments:\n"; +var_dump(new ArrayObject()); + +echo "--> Object argument:\n"; +$a = new stdClass; +$a->p = 'hello'; +var_dump(new ArrayObject($a)); + +echo "--> Array argument:\n"; +var_dump(new ArrayObject(array('key1' => 'val1'))); + +echo "--> Nested ArrayObject argument:\n"; +var_dump(new ArrayObject(new ArrayObject($a))); +?> +--EXPECTF-- +--> No arguments: +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(0) { + } +} +--> Object argument: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(stdClass)#1 (1) { + ["p"]=> + string(5) "hello" + } +} +--> Array argument: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["key1"]=> + string(4) "val1" + } +} +--> Nested ArrayObject argument: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(ArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(stdClass)#1 (1) { + ["p"]=> + string(5) "hello" + } + } +} diff --git a/ext/spl/tests/arrayObject___construct_basic2.phpt b/ext/spl/tests/arrayObject___construct_basic2.phpt new file mode 100644 index 0000000..bd27c42 --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_basic2.phpt @@ -0,0 +1,104 @@ +--TEST-- +SPL: ArrayObject::__construct basic usage. +--FILE-- +<?php +class C { + public $prop = 'C::prop.orig'; +} + +class MyArrayObject extends ArrayObject { + public $prop = 'MyArrayObject::prop.orig'; +} + +echo "--> Access prop on instance of ArrayObject:\n"; +$c = new C; +$ao = new ArrayObject($c); +testAccess($c, $ao); + +echo "\n--> Access prop on instance of MyArrayObject:\n"; +$c = new C; +$ao = new MyArrayObject($c); +testAccess($c, $ao); + +function testAccess($c, $ao) { + echo " - Iteration:\n"; + foreach ($ao as $key=>$value) { + echo " $key=>$value\n"; + } + + echo " - Read:\n"; + @var_dump($ao->prop, $ao['prop']); + + echo " - Write:\n"; + $ao->prop = 'changed1'; + $ao['prop'] = 'changed2'; + var_dump($ao->prop, $ao['prop']); + + echo " - Isset:\n"; + var_dump(isset($ao->prop), isset($ao['prop'])); + + echo " - Unset:\n"; + unset($ao->prop); + unset($ao['prop']); + var_dump($ao->prop, $ao['prop']); + + echo " - After:\n"; + var_dump($ao, $c); +} +?> +--EXPECTF-- +--> Access prop on instance of ArrayObject: + - Iteration: + prop=>C::prop.orig + - Read: +NULL +string(12) "C::prop.orig" + - Write: +string(8) "changed1" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined property: ArrayObject::$prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (0) { + } +} +object(C)#1 (0) { +} + +--> Access prop on instance of MyArrayObject: + - Iteration: + prop=>C::prop.orig + - Read: +string(24) "MyArrayObject::prop.orig" +string(12) "C::prop.orig" + - Write: +string(8) "changed1" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined property: MyArrayObject::$prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(MyArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(C)#4 (0) { + } +} +object(C)#4 (0) { +} diff --git a/ext/spl/tests/arrayObject___construct_basic3.phpt b/ext/spl/tests/arrayObject___construct_basic3.phpt new file mode 100644 index 0000000..11a17a6 --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_basic3.phpt @@ -0,0 +1,104 @@ +--TEST-- +SPL: ArrayObject::__construct basic usage with ArrayObject::STD_PROP_LIST. +--FILE-- +<?php +class C { + public $prop = 'C::prop.orig'; +} + +class MyArrayObject extends ArrayObject { + public $prop = 'MyArrayObject::prop.orig'; +} + +echo "\n--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST:\n"; +$c = new C; +$ao = new ArrayObject($c, ArrayObject::STD_PROP_LIST); +testAccess($c, $ao); + +echo "\n--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST:\n"; +$c = new C; +$ao = new MyArrayObject($c, ArrayObject::STD_PROP_LIST); +testAccess($c, $ao); + +function testAccess($c, $ao) { + echo " - Iteration:\n"; + foreach ($ao as $key=>$value) { + echo " $key=>$value\n"; + } + + echo " - Read:\n"; + @var_dump($ao->prop, $ao['prop']); + + echo " - Write:\n"; + $ao->prop = 'changed1'; + $ao['prop'] = 'changed2'; + var_dump($ao->prop, $ao['prop']); + + echo " - Isset:\n"; + var_dump(isset($ao->prop), isset($ao['prop'])); + + echo " - Unset:\n"; + unset($ao->prop); + unset($ao['prop']); + var_dump($ao->prop, $ao['prop']); + + echo " - After:\n"; + var_dump($ao, $c); +} +?> +--EXPECTF-- +--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST: + - Iteration: + prop=>C::prop.orig + - Read: +NULL +string(12) "C::prop.orig" + - Write: +string(8) "changed1" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined property: ArrayObject::$prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (0) { + } +} +object(C)#1 (0) { +} + +--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST: + - Iteration: + prop=>C::prop.orig + - Read: +string(24) "MyArrayObject::prop.orig" +string(12) "C::prop.orig" + - Write: +string(8) "changed1" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined property: MyArrayObject::$prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(MyArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(C)#4 (0) { + } +} +object(C)#4 (0) { +} diff --git a/ext/spl/tests/arrayObject___construct_basic4.phpt b/ext/spl/tests/arrayObject___construct_basic4.phpt new file mode 100644 index 0000000..b0809de --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_basic4.phpt @@ -0,0 +1,106 @@ +--TEST-- +SPL: ArrayObject::__construct basic usage with ArrayObject::ARRAY_AS_PROPS. Currently fails on php.net due to bug 45622. +--FILE-- +<?php +class C { + public $prop = 'C::prop.orig'; +} + +class MyArrayObject extends ArrayObject { + public $prop = 'MyArrayObject::prop.orig'; +} + +echo "\n--> Access prop on instance of ArrayObject with ArrayObject::ARRAY_AS_PROPS:\n"; +$c = new C; +$ao = new ArrayObject($c, ArrayObject::ARRAY_AS_PROPS); +testAccess($c, $ao); + +echo "\n--> Access prop on instance of MyArrayObject with ArrayObject::ARRAY_AS_PROPS:\n"; +$c = new C; +$ao = new MyArrayObject($c, ArrayObject::ARRAY_AS_PROPS); +testAccess($c, $ao); + +function testAccess($c, $ao) { + echo " - Iteration:\n"; + foreach ($ao as $key=>$value) { + echo " $key=>$value\n"; + } + + echo " - Read:\n"; + @var_dump($ao->prop, $ao['prop']); + + echo " - Write:\n"; + $ao->prop = 'changed1'; + $ao['prop'] = 'changed2'; + var_dump($ao->prop, $ao['prop']); + + echo " - Isset:\n"; + var_dump(isset($ao->prop), isset($ao['prop'])); + + echo " - Unset:\n"; + unset($ao->prop); + unset($ao['prop']); + var_dump($ao->prop, $ao['prop']); + + echo " - After:\n"; + var_dump($ao, $c); +} +?> +--EXPECTF-- +--> Access prop on instance of ArrayObject with ArrayObject::ARRAY_AS_PROPS: + - Iteration: + prop=>C::prop.orig + - Read: +string(12) "C::prop.orig" +string(12) "C::prop.orig" + - Write: +string(8) "changed2" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined index: prop in %s on line 39 + +Notice: Undefined index: prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (0) { + } +} +object(C)#1 (0) { +} + +--> Access prop on instance of MyArrayObject with ArrayObject::ARRAY_AS_PROPS: + - Iteration: + prop=>C::prop.orig + - Read: +string(24) "MyArrayObject::prop.orig" +string(12) "C::prop.orig" + - Write: +string(8) "changed1" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined index: prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(MyArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(C)#4 (0) { + } +} +object(C)#4 (0) { +} diff --git a/ext/spl/tests/arrayObject___construct_basic5.phpt b/ext/spl/tests/arrayObject___construct_basic5.phpt new file mode 100644 index 0000000..8c44ee2 --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_basic5.phpt @@ -0,0 +1,106 @@ +--TEST-- +SPL: ArrayObject::__construct basic usage with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS. Currently fails on php.net due to bug 45622. +--FILE-- +<?php +class C { + public $prop = 'C::prop.orig'; +} + +class MyArrayObject extends ArrayObject { + public $prop = 'MyArrayObject::prop.orig'; +} + +echo "\n--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS:\n"; +$c = new C; +$ao = new ArrayObject($c, ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS); +testAccess($c, $ao); + +echo "\n--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS:\n"; +$c = new C; +$ao = new MyArrayObject($c, ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS); +testAccess($c, $ao); + +function testAccess($c, $ao) { + echo " - Iteration:\n"; + foreach ($ao as $key=>$value) { + echo " $key=>$value\n"; + } + + echo " - Read:\n"; + @var_dump($ao->prop, $ao['prop']); + + echo " - Write:\n"; + $ao->prop = 'changed1'; + $ao['prop'] = 'changed2'; + var_dump($ao->prop, $ao['prop']); + + echo " - Isset:\n"; + var_dump(isset($ao->prop), isset($ao['prop'])); + + echo " - Unset:\n"; + unset($ao->prop); + unset($ao['prop']); + var_dump($ao->prop, $ao['prop']); + + echo " - After:\n"; + var_dump($ao, $c); +} +?> +--EXPECTF-- +--> Access prop on instance of ArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS: + - Iteration: + prop=>C::prop.orig + - Read: +string(12) "C::prop.orig" +string(12) "C::prop.orig" + - Write: +string(8) "changed2" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined index: prop in %s on line 39 + +Notice: Undefined index: prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (0) { + } +} +object(C)#1 (0) { +} + +--> Access prop on instance of MyArrayObject with ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS: + - Iteration: + prop=>C::prop.orig + - Read: +string(24) "MyArrayObject::prop.orig" +string(12) "C::prop.orig" + - Write: +string(8) "changed1" +string(8) "changed2" + - Isset: +bool(true) +bool(true) + - Unset: + +Notice: Undefined index: prop in %s on line 40 + +Notice: Undefined index: prop in %s on line 40 +NULL +NULL + - After: +object(MyArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(C)#4 (0) { + } +} +object(C)#4 (0) { +} diff --git a/ext/spl/tests/arrayObject___construct_basic6.phpt b/ext/spl/tests/arrayObject___construct_basic6.phpt new file mode 100644 index 0000000..1c7ec36 --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_basic6.phpt @@ -0,0 +1,80 @@ +--TEST-- +SPL: ArrayObject::__construct: check impact of ArrayObject::STD_PROP_LIST on var_dump. +--FILE-- +<?php +class MyArrayObject extends ArrayObject { + private $priv1 = 'secret1'; + public $pub1 = 'public1'; +} + +$ao = new ArrayObject(array(1,2,3)); +$ao->p = 1; +var_dump($ao); + +$ao = new ArrayObject(array(1,2,3), ArrayObject::STD_PROP_LIST); +$ao->p = 1; +var_dump($ao); + +$ao = new MyArrayObject(array(1,2,3)); +var_dump($ao); + +$ao = new MyArrayObject(array(1,2,3), ArrayObject::STD_PROP_LIST); +var_dump($ao); +?> +--EXPECTF-- +object(ArrayObject)#1 (2) { + ["p"]=> + int(1) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +object(ArrayObject)#2 (2) { + ["p"]=> + int(1) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +object(MyArrayObject)#1 (3) { + ["priv1":"MyArrayObject":private]=> + string(7) "secret1" + ["pub1"]=> + string(7) "public1" + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +object(MyArrayObject)#2 (3) { + ["priv1":"MyArrayObject":private]=> + string(7) "secret1" + ["pub1"]=> + string(7) "public1" + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} diff --git a/ext/spl/tests/arrayObject___construct_error1.phpt b/ext/spl/tests/arrayObject___construct_error1.phpt new file mode 100644 index 0000000..21c312d --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_error1.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: ArrayObject::__construct with bad iterator. +--FILE-- +<?php +echo "Bad iterator type:\n"; +$a = new stdClass; +$a->p = 1; +try { + var_dump(new ArrayObject($a, 0, "Exception")); +} catch (InvalidArgumentException $e) { + echo $e->getMessage() . "(" . $e->getLine() . ")\n"; +} + +echo "Non-existent class:\n"; +try { + var_dump(new ArrayObject(new stdClass, 0, "nonExistentClassName")); +} catch (InvalidArgumentException $e) { + echo $e->getMessage() . "(" . $e->getLine() . ")\n"; +} +?> +--EXPECTF-- +Bad iterator type: +ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'Exception' given(6) +Non-existent class: +ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'nonExistentClassName' given(13) diff --git a/ext/spl/tests/arrayObject___construct_error2.phpt b/ext/spl/tests/arrayObject___construct_error2.phpt new file mode 100644 index 0000000..850a2cb --- /dev/null +++ b/ext/spl/tests/arrayObject___construct_error2.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: ArrayObject::__construct with too many arguments. +--FILE-- +<?php +echo "Too many arguments:\n"; +Class C implements Iterator { + function current() {} + function next() {} + function key() {} + function valid() {} + function rewind() {} +} + +try { + var_dump(new ArrayObject(new stdClass, 0, "C", "extra")); +} catch (InvalidArgumentException $e) { + echo $e->getMessage() . "(" . $e->getLine() . ")\n"; +} +?> +--EXPECTF-- +Too many arguments: +ArrayObject::__construct() expects at most 3 parameters, 4 given(12)
\ No newline at end of file diff --git a/ext/spl/tests/arrayObject_asort_basic1.phpt b/ext/spl/tests/arrayObject_asort_basic1.phpt new file mode 100644 index 0000000..53df1d5 --- /dev/null +++ b/ext/spl/tests/arrayObject_asort_basic1.phpt @@ -0,0 +1,64 @@ +--TEST-- +SPL: Test ArrayObject::asort() function : basic functionality with array based store +--FILE-- +<?php +/* Prototype : int ArrayObject::asort() + * Description: proto int ArrayIterator::asort() + * Sort the entries by values. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::asort() : basic functionality ***\n"; + +$ao1 = new ArrayObject(array(4,2,3)); +$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3)); +var_dump($ao1->asort()); +var_dump($ao1); +var_dump($ao2->asort('blah')); +var_dump($ao2); +var_dump($ao2->asort(SORT_NUMERIC)); +var_dump($ao2); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::asort() : basic functionality *** +bool(true) +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [1]=> + int(2) + [2]=> + int(3) + [0]=> + int(4) + } +} + +Warning: asort() expects parameter 2 to be long, string given in %sarrayObject_asort_basic1.php on line %d +bool(false) +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["a"]=> + int(4) + ["b"]=> + int(2) + ["c"]=> + int(3) + } +} +bool(true) +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["a"]=> + int(4) + } +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_asort_basic2.phpt b/ext/spl/tests/arrayObject_asort_basic2.phpt new file mode 100644 index 0000000..d481d0c --- /dev/null +++ b/ext/spl/tests/arrayObject_asort_basic2.phpt @@ -0,0 +1,52 @@ +--TEST-- +SPL: Test ArrayObject::asort() function : basic functionality with object based store +--FILE-- +<?php +/* Prototype : int ArrayObject::asort() + * Description: proto int ArrayIterator::asort() + * Sort the entries by values. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::asort() : basic functionality ***\n"; +Class C { + public $prop1 = 'x'; + public $prop2 = 'z'; + private $prop3 = 'a'; + public $prop4 = 'x'; +} + +$c = new C; +$ao1 = new ArrayObject($c); +var_dump($ao1->asort()); +var_dump($ao1, $c); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::asort() : basic functionality *** +bool(true) +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (4) { + ["prop3":"C":private]=> + string(1) "a" + ["prop1"]=> + string(1) "x" + ["prop4"]=> + string(1) "x" + ["prop2"]=> + string(1) "z" + } +} +object(C)#1 (4) { + ["prop3":"C":private]=> + string(1) "a" + ["prop1"]=> + string(1) "x" + ["prop4"]=> + string(1) "x" + ["prop2"]=> + string(1) "z" +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_clone_basic1.phpt b/ext/spl/tests/arrayObject_clone_basic1.phpt new file mode 100644 index 0000000..dd4abf3 --- /dev/null +++ b/ext/spl/tests/arrayObject_clone_basic1.phpt @@ -0,0 +1,48 @@ +--TEST-- +SPL: Cloning an instance of ArrayObject which wraps an array. +--FILE-- +<?php +$a = array(1,2); +$aa1 = new ArrayObject($a); +$a['p1'] = 'new element added to a before clone'; + +$aa2 = clone $aa1; + +$a['p2'] = 'new element added to a after clone'; +$aa1['new.aa1'] = 'new element added to aa1'; +$aa2['new.aa2'] = 'new element added to aa2'; +var_dump($a, $aa1, $aa2); +?> +--EXPECTF-- +array(4) { + [0]=> + int(1) + [1]=> + int(2) + ["p1"]=> + string(35) "new element added to a before clone" + ["p2"]=> + string(34) "new element added to a after clone" +} +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + ["new.aa1"]=> + string(24) "new element added to aa1" + } +} +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + ["new.aa2"]=> + string(24) "new element added to aa2" + } +} diff --git a/ext/spl/tests/arrayObject_clone_basic2.phpt b/ext/spl/tests/arrayObject_clone_basic2.phpt new file mode 100644 index 0000000..932eaed --- /dev/null +++ b/ext/spl/tests/arrayObject_clone_basic2.phpt @@ -0,0 +1,46 @@ +--TEST-- +SPL: Cloning an instance of ArrayObject which wraps an object. +--FILE-- +<?php +class C { } + +$c = new C; +$ao1 = new ArrayObject($c); +$c->p1 = 'new prop added to c before clone'; + +$ao2 = clone $ao1; + +$c->p2 = 'new prop added to c after clone'; +$ao1['new.ao1'] = 'new element added to ao1'; +$ao2['new.ao2'] = 'new element added to ao2'; +var_dump($c, $ao1, $ao2); +?> +--EXPECTF-- +object(C)#1 (3) { + ["p1"]=> + string(32) "new prop added to c before clone" + ["p2"]=> + string(31) "new prop added to c after clone" + ["new.ao1"]=> + string(24) "new element added to ao1" +} +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (3) { + ["p1"]=> + string(32) "new prop added to c before clone" + ["p2"]=> + string(31) "new prop added to c after clone" + ["new.ao1"]=> + string(24) "new element added to ao1" + } +} +object(ArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["p1"]=> + string(32) "new prop added to c before clone" + ["new.ao2"]=> + string(24) "new element added to ao2" + } +} diff --git a/ext/spl/tests/arrayObject_clone_basic3.phpt b/ext/spl/tests/arrayObject_clone_basic3.phpt new file mode 100644 index 0000000..f7ac894 --- /dev/null +++ b/ext/spl/tests/arrayObject_clone_basic3.phpt @@ -0,0 +1,80 @@ +--TEST-- +SPL: Cloning nested ArrayObjects. +--FILE-- +<?php +class C { + public $p = 'C::p.orig'; +} + +$wrappedObject = new C; +$innerArrayObject = new ArrayObject($wrappedObject); + +$outerArrayObject = new ArrayObject($innerArrayObject); + +$wrappedObject->dynamic1 = 'new prop added to $wrappedObject before clone'; +$clonedOuterArrayObject = clone $outerArrayObject; +$wrappedObject->dynamic2 = 'new prop added to $wrappedObject after clone'; + +$innerArrayObject['new.iAO'] = 'new element added $innerArrayObject'; +$outerArrayObject['new.oAO'] = 'new element added to $outerArrayObject'; +$clonedOuterArrayObject['new.coAO'] = 'new element added to $clonedOuterArrayObject'; + +var_dump($wrappedObject, $innerArrayObject, $outerArrayObject, $clonedOuterArrayObject); +?> +--EXPECTF-- +object(C)#1 (5) { + ["p"]=> + string(9) "C::p.orig" + ["dynamic1"]=> + string(45) "new prop added to $wrappedObject before clone" + ["dynamic2"]=> + string(44) "new prop added to $wrappedObject after clone" + ["new.iAO"]=> + string(35) "new element added $innerArrayObject" + ["new.oAO"]=> + string(38) "new element added to $outerArrayObject" +} +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["p"]=> + string(9) "C::p.orig" + ["dynamic1"]=> + string(45) "new prop added to $wrappedObject before clone" + ["dynamic2"]=> + string(44) "new prop added to $wrappedObject after clone" + ["new.iAO"]=> + string(35) "new element added $innerArrayObject" + ["new.oAO"]=> + string(38) "new element added to $outerArrayObject" + } +} +object(ArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["p"]=> + string(9) "C::p.orig" + ["dynamic1"]=> + string(45) "new prop added to $wrappedObject before clone" + ["dynamic2"]=> + string(44) "new prop added to $wrappedObject after clone" + ["new.iAO"]=> + string(35) "new element added $innerArrayObject" + ["new.oAO"]=> + string(38) "new element added to $outerArrayObject" + } + } +} +object(ArrayObject)#4 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["p"]=> + string(9) "C::p.orig" + ["dynamic1"]=> + string(45) "new prop added to $wrappedObject before clone" + ["new.coAO"]=> + string(44) "new element added to $clonedOuterArrayObject" + } +} diff --git a/ext/spl/tests/arrayObject_count_basic1.phpt b/ext/spl/tests/arrayObject_count_basic1.phpt new file mode 100644 index 0000000..a003c2c --- /dev/null +++ b/ext/spl/tests/arrayObject_count_basic1.phpt @@ -0,0 +1,84 @@ +--TEST-- +SPL: ArrayObject::count() and ArrayIterator::count() basic functionality. +--FILE-- +==ArrayObject== +<?php +class C extends ArrayObject { + function count() { + return 99; + } +} + +$c = new C; +$ao = new ArrayObject; + +var_dump(count($c), count($ao)); + +$c[] = 'a'; +$ao[] = 'a'; +var_dump(count($c), count($ao)); + +$c[] = 'b'; +$ao[] = 'b'; +var_dump(count($c), count($ao)); + +unset($c[0]); +unset($ao[0]); +var_dump($c->count(), $ao->count()); + +//Extra args are ignored. +var_dump($ao->count('blah')); +?> +==ArrayIterator== +<?php +class D extends ArrayIterator { + function count() { + return 99; + } +} + +$c = new D; +$ao = new ArrayIterator; + +var_dump(count($c), count($ao)); + +$c[] = 'a'; +$ao[] = 'a'; +var_dump(count($c), count($ao)); + +$c[] = 'b'; +$ao[] = 'b'; +var_dump(count($c), count($ao)); + +unset($c[0]); +unset($ao[0]); +var_dump($c->count(), $ao->count()); + +//Extra args are ignored. +var_dump($ao->count('blah')); +?> +--EXPECTF-- +==ArrayObject== +int(99) +int(0) +int(99) +int(1) +int(99) +int(2) +int(99) +int(1) + +Warning: ArrayObject::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL +==ArrayIterator== +int(99) +int(0) +int(99) +int(1) +int(99) +int(2) +int(99) +int(1) + +Warning: ArrayIterator::count() expects exactly 0 parameters, 1 given in %s on line %d +NULL
\ No newline at end of file diff --git a/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt b/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt new file mode 100644 index 0000000..988f103 --- /dev/null +++ b/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt @@ -0,0 +1,40 @@ +--TEST-- +SPL: ArrayObject::exchangeArray() and copy-on-write references +--FILE-- +<?php +$ao = new ArrayObject(); +$swapIn = array(); +$cowRef = $swapIn; // create a copy-on-write ref to $swapIn +$ao->exchangeArray($swapIn); + +$ao['a'] = 'adding element to $ao'; +$swapIn['b'] = 'adding element to $swapIn'; +$ao['c'] = 'adding another element to $ao'; + +echo "\n--> swapIn: "; +var_dump($swapIn); + +echo "\n--> cowRef: "; +var_dump($cowRef); + +echo "\n--> ao: "; +var_dump($ao); +?> +--EXPECTF-- +--> swapIn: array(1) { + ["b"]=> + string(25) "adding element to $swapIn" +} + +--> cowRef: array(0) { +} + +--> ao: object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["a"]=> + string(21) "adding element to $ao" + ["c"]=> + string(29) "adding another element to $ao" + } +} diff --git a/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt b/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt new file mode 100644 index 0000000..c7f1b3a --- /dev/null +++ b/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt @@ -0,0 +1,97 @@ +--TEST-- +SPL: ArrayObject::exchangeArray() with various object arguments +--FILE-- +<?php +echo "--> exchangeArray(array):\n"; +$ao = new ArrayObject(); +$ao->exchangeArray(array('key'=>'original')); +var_dump($ao['key']); +var_dump($ao); + +echo "\n--> exchangeArray(normal object):\n"; +$obj = new stdClass; +$obj->key = 'normal object prop'; +$ao->exchangeArray($obj); +var_dump($ao['key']); +var_dump($ao); + +echo "\n--> exchangeArray(ArrayObject):\n"; +$obj = new ArrayObject(array('key'=>'ArrayObject element')); +$ao->exchangeArray($obj); +var_dump($ao['key']); +var_dump($ao); + +echo "\n--> exchangeArray(ArrayIterator):\n"; +$obj = new ArrayIterator(array('key'=>'ArrayIterator element')); +$ao->exchangeArray($obj); +var_dump($ao['key']); +var_dump($ao); + +echo "\n--> exchangeArray(nested ArrayObject):\n"; +$obj = new ArrayObject(new ArrayObject(array('key'=>'nested ArrayObject element'))); +$ao->exchangeArray($obj); +var_dump($ao['key']); +var_dump($ao); +?> +--EXPECTF-- +--> exchangeArray(array): +string(8) "original" +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["key"]=> + string(8) "original" + } +} + +--> exchangeArray(normal object): +string(18) "normal object prop" +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(stdClass)#%d (1) { + ["key"]=> + string(18) "normal object prop" + } +} + +--> exchangeArray(ArrayObject): +string(19) "ArrayObject element" +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["key"]=> + string(19) "ArrayObject element" + } + } +} + +--> exchangeArray(ArrayIterator): +string(21) "ArrayIterator element" +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(ArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(1) { + ["key"]=> + string(21) "ArrayIterator element" + } + } +} + +--> exchangeArray(nested ArrayObject): +string(26) "nested ArrayObject element" +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["key"]=> + string(26) "nested ArrayObject element" + } + } + } +}
\ No newline at end of file diff --git a/ext/spl/tests/arrayObject_exchangeArray_basic3.phpt b/ext/spl/tests/arrayObject_exchangeArray_basic3.phpt new file mode 100644 index 0000000..4045b7a --- /dev/null +++ b/ext/spl/tests/arrayObject_exchangeArray_basic3.phpt @@ -0,0 +1,128 @@ +--TEST-- +SPL: ArrayObject::exchangeArray() basic usage with object as underlying data store. +--FILE-- +<?php + +class C { + public $pub1 = 'public1'; +} + +echo "--> exchangeArray() with objects:\n"; +$original = new C; +$ao = new ArrayObject($original); +$swapIn = new C; +try { + $copy = $ao->exchangeArray($swapIn); + $copy['addedToCopy'] = 'added To Copy'; +} catch (Exception $e) { + echo "Exception:" . $e->getMessage() . "\n"; +} +$swapIn->addedToSwapIn = 'added To Swap-In'; +$original->addedToOriginal = 'added To Original'; +var_dump($ao, $original, $swapIn, $copy); + + +echo "\n\n--> exchangeArray() with no arg:\n"; +unset($original, $ao, $swapIn, $copy); +$original = new C; +$ao = new ArrayObject($original); +try { + $copy = $ao->exchangeArray(); + $copy['addedToCopy'] = 'added To Copy'; +} catch (Exception $e) { + echo "Exception:" . $e->getMessage() . "\n"; +} +$original->addedToOriginal = 'added To Original'; +var_dump($ao, $original, $copy); + +echo "\n\n--> exchangeArray() with bad arg type:\n"; +unset($original, $ao, $swapIn, $copy); +$original = new C; +$ao = new ArrayObject($original); +try { + $copy = $ao->exchangeArray(null); + $copy['addedToCopy'] = 'added To Copy'; +} catch (Exception $e) { + echo "Exception:" . $e->getMessage() . "\n"; +} +$original->addedToOriginal = 'added To Original'; +var_dump($ao, $original, $copy); + +?> +--EXPECTF-- +--> exchangeArray() with objects: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#3 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToSwapIn"]=> + string(16) "added To Swap-In" + } +} +object(C)#1 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToOriginal"]=> + string(17) "added To Original" +} +object(C)#3 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToSwapIn"]=> + string(16) "added To Swap-In" +} +array(2) { + ["pub1"]=> + string(7) "public1" + ["addedToCopy"]=> + string(13) "added To Copy" +} + + +--> exchangeArray() with no arg: + +Warning: ArrayObject::exchangeArray() expects exactly 1 parameter, 0 given in %s on line 27 +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#3 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToOriginal"]=> + string(17) "added To Original" + } +} +object(C)#3 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToOriginal"]=> + string(17) "added To Original" +} +array(2) { + ["pub1"]=> + string(7) "public1" + ["addedToCopy"]=> + string(13) "added To Copy" +} + + +--> exchangeArray() with bad arg type: +Exception:Passed variable is not an array or object, using empty array instead + +Notice: Undefined variable: copy in %s on line 46 +object(ArrayObject)#3 (1) { + ["storage":"ArrayObject":private]=> + object(C)#2 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToOriginal"]=> + string(17) "added To Original" + } +} +object(C)#2 (2) { + ["pub1"]=> + string(7) "public1" + ["addedToOriginal"]=> + string(17) "added To Original" +} +NULL diff --git a/ext/spl/tests/arrayObject_getFlags_basic1.phpt b/ext/spl/tests/arrayObject_getFlags_basic1.phpt new file mode 100644 index 0000000..b078c51 --- /dev/null +++ b/ext/spl/tests/arrayObject_getFlags_basic1.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: ArrayObject::getFlags() basic usage +--FILE-- +<?php +$ao = new ArrayObject(new ArrayObject(new stdClass)); +var_dump($ao->getFlags()); + +$ao = new ArrayObject(new ArrayObject(array(1,2,3)), ArrayObject::STD_PROP_LIST); +var_dump($ao->getFlags()); + +$ao = new ArrayObject(new ArrayIterator(new ArrayObject()), ArrayObject::ARRAY_AS_PROPS); +var_dump($ao->getFlags()); + +$ao = new ArrayObject(new ArrayObject(), ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS); +var_dump($ao->getFlags()); + +$cao = clone $ao; +var_dump($cao->getFlags()); +?> +--EXPECTF-- +int(0) +int(1) +int(2) +int(3) +int(3)
\ No newline at end of file diff --git a/ext/spl/tests/arrayObject_getFlags_basic2.phpt b/ext/spl/tests/arrayObject_getFlags_basic2.phpt new file mode 100644 index 0000000..f7d56ea --- /dev/null +++ b/ext/spl/tests/arrayObject_getFlags_basic2.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: ArrayObject::getFlags() - ensure flags are passed on to nested array objects and iterators. +--FILE-- +<?php +$ao = new ArrayObject(array(), ArrayObject::STD_PROP_LIST|ArrayObject::ARRAY_AS_PROPS); +var_dump($ao->getFlags()); + +$ao2 = new ArrayObject($ao); +var_dump($ao2->getFlags()); +var_dump($ao2->getIterator()->getFlags()); + +$ai = new ArrayIterator($ao); +var_dump($ai->getFlags()); + +$ao2 = new ArrayObject($ao, 0); +var_dump($ao2->getFlags()); + +?> +--EXPECTF-- +int(3) +int(3) +int(3) +int(3) +int(0)
\ No newline at end of file diff --git a/ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt b/ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt new file mode 100644 index 0000000..b23c196 --- /dev/null +++ b/ext/spl/tests/arrayObject_getIteratorClass_basic1.phpt @@ -0,0 +1,116 @@ +--TEST-- +SPL: ArrayObject::getIteratorClass and ArrayObject::setIteratorClass basic functionality +--FILE-- +<?php +class MyIterator extends ArrayIterator { + + function __construct() { + $args = func_get_args(); + echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + + function rewind() { + $args = func_get_args(); + echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + return parent::rewind(); + } + + function valid() { + $args = func_get_args(); + echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + return parent::valid(); + } + + function current() { + $args = func_get_args(); + echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + return parent::current(); + } + + function next() { + $args = func_get_args(); + echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + return parent::next(); + } + + function key() { + $args = func_get_args(); + echo " In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + return parent::key(); + } +} + +$ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3), 0, "MyIterator"); + +echo "--> Access using MyIterator:\n"; +var_dump($ao->getIteratorClass()); +var_dump($ao->getIterator()); +foreach($ao as $key=>$value) { + echo " $key=>$value\n"; +} + +echo "\n\n--> Access using ArrayIterator:\n"; +var_dump($ao->setIteratorClass("ArrayIterator")); +var_dump($ao->getIteratorClass()); +var_dump($ao->getIterator()); +foreach($ao as $key=>$value) { + echo "$key=>$value\n"; +} + +?> +--EXPECTF-- +--> Access using MyIterator: +string(10) "MyIterator" +object(MyIterator)#2 (1) { + ["storage":"ArrayIterator":private]=> + object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + } + } +} + In MyIterator::rewind() + In MyIterator::valid() + In MyIterator::current() + In MyIterator::key() + a=>1 + In MyIterator::next() + In MyIterator::valid() + In MyIterator::current() + In MyIterator::key() + b=>2 + In MyIterator::next() + In MyIterator::valid() + In MyIterator::current() + In MyIterator::key() + c=>3 + In MyIterator::next() + In MyIterator::valid() + + +--> Access using ArrayIterator: +NULL +string(13) "ArrayIterator" +object(ArrayIterator)#3 (1) { + ["storage":"ArrayIterator":private]=> + object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + } + } +} +a=>1 +b=>2 +c=>3 diff --git a/ext/spl/tests/arrayObject_ksort_basic1.phpt b/ext/spl/tests/arrayObject_ksort_basic1.phpt new file mode 100644 index 0000000..8f37938 --- /dev/null +++ b/ext/spl/tests/arrayObject_ksort_basic1.phpt @@ -0,0 +1,67 @@ +--TEST-- +SPL: Test ArrayObject::ksort() function : basic functionality with array based store +--FILE-- +<?php +/* Prototype : int ArrayObject::ksort() + * Description: proto int ArrayIterator::ksort() + * Sort the entries by key. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::ksort() : basic functionality ***\n"; +$ao1 = new ArrayObject(array(4,2,3)); +$ao2 = new ArrayObject(array('b'=>4,'a'=>2,'q'=>3, 99=>'x')); +var_dump($ao1->ksort()); +var_dump($ao1); +var_dump($ao2->ksort('blah')); +var_dump($ao2); +var_dump($ao2->ksort(SORT_STRING)); +var_dump($ao2); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::ksort() : basic functionality *** +bool(true) +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(4) + [1]=> + int(2) + [2]=> + int(3) + } +} + +Warning: ksort() expects parameter 2 to be long, string given in %sarrayObject_ksort_basic1.php on line %d +bool(false) +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + array(4) { + ["b"]=> + int(4) + ["a"]=> + int(2) + ["q"]=> + int(3) + [99]=> + string(1) "x" + } +} +bool(true) +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(4) { + [99]=> + string(1) "x" + ["a"]=> + int(2) + ["b"]=> + int(4) + ["q"]=> + int(3) + } +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_ksort_basic2.phpt b/ext/spl/tests/arrayObject_ksort_basic2.phpt new file mode 100644 index 0000000..1464e73 --- /dev/null +++ b/ext/spl/tests/arrayObject_ksort_basic2.phpt @@ -0,0 +1,52 @@ +--TEST-- +SPL: Test ArrayObject::ksort() function : basic functionality with object base store +--FILE-- +<?php +/* Prototype : int ArrayObject::ksort() + * Description: proto int ArrayIterator::ksort() + * Sort the entries by key. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::ksort() : basic functionality ***\n"; +Class C { + public $x = 'prop1'; + public $z = 'prop2'; + public $a = 'prop3'; + private $b = 'prop4'; +} + +$c = new C; +$ao1 = new ArrayObject($c); +var_dump($ao1->ksort()); +var_dump($ao1, $c); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::ksort() : basic functionality *** +bool(true) +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(C)#1 (4) { + ["b":"C":private]=> + string(5) "prop4" + ["a"]=> + string(5) "prop3" + ["x"]=> + string(5) "prop1" + ["z"]=> + string(5) "prop2" + } +} +object(C)#1 (4) { + ["b":"C":private]=> + string(5) "prop4" + ["a"]=> + string(5) "prop3" + ["x"]=> + string(5) "prop1" + ["z"]=> + string(5) "prop2" +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_magicMethods1.phpt b/ext/spl/tests/arrayObject_magicMethods1.phpt new file mode 100644 index 0000000..ec4812f --- /dev/null +++ b/ext/spl/tests/arrayObject_magicMethods1.phpt @@ -0,0 +1,195 @@ +--TEST-- +SPL: ArrayObject: ensure a wrapped object's magic methods for property access are not invoked when manipulating the ArrayObject's elements using []. +--FILE-- +<?php +class UsesMagic { + public $a = 1; + public $b = 2; + public $c = 3; + + private $priv = 'secret'; + + function __get($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __set($name, $value) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __isset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __unset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + +} + +$obj = new UsesMagic; + +$ao = new ArrayObject($obj); +echo "\n--> Write existent, non-existent and dynamic:\n"; +$ao['a'] = 'changed'; +$ao['dynamic'] = 'new'; +$ao['dynamic'] = 'new.changed'; +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Read existent, non-existent and dynamic:\n"; +var_dump($ao['a']); +var_dump($ao['nonexistent']); +var_dump($ao['dynamic']); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> isset existent, non-existent and dynamic:\n"; +var_dump(isset($ao['a'])); +var_dump(isset($ao['nonexistent'])); +var_dump(isset($ao['dynamic'])); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Unset existent, non-existent and dynamic:\n"; +unset($ao['a']); +unset($ao['nonexistent']); +unset($ao['dynamic']); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); +?> +--EXPECTF-- +--> Write existent, non-existent and dynamic: + Original wrapped object: +object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Read existent, non-existent and dynamic: +string(7) "changed" + +Notice: Undefined index: nonexistent in %s on line 42 +NULL +string(11) "new.changed" + Original wrapped object: +object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> isset existent, non-existent and dynamic: +bool(true) +bool(false) +bool(true) + Original wrapped object: +object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Unset existent, non-existent and dynamic: + +Notice: Undefined index: nonexistent in %s on line 60 + Original wrapped object: +object(UsesMagic)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + } +} diff --git a/ext/spl/tests/arrayObject_magicMethods2.phpt b/ext/spl/tests/arrayObject_magicMethods2.phpt new file mode 100644 index 0000000..691a9a1 --- /dev/null +++ b/ext/spl/tests/arrayObject_magicMethods2.phpt @@ -0,0 +1,197 @@ +--TEST-- +SPL: ArrayObject: ensure a wrapped object's magic methods for property access are not invoked when manipulating the ArrayObject's elements using ->. +--FILE-- +<?php +class UsesMagic { + public $a = 1; + public $b = 2; + public $c = 3; + + private $priv = 'secret'; + + function __get($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __set($name, $value) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __isset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __unset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + +} + +$obj = new UsesMagic; + +$ao = new ArrayObject($obj); +echo "\n--> Write existent, non-existent and dynamic:\n"; +$ao->a = 'changed'; +$ao->dynamic = 'new'; +$ao->dynamic = 'new.changed'; +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Read existent, non-existent and dynamic:\n"; +var_dump($ao->a); +var_dump($ao->nonexistent); +var_dump($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> isset existent, non-existent and dynamic:\n"; +var_dump(isset($ao->a)); +var_dump(isset($ao->nonexistent)); +var_dump(isset($ao->dynamic)); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Unset existent, non-existent and dynamic:\n"; +unset($ao->a); +unset($ao->nonexistent); +unset($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); +?> +--EXPECTF-- +--> Write existent, non-existent and dynamic: + Original wrapped object: +object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (3) { + ["a"]=> + string(7) "changed" + ["dynamic"]=> + string(11) "new.changed" + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + } +} + +--> Read existent, non-existent and dynamic: +string(7) "changed" + +Notice: Undefined property: ArrayObject::$nonexistent in %s on line 42 +NULL +string(11) "new.changed" + Original wrapped object: +object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (3) { + ["a"]=> + string(7) "changed" + ["dynamic"]=> + string(11) "new.changed" + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + } +} + +--> isset existent, non-existent and dynamic: +bool(true) +bool(false) +bool(true) + Original wrapped object: +object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (3) { + ["a"]=> + string(7) "changed" + ["dynamic"]=> + string(11) "new.changed" + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + } +} + +--> Unset existent, non-existent and dynamic: + Original wrapped object: +object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + } +} diff --git a/ext/spl/tests/arrayObject_magicMethods3.phpt b/ext/spl/tests/arrayObject_magicMethods3.phpt new file mode 100644 index 0000000..6231cea --- /dev/null +++ b/ext/spl/tests/arrayObject_magicMethods3.phpt @@ -0,0 +1,195 @@ +--TEST-- +SPL: ArrayObject: ensure a wrapped object's magic methods for property access are not invoked when manipulating the ArrayObject's elements using -> and ArrayObject::ARRAY_AS_PROPS. +--FILE-- +<?php +class UsesMagic { + public $a = 1; + public $b = 2; + public $c = 3; + + private $priv = 'secret'; + + function __get($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __set($name, $value) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __isset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __unset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + +} + +$obj = new UsesMagic; + +$ao = new ArrayObject($obj, ArrayObject::ARRAY_AS_PROPS); +echo "\n--> Write existent, non-existent and dynamic:\n"; +$ao->a = 'changed'; +$ao->dynamic = 'new'; +$ao->dynamic = 'new.changed'; +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Read existent, non-existent and dynamic:\n"; +var_dump($ao->a); +var_dump($ao->nonexistent); +var_dump($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> isset existent, non-existent and dynamic:\n"; +var_dump(isset($ao->a)); +var_dump(isset($ao->nonexistent)); +var_dump(isset($ao->dynamic)); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Unset existent, non-existent and dynamic:\n"; +unset($ao->a); +unset($ao->nonexistent); +unset($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); +?> +--EXPECTF-- +--> Write existent, non-existent and dynamic: + Original wrapped object: +object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Read existent, non-existent and dynamic: +string(7) "changed" + +Notice: Undefined index: nonexistent in %s on line 42 +NULL +string(11) "new.changed" + Original wrapped object: +object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> isset existent, non-existent and dynamic: +bool(true) +bool(false) +bool(true) + Original wrapped object: +object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Unset existent, non-existent and dynamic: + +Notice: Undefined index: nonexistent in %s on line 60 + Original wrapped object: +object(UsesMagic)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + object(UsesMagic)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"UsesMagic":private]=> + string(6) "secret" + } +} diff --git a/ext/spl/tests/arrayObject_magicMethods4.phpt b/ext/spl/tests/arrayObject_magicMethods4.phpt new file mode 100644 index 0000000..9580dc5 --- /dev/null +++ b/ext/spl/tests/arrayObject_magicMethods4.phpt @@ -0,0 +1,206 @@ +--TEST-- +SPL: ArrayObject: ensure the magic methods for property access of a subclass of ArrayObject are not invoked when manipulating its elements using []. +--FILE-- +<?php +class C { + public $a = 1; + public $b = 2; + public $c = 3; + + private $priv = 'secret'; +} + +class UsesMagic extends ArrayObject { + + public $b = "This should not be in the storage"; + + function __get($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __set($name, $value) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __isset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __unset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + +} +$obj = new C; +$ao = new UsesMagic($obj); +echo "\n--> Write existent, non-existent and dynamic:\n"; +$ao['a'] = 'changed'; +$ao['dynamic'] = 'new'; +$ao['dynamic'] = 'new.changed'; +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Read existent, non-existent and dynamic:\n"; +var_dump($ao['a']); +var_dump($ao['nonexistent']); +var_dump($ao['dynamic']); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> isset existent, non-existent and dynamic:\n"; +var_dump(isset($ao['a'])); +var_dump(isset($ao['nonexistent'])); +var_dump(isset($ao['dynamic'])); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Unset existent, non-existent and dynamic:\n"; +unset($ao['a']); +unset($ao['nonexistent']); +unset($ao['dynamic']); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); +?> +--EXPECTF-- +--> Write existent, non-existent and dynamic: + Original wrapped object: +object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(33) "This should not be in the storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Read existent, non-existent and dynamic: +string(7) "changed" + +Notice: Undefined index: nonexistent in %s on line 45 +NULL +string(11) "new.changed" + Original wrapped object: +object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(33) "This should not be in the storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> isset existent, non-existent and dynamic: +bool(true) +bool(false) +bool(true) + Original wrapped object: +object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(33) "This should not be in the storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Unset existent, non-existent and dynamic: + +Notice: Undefined index: nonexistent in %s on line 63 + Original wrapped object: +object(C)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(33) "This should not be in the storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + } +} diff --git a/ext/spl/tests/arrayObject_magicMethods5.phpt b/ext/spl/tests/arrayObject_magicMethods5.phpt new file mode 100644 index 0000000..023086d --- /dev/null +++ b/ext/spl/tests/arrayObject_magicMethods5.phpt @@ -0,0 +1,206 @@ +--TEST-- +SPL: ArrayObject: ensure the magic methods for property access of a subclass of ArrayObject ARE invoked when manipulating its elements using ->. +--FILE-- +<?php +class C { + public $a = 1; + public $b = 2; + public $c = 3; + + private $priv = 'secret'; +} + +class UsesMagic extends ArrayObject { + + public $b = "This should appear in storage"; + + function __get($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __set($name, $value) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __isset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __unset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + +} +$obj = new C; +$ao = new UsesMagic($obj); +echo "\n--> Write existent, non-existent and dynamic:\n"; +$ao->a = 'changed'; +$ao->dynamic = 'new'; +$ao->dynamic = 'new.changed'; +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Read existent, non-existent and dynamic:\n"; +var_dump($ao->a); +var_dump($ao->nonexistent); +var_dump($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> isset existent, non-existent and dynamic:\n"; +var_dump(isset($ao->a)); +var_dump(isset($ao->nonexistent)); +var_dump(isset($ao->dynamic)); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Unset existent, non-existent and dynamic:\n"; +unset($ao->a); +unset($ao->nonexistent); +unset($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); +?> +--EXPECTF-- +--> Write existent, non-existent and dynamic: +In UsesMagic::__set(a,changed) +In UsesMagic::__set(dynamic,new) +In UsesMagic::__set(dynamic,new.changed) + Original wrapped object: +object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(29) "This should appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + } +} + +--> Read existent, non-existent and dynamic: +In UsesMagic::__get(a) +NULL +In UsesMagic::__get(nonexistent) +NULL +In UsesMagic::__get(dynamic) +NULL + Original wrapped object: +object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(29) "This should appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + } +} + +--> isset existent, non-existent and dynamic: +In UsesMagic::__isset(a) +bool(false) +In UsesMagic::__isset(nonexistent) +bool(false) +In UsesMagic::__isset(dynamic) +bool(false) + Original wrapped object: +object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(29) "This should appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + } +} + +--> Unset existent, non-existent and dynamic: +In UsesMagic::__unset(a) +In UsesMagic::__unset(nonexistent) +In UsesMagic::__unset(dynamic) + Original wrapped object: +object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(29) "This should appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (4) { + ["a"]=> + int(1) + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + } +} diff --git a/ext/spl/tests/arrayObject_magicMethods6.phpt b/ext/spl/tests/arrayObject_magicMethods6.phpt new file mode 100644 index 0000000..b43f56c --- /dev/null +++ b/ext/spl/tests/arrayObject_magicMethods6.phpt @@ -0,0 +1,206 @@ +--TEST-- +SPL: ArrayObject: ensure the magic methods for property access of a subclass of ArrayObject are not invoked when manipulating its elements using -> ArrayObject::ARRAY_AS_PROPS. +--FILE-- +<?php +class C { + public $a = 1; + public $b = 2; + public $c = 3; + + private $priv = 'secret'; +} + +class UsesMagic extends ArrayObject { + + public $b = "This should never appear in storage"; + + function __get($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __set($name, $value) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __isset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + function __unset($name) { + $args = func_get_args(); + echo "In " . __METHOD__ . "(" . implode($args, ',') . ")\n"; + } + +} +$obj = new C; +$ao = new UsesMagic($obj, ArrayObject::ARRAY_AS_PROPS); +echo "\n--> Write existent, non-existent and dynamic:\n"; +$ao->a = 'changed'; +$ao->dynamic = 'new'; +$ao->dynamic = 'new.changed'; +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Read existent, non-existent and dynamic:\n"; +var_dump($ao->a); +var_dump($ao->nonexistent); +var_dump($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> isset existent, non-existent and dynamic:\n"; +var_dump(isset($ao->a)); +var_dump(isset($ao->nonexistent)); +var_dump(isset($ao->dynamic)); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); + +echo "\n--> Unset existent, non-existent and dynamic:\n"; +unset($ao->a); +unset($ao->nonexistent); +unset($ao->dynamic); +echo " Original wrapped object:\n"; +var_dump($obj); +echo " Wrapping ArrayObject:\n"; +var_dump($ao); +?> +--EXPECTF-- +--> Write existent, non-existent and dynamic: + Original wrapped object: +object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(35) "This should never appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Read existent, non-existent and dynamic: +string(7) "changed" + +Notice: Undefined index: nonexistent in %s on line 45 +NULL +string(11) "new.changed" + Original wrapped object: +object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(35) "This should never appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> isset existent, non-existent and dynamic: +bool(true) +bool(false) +bool(true) + Original wrapped object: +object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(35) "This should never appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (5) { + ["a"]=> + string(7) "changed" + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + ["dynamic"]=> + string(11) "new.changed" + } +} + +--> Unset existent, non-existent and dynamic: + +Notice: Undefined index: nonexistent in %s on line 63 + Original wrapped object: +object(C)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" +} + Wrapping ArrayObject: +object(UsesMagic)#2 (2) { + ["b"]=> + string(35) "This should never appear in storage" + ["storage":"ArrayObject":private]=> + object(C)#1 (3) { + ["b"]=> + int(2) + ["c"]=> + int(3) + ["priv":"C":private]=> + string(6) "secret" + } +} diff --git a/ext/spl/tests/arrayObject_natcasesort_basic1.phpt b/ext/spl/tests/arrayObject_natcasesort_basic1.phpt new file mode 100644 index 0000000..62ad2ed --- /dev/null +++ b/ext/spl/tests/arrayObject_natcasesort_basic1.phpt @@ -0,0 +1,56 @@ +--TEST-- +SPL: Test ArrayObject::natcasesort() function : basic functionality +--FILE-- +<?php +/* Prototype : int ArrayObject::natcasesort() + * Description: proto int ArrayIterator::natcasesort() + Sort the entries by values using case insensitive "natural order" algorithm. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::natcasesort() : basic functionality ***\n"; + +$ao1 = new ArrayObject(array('boo10','boo1','boo2','boo22','BOO5')); +$ao2 = new ArrayObject(array('a'=>'boo10','b'=>'boo1','c'=>'boo2','d'=>'boo22','e'=>'BOO5')); +var_dump($ao1->natcasesort()); +var_dump($ao1); +var_dump($ao2->natcasesort('blah')); +var_dump($ao2); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::natcasesort() : basic functionality *** +bool(true) +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + [1]=> + string(4) "boo1" + [2]=> + string(4) "boo2" + [4]=> + string(4) "BOO5" + [0]=> + string(5) "boo10" + [3]=> + string(5) "boo22" + } +} +bool(true) +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + ["b"]=> + string(4) "boo1" + ["c"]=> + string(4) "boo2" + ["e"]=> + string(4) "BOO5" + ["a"]=> + string(5) "boo10" + ["d"]=> + string(5) "boo22" + } +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_natsort_basic1.phpt b/ext/spl/tests/arrayObject_natsort_basic1.phpt new file mode 100644 index 0000000..1b4fd60 --- /dev/null +++ b/ext/spl/tests/arrayObject_natsort_basic1.phpt @@ -0,0 +1,57 @@ +--TEST-- +SPL: Test ArrayObject::natsort() function : basic functionality +--FILE-- +<?php +/* Prototype : int ArrayObject::natsort() + * Description: proto int ArrayIterator::natsort() + Sort the entries by values using "natural order" algorithm. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::natsort() : basic functionality ***\n"; + +$ao1 = new ArrayObject(array('boo10','boo1','boo2','boo22','BOO5')); +$ao2 = new ArrayObject(array('a'=>'boo10','b'=>'boo1','c'=>'boo2','d'=>'boo22','e'=>'BOO5')); +var_dump($ao1->natsort()); +var_dump($ao1); +var_dump($ao2->natsort('blah')); +var_dump($ao2); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::natsort() : basic functionality *** +bool(true) +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + [4]=> + string(4) "BOO5" + [1]=> + string(4) "boo1" + [2]=> + string(4) "boo2" + [0]=> + string(5) "boo10" + [3]=> + string(5) "boo22" + } +} +bool(true) +object(ArrayObject)#2 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + ["e"]=> + string(4) "BOO5" + ["b"]=> + string(4) "boo1" + ["c"]=> + string(4) "boo2" + ["a"]=> + string(5) "boo10" + ["d"]=> + string(5) "boo22" + } +} +===DONE=== + diff --git a/ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt b/ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt new file mode 100644 index 0000000..1953643 --- /dev/null +++ b/ext/spl/tests/arrayObject_offsetExists_nullcheck.phpt @@ -0,0 +1,10 @@ +--TEST-- +SPL: ArrayObject::offsetExists() should return true for element containing NULL +--FILE-- +<?php +$ao = new ArrayObject(array('foo' => null)); +var_dump($ao->offsetExists('foo')); + +?> +--EXPECTF-- +bool(true)
\ No newline at end of file diff --git a/ext/spl/tests/arrayObject_setFlags_basic1.phpt b/ext/spl/tests/arrayObject_setFlags_basic1.phpt new file mode 100644 index 0000000..391b0ee --- /dev/null +++ b/ext/spl/tests/arrayObject_setFlags_basic1.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: ArrayObject::setFlags basic usage with ArrayObject::ARRAY_AS_PROPS. Currently fails on php.net due to bug 45622. +--FILE-- +<?php +class C extends ArrayObject { + public $p = 'object property'; +} + +function access_p($ao) { + // isset + var_dump(isset($ao->p)); + // read + var_dump($ao->p); + // write + $ao->p = $ao->p . '.changed'; + var_dump($ao->p); +} + +$ao = new C(array('p'=>'array element')); +$ao->setFlags(ArrayObject::ARRAY_AS_PROPS); + +echo "\n--> Access the real property:\n"; +access_p($ao); + +echo "\n--> Remove the real property and access the array element:\n"; +unset($ao->p); +access_p($ao); + +echo "\n--> Remove the array element and try access again:\n"; +unset($ao->p); +access_p($ao); +?> +--EXPECTF-- +--> Access the real property: +bool(true) +string(15) "object property" +string(23) "object property.changed" + +--> Remove the real property and access the array element: +bool(true) +string(13) "array element" +string(21) "array element.changed" + +--> Remove the array element and try access again: +bool(false) + +Notice: Undefined index: p in %s on line 10 +NULL + +Notice: Undefined index: p in %s on line 12 +string(8) ".changed" diff --git a/ext/spl/tests/arrayObject_setFlags_basic2.phpt b/ext/spl/tests/arrayObject_setFlags_basic2.phpt new file mode 100644 index 0000000..806f812 --- /dev/null +++ b/ext/spl/tests/arrayObject_setFlags_basic2.phpt @@ -0,0 +1,29 @@ +--TEST-- +SPL: Ensure access to non-visible properties falls back to dimension access with ArrayObject::ARRAY_AS_PROPS. +--FILE-- +<?php +class C extends ArrayObject { + private $x = 'secret'; + + static function go($c) { + var_dump($c->x); + } +} + +$c = new C(array('x'=>'public')); + +$c->setFlags(ArrayObject::ARRAY_AS_PROPS); +C::go($c); +var_dump($c->x); + + +$c->setFlags(0); +C::go($c); +var_dump($c->x); +?> +--EXPECTF-- +string(6) "secret" +string(6) "public" +string(6) "secret" + +Fatal error: Cannot access private property C::$x in %s on line 19 diff --git a/ext/spl/tests/arrayObject_setIteratorClass_error1.phpt b/ext/spl/tests/arrayObject_setIteratorClass_error1.phpt new file mode 100644 index 0000000..4715eea --- /dev/null +++ b/ext/spl/tests/arrayObject_setIteratorClass_error1.phpt @@ -0,0 +1,56 @@ +--TEST-- +SPL: ArrayObject with bad iterator class. +--FILE-- +<?php +try { + $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3)); + $ao->setIteratorClass("nonExistentClass"); + foreach($ao as $key=>$value) { + echo " $key=>$value\n"; + } +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +try { + $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3)); + $ao->setIteratorClass("stdClass"); + foreach($ao as $key=>$value) { + echo " $key=>$value\n"; + } +} catch (Exception $e) { + var_dump($e->getMessage()); +} + + +try { + $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3), 0, "nonExistentClass"); + foreach($ao as $key=>$value) { + echo " $key=>$value\n"; + } +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +try { + $ao = new ArrayObject(array('a'=>1,'b'=>2,'c'=>3), 0, "stdClass"); + foreach($ao as $key=>$value) { + echo " $key=>$value\n"; + } +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +?> +--EXPECTF-- +Warning: ArrayObject::setIteratorClass() expects parameter 1 to be a class name derived from Iterator, 'nonExistentClass' given in %s on line 4 + a=>1 + b=>2 + c=>3 + +Warning: ArrayObject::setIteratorClass() expects parameter 1 to be a class name derived from Iterator, 'stdClass' given in %s on line 14 + a=>1 + b=>2 + c=>3 +string(113) "ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'nonExistentClass' given" +string(105) "ArrayObject::__construct() expects parameter 3 to be a class name derived from Iterator, 'stdClass' given" diff --git a/ext/spl/tests/arrayObject_uasort_basic1.phpt b/ext/spl/tests/arrayObject_uasort_basic1.phpt new file mode 100644 index 0000000..203edb6 --- /dev/null +++ b/ext/spl/tests/arrayObject_uasort_basic1.phpt @@ -0,0 +1,44 @@ +--TEST-- +SPL: Test ArrayObject::uasort() function : basic functionality +--FILE-- +<?php +/* Prototype : int ArrayObject::uasort(callback cmp_function) + * Description: proto int ArrayIterator::uasort(callback cmp_function) + Sort the entries by values user defined function. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::uasort() : basic functionality ***\n"; + +// Reverse sorter +function cmp($value1, $value2) { + if($value1 == $value2) { + return 0; + } + else if($value1 < $value2) { + return 1; + } + else + return -1; +} +$ao = new ArrayObject(array(2,3,1)); + +$ao->uasort('cmp'); +var_dump($ao); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::uasort() : basic functionality *** +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(3) { + [1]=> + int(3) + [0]=> + int(2) + [2]=> + int(1) + } +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_uasort_error1.phpt b/ext/spl/tests/arrayObject_uasort_error1.phpt new file mode 100644 index 0000000..d7306c9 --- /dev/null +++ b/ext/spl/tests/arrayObject_uasort_error1.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test ArrayObject::uasort() function : wrong arg count +--FILE-- +<?php +/* Prototype : int ArrayObject::uasort(callback cmp_function) + * Description: proto int ArrayIterator::uasort(callback cmp_function) + Sort the entries by values user defined function. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +$ao = new ArrayObject(); + +try { + $ao->uasort(); +} catch (BadMethodCallException $e) { + echo $e->getMessage() . "\n"; +} + +try { + $ao->uasort(1,2); +} catch (BadMethodCallException $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +Function expects exactly one argument +Function expects exactly one argument +===DONE=== diff --git a/ext/spl/tests/arrayObject_uksort_basic1.phpt b/ext/spl/tests/arrayObject_uksort_basic1.phpt new file mode 100644 index 0000000..1581589 --- /dev/null +++ b/ext/spl/tests/arrayObject_uksort_basic1.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test ArrayObject::uksort() function : basic functionality +--FILE-- +<?php +/* Prototype : int ArrayObject::uksort(callback cmp_function) + * Description: proto int ArrayIterator::uksort(callback cmp_function) + * Sort the entries by key using user defined function. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +echo "*** Testing ArrayObject::uksort() : basic functionality ***\n"; +// Reverse sorter +function cmp($value1, $value2) { + if($value1 == $value2) { + return 0; + } + else if($value1 < $value2) { + return 1; + } + else + return -1; +} +$ao = new ArrayObject(array(3=>0, 2=>1, 5=>2, 6=>3, 1=>4)); + +$ao->uksort('cmp'); +var_dump($ao); +?> +===DONE=== +--EXPECTF-- +*** Testing ArrayObject::uksort() : basic functionality *** +object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + [6]=> + int(3) + [5]=> + int(2) + [3]=> + int(0) + [2]=> + int(1) + [1]=> + int(4) + } +} +===DONE=== diff --git a/ext/spl/tests/arrayObject_uksort_error1.phpt b/ext/spl/tests/arrayObject_uksort_error1.phpt new file mode 100644 index 0000000..d019fc4 --- /dev/null +++ b/ext/spl/tests/arrayObject_uksort_error1.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test ArrayObject::uksort() function : wrong arg count +--FILE-- +<?php +/* Prototype : int ArrayObject::uksort(callback cmp_function) + * Description: proto int ArrayIterator::uksort(callback cmp_function) + Sort the entries by key using user defined function. + * Source code: ext/spl/spl_array.c + * Alias to functions: + */ + +$ao = new ArrayObject(); + +try { + $ao->uksort(); +} catch (BadMethodCallException $e) { + echo $e->getMessage() . "\n"; +} + +try { + $ao->uksort(1,2); +} catch (BadMethodCallException $e) { + echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +Function expects exactly one argument +Function expects exactly one argument +===DONE=== diff --git a/ext/spl/tests/array_001.phpt b/ext/spl/tests/array_001.phpt new file mode 100644 index 0000000..b55fcba --- /dev/null +++ b/ext/spl/tests/array_001.phpt @@ -0,0 +1,113 @@ +--TEST-- +SPL: ArrayObject +--FILE-- +<?php + +$ar = array(0=>0, 1=>1); +$ar = new ArrayObject($ar); + +var_dump($ar); + +$ar[2] = 2; +var_dump($ar[2]); +var_dump($ar["3"] = 3); + +var_dump(array_merge((array)$ar, array(4=>4, 5=>5))); + +var_dump($ar["a"] = "a"); + +var_dump($ar); +var_dump($ar[0]); +var_dump($ar[6]); +var_dump($ar["b"]); + +unset($ar[1]); +unset($ar["3"]); +unset($ar["a"]); +unset($ar[7]); +unset($ar["c"]); +var_dump($ar); + +$ar[] = '3'; +$ar[] = 4; +var_dump($ar); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + int(0) + [1]=> + int(1) + } +} +int(2) +int(3) +array(6) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) + [4]=> + int(4) + [5]=> + int(5) +} +string(1) "a" +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(5) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) + ["a"]=> + string(1) "a" + } +} +int(0) + +Notice: Undefined offset: 6 in %sarray_001.php on line %d +NULL + +Notice: Undefined index: b in %sarray_001.php on line %d +NULL + +Notice: Undefined offset: 7 in %sarray_001.php on line %d + +Notice: Undefined index: c in %sarray_001.php on line %d +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(2) { + [0]=> + int(0) + [2]=> + int(2) + } +} +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(4) { + [0]=> + int(0) + [2]=> + int(2) + [4]=> + string(1) "3" + [5]=> + int(4) + } +} +===DONE=== diff --git a/ext/spl/tests/array_002.phpt b/ext/spl/tests/array_002.phpt new file mode 100644 index 0000000..5593588 --- /dev/null +++ b/ext/spl/tests/array_002.phpt @@ -0,0 +1,41 @@ +--TEST-- +SPL: ArrayObject copy constructor +--FILE-- +<?php + +$array = array('1' => 'one', + '2' => 'two', + '3' => 'three'); + +$object = new ArrayObject($array); +$object[] = 'four'; + +$arrayObject = new ArrayObject($object); + +$arrayObject[] = 'five'; + +var_dump($arrayObject); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(ArrayObject)#1 (1) { + ["storage":"ArrayObject":private]=> + array(5) { + [1]=> + string(3) "one" + [2]=> + string(3) "two" + [3]=> + string(5) "three" + [4]=> + string(4) "four" + [5]=> + string(4) "five" + } + } +} +===DONE=== diff --git a/ext/spl/tests/array_003.phpt b/ext/spl/tests/array_003.phpt new file mode 100644 index 0000000..de4ce30 --- /dev/null +++ b/ext/spl/tests/array_003.phpt @@ -0,0 +1,63 @@ +--TEST-- +SPL: ArrayObject from object +--FILE-- +<?php + +// This test also needs to exclude the protected and private variables +// since they cannot be accessed from the external object which iterates +// them. + +class test +{ + public $pub = "public"; + protected $pro = "protected"; + private $pri = "private"; + + function __construct() + { + $this->imp = "implicit"; + } +}; + +$test = new test; +$test->dyn = "dynamic"; + +print_r($test); + +$object = new ArrayObject($test); + +print_r($object); + +foreach($test as $key => $val) +{ + echo "$key => $val\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +test Object +( + [pub] => public + [pro:protected] => protected + [pri:test:private] => private + [imp] => implicit + [dyn] => dynamic +) +ArrayObject Object +( + [storage:ArrayObject:private] => test Object + ( + [pub] => public + [pro:protected] => protected + [pri:test:private] => private + [imp] => implicit + [dyn] => dynamic + ) + +) +pub => public +imp => implicit +dyn => dynamic +===DONE=== diff --git a/ext/spl/tests/array_004.phpt b/ext/spl/tests/array_004.phpt new file mode 100644 index 0000000..0b80e5c --- /dev/null +++ b/ext/spl/tests/array_004.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: ArrayIterator +--FILE-- +<?php + +$arr = array(0=>0, 1=>1, 2=>2); +$obj = new ArrayObject($arr); + +foreach($obj as $ak=>$av) { + foreach($obj as $bk=>$bv) { + if ($ak==0 && $bk==0) { + $arr[0] = "modify"; + } + echo "$ak=>$av - $bk=>$bv\n"; + } +} + +echo "Done\n"; +?> +--EXPECTF-- +0=>0 - 0=>0 +0=>0 - 1=>1 +0=>0 - 2=>2 +1=>1 - 0=>0 +1=>1 - 1=>1 +1=>1 - 2=>2 +2=>2 - 0=>0 +2=>2 - 1=>1 +2=>2 - 2=>2 +Done diff --git a/ext/spl/tests/array_005.phpt b/ext/spl/tests/array_005.phpt new file mode 100644 index 0000000..d7ef15d --- /dev/null +++ b/ext/spl/tests/array_005.phpt @@ -0,0 +1,91 @@ +--TEST-- +SPL: ArrayObject/Iterator interaction +--FILE-- +<?php + +class Student +{ + private $id; + private $name; + + public function __construct($id, $name) + { + $this->id = $id; + $this->name = $name; + } + + public function __toString() + { + return $this->id . ', ' . $this->name; + } + + public function getId() + { + return $this->id; + } +} + +class StudentIdFilter extends FilterIterator +{ + private $id; + + public function __construct(ArrayObject $students, Student $other) + { + FilterIterator::__construct($students->getIterator()); + $this->id = $other->getId(); + } + + public function accept() + { + echo "ACCEPT ".$this->current()->getId()." == ".$this->id."\n"; + return $this->current()->getId() == $this->id; + } +} + +class StudentList implements IteratorAggregate +{ + private $students; + + public function __construct() + { + $this->students = new ArrayObject(array()); + } + + public function add(Student $student) + { + if (!$this->contains($student)) { + $this->students[] = $student; + } + } + + public function contains(Student $student) + { + foreach ($this->students as $s) + { + if ($s->getId() == $student->getId()) { + return true; + } + } + return false; + } + + public function getIterator() { + return $this->students->getIterator(); + } +} + +$students = new StudentList(); +$students->add(new Student('01234123', 'Joe')); +$students->add(new Student('00000014', 'Bob')); +$students->add(new Student('00000014', 'Foo')); + +foreach ($students as $student) { + echo $student, "\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +01234123, Joe +00000014, Bob +===DONE=== diff --git a/ext/spl/tests/array_006.phpt b/ext/spl/tests/array_006.phpt new file mode 100644 index 0000000..49f2838 --- /dev/null +++ b/ext/spl/tests/array_006.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: ArrayIterator without ArrayObject +--INI-- +error_reporting=2047 +--FILE-- +<?php + +echo "==Normal==\n"; + +$arr = array(0=>0, 1=>1, 2=>2); +$obj = new ArrayIterator($arr); + +foreach($obj as $ak=>$av) { + foreach($obj as $bk=>$bv) { + if ($ak==0 && $bk==0) { + $arr[0] = "modify"; + } + echo "$ak=>$av - $bk=>$bv\n"; + } +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +==Normal== +0=>0 - 0=>0 +0=>0 - 1=>1 +0=>0 - 2=>2 +===DONE=== diff --git a/ext/spl/tests/array_007.phpt b/ext/spl/tests/array_007.phpt new file mode 100644 index 0000000..7d9bf6a --- /dev/null +++ b/ext/spl/tests/array_007.phpt @@ -0,0 +1,71 @@ +--TEST-- +SPL: ArrayObject/Iterator from IteratorAggregate +--FILE-- +<?php + +// This test also needs to exclude the protected and private variables +// since they cannot be accessed from the external object which iterates +// them. + +class test implements IteratorAggregate +{ + public $pub = "public"; + protected $pro = "protected"; + private $pri = "private"; + + function __construct() + { + $this->imp = "implicit"; + } + + function getIterator() + { + $it = new ArrayObject($this); + return $it->getIterator(); + } +}; + +$test = new test; +$test->dyn = "dynamic"; + +print_r($test); + +print_r($test->getIterator()); + +foreach($test as $key => $val) +{ + echo "$key => $val\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +test Object +( + [pub] => public + [pro:protected] => protected + [pri:test:private] => private + [imp] => implicit + [dyn] => dynamic +) +ArrayIterator Object +( + [storage:ArrayIterator:private] => ArrayObject Object + ( + [storage:ArrayObject:private] => test Object + ( + [pub] => public + [pro:protected] => protected + [pri:test:private] => private + [imp] => implicit + [dyn] => dynamic + ) + + ) + +) +pub => public +imp => implicit +dyn => dynamic +===DONE=== diff --git a/ext/spl/tests/array_008.phpt b/ext/spl/tests/array_008.phpt new file mode 100644 index 0000000..e7a618d --- /dev/null +++ b/ext/spl/tests/array_008.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: ArrayIterator and foreach reference +--FILE-- +<?php + +$arr = array(0=>0, 1=>1, 2=>2); +$obj = new ArrayObject($arr); + +foreach($obj as $ak=>&$av) { + foreach($obj as $bk=>&$bv) { + if ($ak==0 && $bk==0) { + $bv = "modify"; + } + echo "$ak=>$av - $bk=>$bv\n"; + } +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +0=>modify - 0=>modify +0=>modify - 1=>1 +0=>modify - 2=>2 +1=>1 - 0=>modify +1=>1 - 1=>1 +1=>1 - 2=>2 +2=>2 - 0=>modify +2=>2 - 1=>1 +2=>2 - 2=>2 +===DONE=== diff --git a/ext/spl/tests/array_009.phpt b/ext/spl/tests/array_009.phpt new file mode 100644 index 0000000..fc0d60b --- /dev/null +++ b/ext/spl/tests/array_009.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: ArrayIterator implementing RecursiveIterator +--FILE-- +<?php + +$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); + +$dir = new RecursiveIteratorIterator(new RecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY); + +foreach ($dir as $file) { + print "$file\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1 +21 +221 +222 +231 +3 +===DONE=== diff --git a/ext/spl/tests/array_009a.phpt b/ext/spl/tests/array_009a.phpt new file mode 100644 index 0000000..396aa9b --- /dev/null +++ b/ext/spl/tests/array_009a.phpt @@ -0,0 +1,37 @@ +--TEST-- +SPL: ArrayIterator implementing RecursiveIterator +--FILE-- +<?php + +class MyRecursiveArrayIterator extends ArrayIterator implements RecursiveIterator +{ + function hasChildren() + { + return is_array($this->current()); + } + + function getChildren() + { + return new MyRecursiveArrayIterator($this->current()); + } +} + +$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); + +$dir = new RecursiveIteratorIterator(new MyRecursiveArrayIterator($array), RecursiveIteratorIterator::LEAVES_ONLY); + +foreach ($dir as $file) { + print "$file\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1 +21 +221 +222 +231 +3 +===DONE=== diff --git a/ext/spl/tests/array_010.phpt b/ext/spl/tests/array_010.phpt new file mode 100644 index 0000000..d2f3de7 --- /dev/null +++ b/ext/spl/tests/array_010.phpt @@ -0,0 +1,144 @@ +--TEST-- +SPL: ArrayIterator implements ArrayAccess +--FILE-- +<?php + +$obj = new ArrayObject(array('1st', 1, 2=>'3rd', '4th'=>4)); + +var_dump($obj->getArrayCopy()); + +echo "===EMPTY===\n"; +var_dump(empty($obj[0])); +var_dump(empty($obj[1])); +var_dump(empty($obj[2])); +var_dump(empty($obj['4th'])); +var_dump(empty($obj['5th'])); +var_dump(empty($obj[6])); + +echo "===isset===\n"; +var_dump(isset($obj[0])); +var_dump(isset($obj[1])); +var_dump(isset($obj[2])); +var_dump(isset($obj['4th'])); +var_dump(isset($obj['5th'])); +var_dump(isset($obj[6])); + +echo "===offsetGet===\n"; +var_dump($obj[0]); +var_dump($obj[1]); +var_dump($obj[2]); +var_dump($obj['4th']); +var_dump($obj['5th']); +var_dump($obj[6]); + +echo "===offsetSet===\n"; +echo "WRITE 1\n"; +$obj[1] = 'Changed 1'; +var_dump($obj[1]); +echo "WRITE 2\n"; +$obj['4th'] = 'Changed 4th'; +var_dump($obj['4th']); +echo "WRITE 3\n"; +$obj['5th'] = 'Added 5th'; +var_dump($obj['5th']); +echo "WRITE 4\n"; +$obj[6] = 'Added 6'; +var_dump($obj[6]); + +var_dump($obj[0]); +var_dump($obj[2]); + +$x = $obj[6] = 'changed 6'; +var_dump($obj[6]); +var_dump($x); + +echo "===unset===\n"; +var_dump($obj->getArrayCopy()); +unset($obj[2]); +unset($obj['4th']); +unset($obj[7]); +unset($obj['8th']); +var_dump($obj->getArrayCopy()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +array(4) { + [0]=> + string(3) "1st" + [1]=> + int(1) + [2]=> + string(3) "3rd" + ["4th"]=> + int(4) +} +===EMPTY=== +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +===isset=== +bool(true) +bool(true) +bool(true) +bool(true) +bool(false) +bool(false) +===offsetGet=== +string(3) "1st" +int(1) +string(3) "3rd" +int(4) + +Notice: Undefined index: 5th in %sarray_010.php on line %d +NULL + +Notice: Undefined offset: 6 in %sarray_010.php on line %d +NULL +===offsetSet=== +WRITE 1 +string(9) "Changed 1" +WRITE 2 +string(11) "Changed 4th" +WRITE 3 +string(9) "Added 5th" +WRITE 4 +string(7) "Added 6" +string(3) "1st" +string(3) "3rd" +string(9) "changed 6" +string(9) "changed 6" +===unset=== +array(6) { + [0]=> + string(3) "1st" + [1]=> + string(9) "Changed 1" + [2]=> + string(3) "3rd" + ["4th"]=> + string(11) "Changed 4th" + ["5th"]=> + string(9) "Added 5th" + [6]=> + string(9) "changed 6" +} + +Notice: Undefined offset: 7 in %sarray_010.php on line %d + +Notice: Undefined index: 8th in %sarray_010.php on line %d +array(4) { + [0]=> + string(3) "1st" + [1]=> + string(9) "Changed 1" + ["5th"]=> + string(9) "Added 5th" + [6]=> + string(9) "changed 6" +} +===DONE=== diff --git a/ext/spl/tests/array_011.phpt b/ext/spl/tests/array_011.phpt new file mode 100644 index 0000000..0c5ad55 --- /dev/null +++ b/ext/spl/tests/array_011.phpt @@ -0,0 +1,35 @@ +--TEST-- +SPL: ArrayIterator, LimitIterator and string keys +--FILE-- +<?php + +$a = array('zero' => 0, 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5); +//foreach (new ArrayIterator($a) as $k => $v) +foreach (new LimitIterator(new ArrayIterator($a), 1, 3) as $k => $v) +{ + var_dump(array($k, $v)); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +array(2) { + [0]=> + string(3) "one" + [1]=> + int(1) +} +array(2) { + [0]=> + string(3) "two" + [1]=> + int(2) +} +array(2) { + [0]=> + string(5) "three" + [1]=> + int(3) +} +===DONE=== diff --git a/ext/spl/tests/array_012.phpt b/ext/spl/tests/array_012.phpt new file mode 100644 index 0000000..2ee9724 --- /dev/null +++ b/ext/spl/tests/array_012.phpt @@ -0,0 +1,63 @@ +--TEST-- +SPL: ArrayIterator::count +--FILE-- +<?php + +echo "===Array===\n"; + +$a = array('zero' => 0, 'one' => 1, 'two' => 2); +$it = new ArrayIterator($a); + +var_dump($it->count()); +foreach($it as $key => $val) +{ + echo "$key=>$val\n"; + var_dump($it->count()); +} +var_dump($it->count()); + +echo "===Object===\n"; + +class test +{ + public $zero = 0; + protected $pro; + public $one = 1; + private $pri; + public $two = 2; +} + +$o = new test; +$it = new ArrayIterator($o); + +var_dump($it->count()); +foreach($it as $key => $val) +{ + echo "$key=>$val\n"; + var_dump($it->count()); +} +var_dump($it->count()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +===Array=== +int(3) +zero=>0 +int(3) +one=>1 +int(3) +two=>2 +int(3) +int(3) +===Object=== +int(3) +zero=>0 +int(3) +one=>1 +int(3) +two=>2 +int(3) +int(3) +===DONE=== diff --git a/ext/spl/tests/array_013.phpt b/ext/spl/tests/array_013.phpt new file mode 100644 index 0000000..3fda538 --- /dev/null +++ b/ext/spl/tests/array_013.phpt @@ -0,0 +1,79 @@ +--TEST-- +SPL: ArrayIterator::append +--FILE-- +<?php + +if (!class_exists('NoRewindIterator', false)) +{ + require_once(dirname(__FILE__) . '/../examples/norewinditerator.inc'); +} + +echo "===Array===\n"; + +$a = array(0 => 'zero', 1 => 'one', 2 => 'two'); +$it = new ArrayIterator($a); + +foreach($it as $key => $val) +{ + echo "$key=>$val\n"; +} + +echo "===Append===\n"; + +$it->append('three'); +$it->append('four'); + +foreach(new NoRewindIterator($it) as $key => $val) +{ + echo "$key=>$val\n"; +} + +echo "===Object===\n"; + +class test +{ + public $zero = 0; + protected $pro; + public $one = 1; + private $pri; + public $two = 2; +} + +$o = new test; +$it = new ArrayIterator($o); + +foreach($it as $key => $val) +{ + echo "$key=>$val\n"; +} + +echo "===Append===\n"; + +$it->append('three'); +$it->append('four'); + +foreach(new NoRewindIterator($it) as $key => $val) +{ + echo "$key=>$val\n"; +} + +var_dump($o->{0}); /* doesn't wotk anyway */ + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===Array=== +0=>zero +1=>one +2=>two +===Append=== +3=>three +4=>four +===Object=== +zero=>0 +one=>1 +two=>2 +===Append=== + +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_014.phpt b/ext/spl/tests/array_014.phpt new file mode 100644 index 0000000..1ac9d4f --- /dev/null +++ b/ext/spl/tests/array_014.phpt @@ -0,0 +1,59 @@ +--TEST-- +SPL: ArrayIterator::seek() +--FILE-- +<?php + +$it = new ArrayIterator(range(0,10)); +var_dump($it->count()); +$it->seek(5); +var_dump($it->current()); +$it->seek(4); +var_dump($it->current()); +try +{ + $it->seek(-1); + var_dump($it->current()); +} +catch(Exception $e) +{ + echo $e->getMessage() . "\n"; +} + +try +{ + $it->seek(12); + var_dump($it->current()); +} +catch(Exception $e) +{ + echo $e->getMessage() . "\n"; +} + +$pos = 0; +foreach($it as $v) +{ + $it->seek($pos++); + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(11) +int(5) +int(4) +Seek position -1 is out of range +Seek position 12 is out of range +int(0) +int(1) +int(2) +int(3) +int(4) +int(5) +int(6) +int(7) +int(8) +int(9) +int(10) +===DONE=== diff --git a/ext/spl/tests/array_015.phpt b/ext/spl/tests/array_015.phpt new file mode 100644 index 0000000..f0bf9f4 --- /dev/null +++ b/ext/spl/tests/array_015.phpt @@ -0,0 +1,97 @@ +--TEST-- +SPL: ArrayIterator::next() with internal arrays +--FILE-- +<?php + +$ar = new ArrayObject(); + +$ar[0] = 1; +$ar[1] = 2; +$ar[2] = 3; +$ar[3] = 4; +$ar[4] = 5; + +var_dump($ar); + +$it = $ar->getIterator(); + +$ar->offsetUnset($it->key()); +$it->next(); + +var_dump($it->current()); +var_dump($ar); + +foreach($it as $k => $v) +{ + $ar->offsetUnset($k+1); + echo "$k=>$v\n"; +} + +var_dump($ar); + +foreach($it as $k => $v) +{ + $ar->offsetUnset($k); + echo "$k=>$v\n"; +} + +var_dump($ar); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(ArrayObject)#%d (1) { + %s"storage"%s"ArrayObject":private]=> + array(5) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + } +} + +Notice: ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sarray_015.php on line %d +int(2) +object(ArrayObject)#%d (1) { + %s"storage"%s"ArrayObject":private]=> + array(4) { + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + [4]=> + int(5) + } +} +1=>2 +3=>4 +object(ArrayObject)#%d (1) { + %s"storage"%s"ArrayObject":private]=> + array(2) { + [1]=> + int(2) + [3]=> + int(4) + } +} +1=>2 + +Notice: main(): ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sarray_015.php on line %d +3=>4 + +Notice: main(): ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sarray_015.php on line %d +object(ArrayObject)#%d (1) { + %s"storage"%s"ArrayObject":private]=> + array(0) { + } +} +===DONE=== diff --git a/ext/spl/tests/array_016.phpt b/ext/spl/tests/array_016.phpt new file mode 100644 index 0000000..8637c5c --- /dev/null +++ b/ext/spl/tests/array_016.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: ArrayIterator/Object and IteratorIterator +--FILE-- +<?php + +$it = new ArrayIterator(range(0,3)); + +foreach(new IteratorIterator($it) as $v) +{ + var_dump($v); +} + +$it = new ArrayObject(range(0,3)); + +foreach(new IteratorIterator($it) as $v) +{ + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(0) +int(1) +int(2) +int(3) +int(0) +int(1) +int(2) +int(3) +===DONE=== diff --git a/ext/spl/tests/array_017.phpt b/ext/spl/tests/array_017.phpt new file mode 100644 index 0000000..8f3d345 --- /dev/null +++ b/ext/spl/tests/array_017.phpt @@ -0,0 +1,817 @@ +--TEST-- +SPL: ArrayObject::exchangeArray($this) +--FILE-- +<?php + +class ArrayIteratorEx extends ArrayIterator +{ + public $pub2 = 1; + protected $pro2 = 2; + private $pri2 = 3; + + function __construct($ar, $flags = 0) + { + echo __METHOD__ . "()\n"; + parent::__construct($ar, $flags); + $this->imp2 = 4; + } + + function dump() + { + echo __METHOD__ . "()\n"; + var_dump(array('Flags'=>$this->getFlags() + ,'OVars'=>get_object_vars($this) + ,'$this'=>$this)); + } + + function setFlags($flags) + { + echo __METHOD__ . "($flags)\n"; + ArrayIterator::setFlags($flags); + } +} + +class ArrayObjectEx extends ArrayObject +{ + public $pub1 = 1; + protected $pro1 = 2; + private $pri1 = 3; + + function __construct($ar = array(), $flags = 0) + { + echo __METHOD__ . "()\n"; + parent::__construct($ar, $flags); + $this->imp1 = 4; + } + + function exchange() + { + echo __METHOD__ . "()\n"; + $this->exchangeArray($this); + } + + function dump() + { + echo __METHOD__ . "()\n"; + var_dump(array('Flags'=>$this->getFlags() + ,'OVars'=>get_object_vars($this) + ,'$this'=>$this)); + } + + function show() + { + echo __METHOD__ . "()\n"; + foreach($this as $n => $v) + { + var_dump(array($n => $v)); + } + } + + function setFlags($flags) + { + echo __METHOD__ . "($flags)\n"; + ArrayObject::setFlags($flags); + } + + function getIterator() + { + echo __METHOD__ . "()\n"; + $it = new ArrayIteratorEx($this, $this->getFlags()); + $it->dyn2 = 5; + $it->dump(); + return $it; + } +} + +function check($obj, $flags) +{ + echo "===CHECK===\n"; + + $obj->setFlags($flags); + $obj->dump(); + $obj->show(); + + echo "===FOREACH===\n"; + + $it = $obj->getIterator(); + foreach($it as $n => $v) + { + var_dump(array($n => $v)); + } + + echo "===PROPERTY===\n"; + + var_dump($obj->pub1); + var_dump(isset($obj->a)); + $obj->setFlags($flags | 2); + var_dump($obj->pub1); + var_dump(isset($obj->a)); + + var_dump($it->pub2); + var_dump(isset($it->pub1)); + $it->setFlags($flags | 2); + var_dump($it->pub2); + var_dump(isset($it->pub1)); +} + +$obj = new ArrayObjectEx(array(0=>1,'a'=>25, 'pub1'=>42), 0); +$obj->dyn1 = 5; + +check($obj, 0); +check($obj, 1); + +echo "#####EXCHANGE#####\n"; + +$obj->exchange(); + +check($obj, 0); +check($obj, 1); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +ArrayObjectEx::__construct() +===CHECK=== +ArrayObjectEx::setFlags(0) +ArrayObjectEx::dump() +array(3) { + ["Flags"]=> + int(0) + ["OVars"]=> + array(2) { + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + ["$this"]=> + object(ArrayObjectEx)#%d (6) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + } +} +ArrayObjectEx::show() +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(0) + ["OVars"]=> + array(2) { + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (6) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + } + } +} +array(1) { + [0]=> + int(1) +} +array(1) { + ["a"]=> + int(25) +} +array(1) { + ["pub1"]=> + int(42) +} +===FOREACH=== +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(0) + ["OVars"]=> + array(2) { + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (6) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + } + } +} +array(1) { + [0]=> + int(1) +} +array(1) { + ["a"]=> + int(25) +} +array(1) { + ["pub1"]=> + int(42) +} +===PROPERTY=== +int(1) +bool(false) +ArrayObjectEx::setFlags(2) +int(1) +bool(true) +int(1) +bool(false) +ArrayIteratorEx::setFlags(2) +int(1) +bool(true) +===CHECK=== +ArrayObjectEx::setFlags(1) +ArrayObjectEx::dump() +array(3) { + ["Flags"]=> + int(1) + ["OVars"]=> + array(5) { + ["pub1"]=> + int(1) + ["pro1"]=> + int(2) + ["pri1"]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + ["$this"]=> + object(ArrayObjectEx)#%d (6) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + } +} +ArrayObjectEx::show() +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(1) + ["OVars"]=> + array(5) { + ["pub2"]=> + int(1) + ["pro2"]=> + int(2) + ["pri2"]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (6) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + } + } +} +array(1) { + [0]=> + int(1) +} +array(1) { + ["a"]=> + int(25) +} +array(1) { + ["pub1"]=> + int(42) +} +===FOREACH=== +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(1) + ["OVars"]=> + array(5) { + ["pub2"]=> + int(1) + ["pro2"]=> + int(2) + ["pri2"]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (6) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + ["a"]=> + int(25) + ["pub1"]=> + int(42) + } + } + } +} +array(1) { + [0]=> + int(1) +} +array(1) { + ["a"]=> + int(25) +} +array(1) { + ["pub1"]=> + int(42) +} +===PROPERTY=== +int(1) +bool(false) +ArrayObjectEx::setFlags(3) +int(1) +bool(true) +int(1) +bool(false) +ArrayIteratorEx::setFlags(3) +int(1) +bool(true) +#####EXCHANGE##### +ArrayObjectEx::exchange() +===CHECK=== +ArrayObjectEx::setFlags(0) +ArrayObjectEx::dump() +array(3) { + ["Flags"]=> + int(0) + ["OVars"]=> + array(5) { + ["pub1"]=> + int(1) + ["pro1"]=> + int(2) + ["pri1"]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + ["$this"]=> + object(ArrayObjectEx)#%d (5) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } +} +ArrayObjectEx::show() +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(0) + ["OVars"]=> + array(4) { + ["pub1"]=> + int(1) + ["pro1"]=> + int(2) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (5) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + } +} +array(1) { + ["pub1"]=> + int(1) +} +array(1) { + ["imp1"]=> + int(4) +} +array(1) { + ["dyn1"]=> + int(5) +} +===FOREACH=== +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(0) + ["OVars"]=> + array(4) { + ["pub1"]=> + int(1) + ["pro1"]=> + int(2) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (5) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + } +} +array(1) { + ["pub1"]=> + int(1) +} +array(1) { + ["imp1"]=> + int(4) +} +array(1) { + ["dyn1"]=> + int(5) +} +===PROPERTY=== +int(1) +bool(false) +ArrayObjectEx::setFlags(2) +int(1) +bool(false) +int(1) +bool(false) +ArrayIteratorEx::setFlags(2) +int(1) +bool(true) +===CHECK=== +ArrayObjectEx::setFlags(1) +ArrayObjectEx::dump() +array(3) { + ["Flags"]=> + int(1) + ["OVars"]=> + array(5) { + ["pub1"]=> + int(1) + ["pro1"]=> + int(2) + ["pri1"]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + ["$this"]=> + object(ArrayObjectEx)#%d (5) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } +} +ArrayObjectEx::show() +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(1) + ["OVars"]=> + array(5) { + ["pub2"]=> + int(1) + ["pro2"]=> + int(2) + ["pri2"]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (5) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + } +} +array(1) { + ["pub1"]=> + int(1) +} +array(1) { + ["imp1"]=> + int(4) +} +array(1) { + ["dyn1"]=> + int(5) +} +===FOREACH=== +ArrayObjectEx::getIterator() +ArrayIteratorEx::__construct() +ArrayIteratorEx::dump() +array(3) { + ["Flags"]=> + int(1) + ["OVars"]=> + array(5) { + ["pub2"]=> + int(1) + ["pro2"]=> + int(2) + ["pri2"]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + } + ["$this"]=> + object(ArrayIteratorEx)#%d (6) { + ["pub2"]=> + int(1) + ["pro2":protected]=> + int(2) + ["pri2":"ArrayIteratorEx":private]=> + int(3) + ["imp2"]=> + int(4) + ["dyn2"]=> + int(5) + ["storage":"ArrayIterator":private]=> + object(ArrayObjectEx)#%d (5) { + ["pub1"]=> + int(1) + ["pro1":protected]=> + int(2) + ["pri1":"ArrayObjectEx":private]=> + int(3) + ["imp1"]=> + int(4) + ["dyn1"]=> + int(5) + } + } +} +array(1) { + ["pub1"]=> + int(1) +} +array(1) { + ["imp1"]=> + int(4) +} +array(1) { + ["dyn1"]=> + int(5) +} +===PROPERTY=== +int(1) +bool(false) +ArrayObjectEx::setFlags(3) +int(1) +bool(false) +int(1) +bool(false) +ArrayIteratorEx::setFlags(3) +int(1) +bool(true) +===DONE=== diff --git a/ext/spl/tests/array_018.phpt b/ext/spl/tests/array_018.phpt Binary files differnew file mode 100644 index 0000000..7c68a62 --- /dev/null +++ b/ext/spl/tests/array_018.phpt diff --git a/ext/spl/tests/array_019.phpt b/ext/spl/tests/array_019.phpt new file mode 100644 index 0000000..d128f4d --- /dev/null +++ b/ext/spl/tests/array_019.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: ArrayIterator and foreach by reference +--FILE-- +<?php + +$ar = new ArrayObject(array(1)); foreach($ar as &$v) var_dump($v); +$ar = new ArrayIterator(array(2)); foreach($ar as &$v) var_dump($v); +$ar = new RecursiveArrayIterator(array(3)); foreach($ar as &$v) var_dump($v); + +class ArrayIteratorEx extends ArrayIterator +{ + function current() + { + return ArrayIterator::current(); + } +} + +$ar = new ArrayIteratorEx(array(4)); foreach($ar as $v) var_dump($v); +$ar = new ArrayIteratorEx(array(5)); foreach($ar as &$v) var_dump($v); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) + +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_020.phpt b/ext/spl/tests/array_020.phpt new file mode 100644 index 0000000..4c6fe0d --- /dev/null +++ b/ext/spl/tests/array_020.phpt @@ -0,0 +1,64 @@ +--TEST-- +SPL: ArrayIterator overloading +--FILE-- +<?php + +class ArrayIteratorEx extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + ArrayIterator::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return ArrayIterator::valid(); + } + + function key() + { + echo __METHOD__ . "\n"; + return ArrayIterator::key(); + } + + function current() + { + echo __METHOD__ . "\n"; + return ArrayIterator::current(); + } + + function next() + { + echo __METHOD__ . "\n"; + return ArrayIterator::next(); + } +} + +$ar = new ArrayIteratorEx(array(1,2)); +foreach($ar as $k => $v) +{ + var_dump($k); + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +ArrayIteratorEx::rewind +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(0) +int(1) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(1) +int(2) +ArrayIteratorEx::next +ArrayIteratorEx::valid +===DONE=== diff --git a/ext/spl/tests/array_021.phpt b/ext/spl/tests/array_021.phpt new file mode 100644 index 0000000..f2ae0c8 --- /dev/null +++ b/ext/spl/tests/array_021.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: ArrayObject::seek() and exceptions +--FILE-- +<?php + +class foo extends ArrayObject +{ + public function seek($key) + { + echo __METHOD__ . "($key)\n"; + throw new Exception("hi"); + } +} + +$test = new foo(array(1,2,3)); + +try +{ + $test->seek('bar'); +} +catch (Exception $e) +{ + echo "got exception\n"; +} + +?> +===DONE=== +--EXPECT-- +foo::seek(bar) +got exception +===DONE=== diff --git a/ext/spl/tests/array_022.phpt b/ext/spl/tests/array_022.phpt new file mode 100644 index 0000000..82da3bb --- /dev/null +++ b/ext/spl/tests/array_022.phpt @@ -0,0 +1,80 @@ +--TEST-- +SPL: ArrayObject/Iterator and reference to self +--FILE-- +==ArrayObject=== +<?php + +class MyArrayObject extends ArrayObject +{ + public function __construct() + { + parent::__construct($this); + $this['bar'] = 'baz'; + } +} + +$a = new MyArrayObject; + +$b = clone $a; +$b['baz'] = 'Foo'; + +var_dump($a); +var_dump($b); + +?> +==ArrayIterator=== +<?php + +class MyArrayIterator extends ArrayIterator +{ + public function __construct() + { + parent::__construct($this); + $this['bar'] = 'baz'; + } +} + +$a = new MyArrayIterator; + +$b = clone $a; +$b['baz'] = 'Foo'; + +var_dump($a); +var_dump($b); + +?> +===DONE=== +--EXPECTF-- +==ArrayObject=== +object(MyArrayObject)#%d (1) { + ["bar"]=> + string(3) "baz" +} +object(MyArrayObject)#%d (3) { + ["bar"]=> + string(3) "baz" + ["baz"]=> + string(3) "Foo" + ["storage":"ArrayObject":private]=> + array(1) { + ["bar"]=> + string(3) "baz" + } +} +==ArrayIterator=== +object(MyArrayIterator)#%d (1) { + ["bar"]=> + string(3) "baz" +} +object(MyArrayIterator)#%d (3) { + ["bar"]=> + string(3) "baz" + ["baz"]=> + string(3) "Foo" + ["storage":"ArrayIterator":private]=> + object(MyArrayIterator)#%d (1) { + ["bar"]=> + string(3) "baz" + } +} +===DONE=== diff --git a/ext/spl/tests/array_023.phpt b/ext/spl/tests/array_023.phpt new file mode 100644 index 0000000..a444604 --- /dev/null +++ b/ext/spl/tests/array_023.phpt @@ -0,0 +1,87 @@ +--TEST-- +Testing class extending to ArrayObject and serialize +--FILE-- +<?php + +class Name extends ArrayObject +{ + public $var = 'a'; + protected $bar = 'b'; + private $foo = 'c'; +} + +$a = new Name(); +var_dump($a); +var_dump($a->var); + +$a = unserialize(serialize($a)); + +var_dump($a); +var_dump($a->var); + +class Bla extends ArrayObject +{ + public $var = 'aaa'; + protected $bar = 'bbb'; + private $foo = 'ccc'; +} + +$a = new Bla(); +var_dump($a); +var_dump($a->var); + +$a = unserialize(serialize($a)); + +var_dump($a); +var_dump($a->var); + +?> +--EXPECT-- +object(Name)#1 (4) { + ["var"]=> + string(1) "a" + ["bar":protected]=> + string(1) "b" + ["foo":"Name":private]=> + string(1) "c" + ["storage":"ArrayObject":private]=> + array(0) { + } +} +string(1) "a" +object(Name)#2 (4) { + ["var"]=> + string(1) "a" + ["bar":protected]=> + string(1) "b" + ["foo":"Name":private]=> + string(1) "c" + ["storage":"ArrayObject":private]=> + array(0) { + } +} +string(1) "a" +object(Bla)#1 (4) { + ["var"]=> + string(3) "aaa" + ["bar":protected]=> + string(3) "bbb" + ["foo":"Bla":private]=> + string(3) "ccc" + ["storage":"ArrayObject":private]=> + array(0) { + } +} +string(3) "aaa" +object(Bla)#2 (4) { + ["var"]=> + string(3) "aaa" + ["bar":protected]=> + string(3) "bbb" + ["foo":"Bla":private]=> + string(3) "ccc" + ["storage":"ArrayObject":private]=> + array(0) { + } +} +string(3) "aaa" diff --git a/ext/spl/tests/array_024.phpt b/ext/spl/tests/array_024.phpt new file mode 100644 index 0000000..0c073bf --- /dev/null +++ b/ext/spl/tests/array_024.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: ArrayObject with overriden count() +--FILE-- +<?php +$obj = new ArrayObject(array(1,2)); +var_dump(count($obj)); +class ArrayObject2 extends ArrayObject { + public function count() { + return -parent::count(); + } +} +$obj = new ArrayObject2(array(1,2)); +var_dump(count($obj)); +?> +--EXPECT-- +int(2) +int(-2) diff --git a/ext/spl/tests/array_025.phpt b/ext/spl/tests/array_025.phpt new file mode 100644 index 0000000..35893ea --- /dev/null +++ b/ext/spl/tests/array_025.phpt @@ -0,0 +1,40 @@ +--TEST-- +SPL: ArrayObject serialize with an object as storage +--FILE-- +<?php +$obj1 = new ArrayObject(new ArrayObject(array(1,2))); +$s = serialize($obj1); +$obj2 = unserialize($s); + +print_r($obj1); +echo "$s\n"; +print_r($obj2); +?> +--EXPECT-- +ArrayObject Object +( + [storage:ArrayObject:private] => ArrayObject Object + ( + [storage:ArrayObject:private] => Array + ( + [0] => 1 + [1] => 2 + ) + + ) + +) +C:11:"ArrayObject":76:{x:i:0;C:11:"ArrayObject":37:{x:i:0;a:2:{i:0;i:1;i:1;i:2;};m:a:0:{}};m:a:0:{}} +ArrayObject Object +( + [storage:ArrayObject:private] => ArrayObject Object + ( + [storage:ArrayObject:private] => Array + ( + [0] => 1 + [1] => 2 + ) + + ) + +) diff --git a/ext/spl/tests/array_026.phpt b/ext/spl/tests/array_026.phpt new file mode 100644 index 0000000..9c79c57 --- /dev/null +++ b/ext/spl/tests/array_026.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: ArrayObject indirect offsetGet overwriting EG(uninitialized_zvar_ptr) +--FILE-- +<?php +$test = new ArrayObject(); +$test['d1']['d2'] = 'hello'; +$test['d1']['d3'] = 'world'; +var_dump($test, $test3['mmmmm']); +?> +--EXPECTF-- +Notice: Undefined variable: test3 in %s%earray_026.php on line %d +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["d1"]=> + array(2) { + ["d2"]=> + string(5) "hello" + ["d3"]=> + string(5) "world" + } + } +} +NULL diff --git a/ext/spl/tests/array_027.phpt b/ext/spl/tests/array_027.phpt new file mode 100644 index 0000000..509b8f9 --- /dev/null +++ b/ext/spl/tests/array_027.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: ArrayObject revursive var_dump +--FILE-- +<?php +class AO extends ArrayObject { +} +$o = new AO(); +$o['plop'] = $o; + +var_dump($o); +--EXPECTF-- +object(AO)#%d (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["plop"]=> + *RECURSION* + } +} diff --git a/ext/spl/tests/bug28822.phpt b/ext/spl/tests/bug28822.phpt new file mode 100644 index 0000000..7114eda --- /dev/null +++ b/ext/spl/tests/bug28822.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #28822 (ArrayObject::offsetExists() works inverted) +--FILE-- +<?php + +$array = new ArrayObject(); +$array->offsetSet('key', 'value'); +var_dump($array->offsetExists('key')); +var_dump($array->offsetExists('nokey')); + +?> +===DONE=== +--EXPECT-- +bool(true) +bool(false) +===DONE=== diff --git a/ext/spl/tests/bug31185.phpt b/ext/spl/tests/bug31185.phpt new file mode 100644 index 0000000..aa410eb --- /dev/null +++ b/ext/spl/tests/bug31185.phpt @@ -0,0 +1,61 @@ +--TEST-- +Bug #31185 (Crash when exceptions thrown from ArrayAccess::offsetUnset()) +--FILE-- +<?php + +class FooBar implements ArrayAccess { + private $array = array(); + + public function offsetExists($index) { + return isset($this->array[$index]); + } + + public function offsetGet($index) { + return $this->array[$index]; + } + + public function offsetSet($index, $value) { + echo __METHOD__ . "($index, $value)\n"; + $this->array[$index] = $value; + } + + public function offsetUnset($index) { + throw new Exception('FAIL'); + unset($this->array[$index]); + } + +} + +$i = 0; $j = 0; +$foo = new FooBar(); +$foo[$j++] = $i++; +$foo[$j++] = $i++; +$foo[$j++] = $i++; +try +{ + unset($foo[1]); +} +catch (Exception $e) +{ + echo "CAUGHT: " . $e->getMessage() . "\n"; +} + +print_R($foo); +?> +===DONE=== +--EXPECT-- +FooBar::offsetSet(0, 0) +FooBar::offsetSet(1, 1) +FooBar::offsetSet(2, 2) +CAUGHT: FAIL +FooBar Object +( + [array:FooBar:private] => Array + ( + [0] => 0 + [1] => 1 + [2] => 2 + ) + +) +===DONE=== diff --git a/ext/spl/tests/bug31346.phpt b/ext/spl/tests/bug31346.phpt new file mode 100644 index 0000000..9b5618e --- /dev/null +++ b/ext/spl/tests/bug31346.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #31486 (ArrayIterator::next segfaults) +--FILE-- +<?php +$obj = new stdClass; +$obj->var1=1; + +$ao = new ArrayObject($obj); + +$i = $ao->getIterator(); + +$ao->offsetUnset($i->key()); +$i->next(); + +?> +===DONE=== +--EXPECTF-- +Notice: ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sbug31346.php on line %d +===DONE=== diff --git a/ext/spl/tests/bug31348.phpt b/ext/spl/tests/bug31348.phpt new file mode 100644 index 0000000..047e4b2 --- /dev/null +++ b/ext/spl/tests/bug31348.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #31348 (CachingIterator::rewind() leaks) +--FILE-- +<?php +$a = Array("some","blah"); +$i = new ArrayIterator($a); + +$ci = new CachingIterator($i); + +$ci->rewind(); + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/ext/spl/tests/bug31926.phpt b/ext/spl/tests/bug31926.phpt new file mode 100644 index 0000000..2d72df4 --- /dev/null +++ b/ext/spl/tests/bug31926.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #31926 (php in free() error with RecursiveArrayIterator) +--FILE-- +<?php + +$array = array(0 => array('world')); + +$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($array)); +foreach($it as $key => $val) { + var_dump($key, $val); +} + +?> +--EXPECT-- +int(0) +string(5) "world" diff --git a/ext/spl/tests/bug32134.phpt b/ext/spl/tests/bug32134.phpt new file mode 100644 index 0000000..5a880b3 --- /dev/null +++ b/ext/spl/tests/bug32134.phpt @@ -0,0 +1,48 @@ +--TEST-- +Bug #32134 (Overloading offsetGet/offsetSet) +--FILE-- +<?php + +class myArray extends ArrayIterator +{ + + public function __construct($array = array()) + { + parent::__construct($array); + } + + public function offsetGet($index) + { + static $i = 0; + echo __METHOD__ . "($index)\n"; + if (++$i > 3) exit(1); + return parent::offsetGet($index); + } + + public function offsetSet($index, $newval) + { + echo __METHOD__ . "($index,$newval)\n"; + return parent::offsetSet($index, $newval); + } + +} + +$myArray = new myArray(); + +$myArray->offsetSet('one', 'one'); +var_dump($myArray->offsetGet('one')); + +$myArray['two'] = 'two'; +var_dump($myArray['two']); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +myArray::offsetSet(one,one) +myArray::offsetGet(one) +string(3) "one" +myArray::offsetSet(two,two) +myArray::offsetGet(two) +string(3) "two" +===DONE=== diff --git a/ext/spl/tests/bug32394.phpt b/ext/spl/tests/bug32394.phpt new file mode 100644 index 0000000..8189b23 --- /dev/null +++ b/ext/spl/tests/bug32394.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #32394 (offsetUnset() segfaults in a foreach) +--FILE-- +<?php + +$object = new ArrayIterator; +$object->append(1); + +foreach($object as $key => $value) +{ + $object->offsetUnset($key); +} + +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/ext/spl/tests/bug33136.phpt b/ext/spl/tests/bug33136.phpt new file mode 100644 index 0000000..121ff58 --- /dev/null +++ b/ext/spl/tests/bug33136.phpt @@ -0,0 +1,80 @@ +--TEST-- +Bug #33136 (method offsetSet in class extended from ArrayObject crash PHP) +--FILE-- +<?php + +class Collection extends ArrayObject +{ + private $data; + + function __construct() + { + $this->data = array(); + parent::__construct($this->data); + } + + function offsetGet($index) + { + echo __METHOD__ . "($index)\n"; + return parent::offsetGet($index); + } + + function offsetSet($index, $value) + { + echo __METHOD__ . "(" . (is_null($index) ? "NULL" : $index) . ",$value)\n"; + parent::offsetSet($index, $value); + } +} + +echo "\n\nInitiate Obj\n"; +$arrayObj = new Collection(); + +echo "Assign values\n"; + +$arrayObj[] = "foo"; +var_dump($arrayObj[0]); + +$arrayObj[] = "bar"; +var_dump($arrayObj[0]); +var_dump($arrayObj[1]); + +$arrayObj["foo"] = "baz"; +var_dump($arrayObj["foo"]); + +print_r($arrayObj); + +var_dump(count($arrayObj)); + +?> +===DONE=== +<?php //exit(0); ?> +--EXPECT-- +Initiate Obj +Assign values +Collection::offsetSet(NULL,foo) +Collection::offsetGet(0) +string(3) "foo" +Collection::offsetSet(NULL,bar) +Collection::offsetGet(0) +string(3) "foo" +Collection::offsetGet(1) +string(3) "bar" +Collection::offsetSet(foo,baz) +Collection::offsetGet(foo) +string(3) "baz" +Collection Object +( + [data:Collection:private] => Array + ( + ) + + [storage:ArrayObject:private] => Array + ( + [0] => foo + [1] => bar + [foo] => baz + ) + +) +int(3) +===DONE=== diff --git a/ext/spl/tests/bug34548.phpt b/ext/spl/tests/bug34548.phpt new file mode 100644 index 0000000..27c3094 --- /dev/null +++ b/ext/spl/tests/bug34548.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug #34548 (Method append() in class extended from ArrayObject crashes PHP) +--FILE-- +<?php + +class Collection extends ArrayObject +{ + public function add($dataArray) + { + foreach($dataArray as $value) $this->append($value); + } + + public function offsetSet($index, $value) + { + parent::offsetSet($index, $value); + } +} + +$data1=array('one', 'two', 'three'); +$data2=array('four', 'five'); + +$foo=new Collection($data1); +$foo->add($data2); + +print_r($foo->getArrayCopy()); + +echo "Done\n"; +?> +--EXPECT-- +Array +( + [0] => one + [1] => two + [2] => three + [3] => four + [4] => five +) +Done diff --git a/ext/spl/tests/bug36258.phpt b/ext/spl/tests/bug36258.phpt new file mode 100644 index 0000000..60817d0 --- /dev/null +++ b/ext/spl/tests/bug36258.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #36258 (SplFileObject::getPath() may lead to segfault) +--FILE-- +<?php + +$diriter = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('.') ); + +foreach ($diriter as $key => $file) { + var_dump($file->getFilename()); + var_dump($file->getPath()); + break; +} + +?> +===DONE=== +--EXPECTF-- +string(%d) "%s" +string(%d) "%s" +===DONE=== diff --git a/ext/spl/tests/bug36287.phpt b/ext/spl/tests/bug36287.phpt new file mode 100644 index 0000000..0c3f287 --- /dev/null +++ b/ext/spl/tests/bug36287.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #36287 (Segfault with SplFileInfo conversion) +--FILE-- +<?php + +$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."), true); + +$idx = 0; +foreach($it as $file) +{ + echo "First\n"; + var_Dump($file->getFilename()); + echo "Second\n"; + var_dump($file->getFilename()); + if (++$idx > 1) + { + break; + } +} + +?> +===DONE=== +--EXPECTF-- +First +string(%d) "%s" +Second +string(%d) "%s" +First +string(%d) "%s" +Second +string(%d) "%s" +===DONE=== diff --git a/ext/spl/tests/bug36825.phpt b/ext/spl/tests/bug36825.phpt new file mode 100644 index 0000000..35de013 --- /dev/null +++ b/ext/spl/tests/bug36825.phpt @@ -0,0 +1,31 @@ +--TEST-- +Bug #36825 (Exceptions thrown in ArrayObject::offsetGet cause segfault) +--FILE-- +<?php + +class foo extends ArrayObject +{ + public function offsetGet($key) + { + echo __METHOD__ . "($key)\n"; + throw new Exception("hi"); + } +} + +$test = new foo(); + +try +{ + var_dump($test['bar']); +} +catch (Exception $e) +{ + echo "got exception\n"; +} + +?> +===DONE=== +--EXPECT-- +foo::offsetGet(bar) +got exception +===DONE=== diff --git a/ext/spl/tests/bug36941.phpt b/ext/spl/tests/bug36941.phpt new file mode 100644 index 0000000..528ba4a --- /dev/null +++ b/ext/spl/tests/bug36941.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #36941 (ArrayIterator does not clone itself) +--FILE-- +===ArrayObject=== +<?php +$a = new ArrayObject(); +$a[] = 1; + +$b = clone $a; + +var_dump($a[0], $b[0]); +$b[0] = $b[0] + 1; +var_dump($a[0], $b[0]); +$b[0] = 3; +var_dump($a[0], $b[0]); +?> +===ArrayIterator=== +<?php +$a = new ArrayIterator(); +$a[] = 1; + +$b = clone $a; + +var_dump($a[0], $b[0]); +$b[0] = $b[0] + 1; +var_dump($a[0], $b[0]); +$b[0] = 3; +var_dump($a[0], $b[0]); +?> +===DONE=== +--EXPECT-- +===ArrayObject=== +int(1) +int(1) +int(1) +int(2) +int(1) +int(3) +===ArrayIterator=== +int(1) +int(1) +int(2) +int(2) +int(3) +int(3) +===DONE=== diff --git a/ext/spl/tests/bug37457.phpt b/ext/spl/tests/bug37457.phpt new file mode 100644 index 0000000..e66fa4d --- /dev/null +++ b/ext/spl/tests/bug37457.phpt @@ -0,0 +1,80 @@ +--TEST-- +Bug #37457 (Crash when an exception is thrown in accept() method of FilterIterator) +--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/bug38325.phpt b/ext/spl/tests/bug38325.phpt new file mode 100644 index 0000000..ddb2829 --- /dev/null +++ b/ext/spl/tests/bug38325.phpt @@ -0,0 +1,9 @@ +--TEST-- +Bug #38325 (spl_autoload_register() gaves wrong line for "class not found") +--FILE-- +<?php +spl_autoload_register(); +new ThisClassDoesNotExistEverFoo(); +?> +--EXPECTF-- +Fatal error: spl_autoload(): Class ThisClassDoesNotExistEverFoo could not be loaded in %s on line 3 diff --git a/ext/spl/tests/bug38618.phpt b/ext/spl/tests/bug38618.phpt new file mode 100644 index 0000000..17439b4 --- /dev/null +++ b/ext/spl/tests/bug38618.phpt @@ -0,0 +1,105 @@ +--TEST-- +Bug #38618 (RecursiveArrayIterator::hasChildren() follows objects) +--FILE-- +<?php # vim:ft=php + +class FruitPublic +{ + public $title; + + public function __construct($title) + { + $this->title = $title; + } + + public function __toString() + { + return $this->title; + } +} + +class FruitProtected +{ + protected $title; + + public function __construct($title) + { + $this->title = $title; + } + + public function __toString() + { + return $this->title; + } +} + +function test_array($array, $which, $flags = 0) +{ + echo "===$which===\n"; + $it = new RecursiveArrayIterator($array, $flags); + foreach (new RecursiveIteratorIterator($it) as $k => $fruit) { + echo $k , ' => ', $fruit, "\n"; + } +} + +$array = array( + 1 => array( + 1 => array( + 1 => 'apple', + ), + 2 => array( + 1 => 'grape', + ), + ), +); + +test_array($array, 'Default with array'); + +$array = array( + 1 => array( + 1 => array( + 1 => new FruitPublic('apple'), + ), + 2 => array( + 1 => new FruitPublic('grape'), + ), + ), +); + +test_array($array, 'Public Property'); + +$array = array( + 1 => array( + 1 => array( + 1 => new FruitProtected('apple'), + ), + 2 => array( + 1 => new FruitProtected('grape'), + ), + ), +); + +test_array($array, 'Protected Property'); + +test_array($array, 'Public Property New', RecursiveArrayIterator::CHILD_ARRAYS_ONLY); +test_array($array, 'Protected Property New', RecursiveArrayIterator::CHILD_ARRAYS_ONLY); +?> +===DONE=== +<?php exit(0); ?> +?> +===DONE=== +--EXPECTF-- +===Default with array=== +1 => apple +1 => grape +===Public Property=== +title => apple +title => grape +===Protected Property=== +===Public Property New=== +1 => apple +1 => grape +===Protected Property New=== +1 => apple +1 => grape +===DONE=== diff --git a/ext/spl/tests/bug40036.phpt b/ext/spl/tests/bug40036.phpt new file mode 100644 index 0000000..8180c03 --- /dev/null +++ b/ext/spl/tests/bug40036.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #40036 (empty() does not work correctly with ArrayObject when using ARRAY_AS_PROPS) +--FILE-- +<?php +class View extends ArrayObject +{ + public function __construct(array $array = array()) + { + parent::__construct($array, ArrayObject::ARRAY_AS_PROPS); + } +} + +$view = new View(); +$view->foo = false; +$view->bar = null; +$view->baz = ''; +if (empty($view['foo']) || empty($view->foo)) { + echo "View::foo empty\n"; +} +if (empty($view['bar']) || empty($view->bar)) { + echo "View::bar empty\n"; +} +if (empty($view['baz']) || empty($view->baz)) { + echo "View::baz empty\n"; +} +?> +===DONE=== +--EXPECT-- +View::foo empty +View::bar empty +View::baz empty +===DONE=== diff --git a/ext/spl/tests/bug40091.phpt b/ext/spl/tests/bug40091.phpt new file mode 100644 index 0000000..eb157e7 --- /dev/null +++ b/ext/spl/tests/bug40091.phpt @@ -0,0 +1,43 @@ +--TEST-- +Bug #40091 (issue with spl_autoload_register() and 2 instances of the same class) +--FILE-- +<?php +class MyAutoloader { + function __construct($directory_to_use) {} + function autoload($class_name) { + // code to autoload based on directory + } +} + +$autloader1 = new MyAutoloader('dir1'); +spl_autoload_register(array($autloader1, 'autoload')); + +$autloader2 = new MyAutoloader('dir2'); +spl_autoload_register(array($autloader2, 'autoload')); + +print_r(spl_autoload_functions()); +?> +===DONE=== +--EXPECT-- +Array +( + [0] => Array + ( + [0] => MyAutoloader Object + ( + ) + + [1] => autoload + ) + + [1] => Array + ( + [0] => MyAutoloader Object + ( + ) + + [1] => autoload + ) + +) +===DONE=== diff --git a/ext/spl/tests/bug40442.phpt b/ext/spl/tests/bug40442.phpt new file mode 100644 index 0000000..fbeb22d --- /dev/null +++ b/ext/spl/tests/bug40442.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #40442 (ArrayObject::offsetExists broke in 5.2.1, works in 5.2.0) +--FILE-- +<?php +$a = new ArrayObject(); +$a->offsetSet('property', 0); +var_dump($a->offsetExists('property')); +?> +===DONE=== +--EXPECT-- +bool(true) +===DONE=== diff --git a/ext/spl/tests/bug40872.phpt b/ext/spl/tests/bug40872.phpt new file mode 100644 index 0000000..a48fe74 --- /dev/null +++ b/ext/spl/tests/bug40872.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #40872 (inconsistency in offsetSet, offsetExists treatment of string enclosed integers) +--FILE-- +<?php + class Project { + public $id; + + function __construct($id) { + $this->id = $id; + } + } + + class ProjectsList extends ArrayIterator { + public function add(Project $item) { + $this->offsetSet($item->id, $item); + } + } + + $projects = new ProjectsList(); + $projects->add(new Project('1')); + $projects->add(new Project(2)); + + var_dump($projects->offsetExists(1)); + var_dump($projects->offsetExists('2')); +?> +===DONE=== +--EXPECT-- +bool(true) +bool(true) +===DONE=== diff --git a/ext/spl/tests/bug41528.phpt b/ext/spl/tests/bug41528.phpt new file mode 100644 index 0000000..6be82c1 --- /dev/null +++ b/ext/spl/tests/bug41528.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug #41528 (Classes extending ArrayObject do not serialize correctly) +--FILE-- +<?php +class ClassOne extends ArrayObject +{ + public $a = 2; +} + +$classOne = new ClassOne(); +$classOne->a = 1; + +var_dump($classOne); +var_dump($classOne->a); + +$classOne = unserialize(serialize($classOne)); + +var_dump($classOne); +var_dump($classOne->a); +?> +--EXPECT-- +object(ClassOne)#1 (2) { + ["a"]=> + int(1) + ["storage":"ArrayObject":private]=> + array(0) { + } +} +int(1) +object(ClassOne)#2 (2) { + ["a"]=> + int(1) + ["storage":"ArrayObject":private]=> + array(0) { + } +} +int(1) diff --git a/ext/spl/tests/bug41691.phpt b/ext/spl/tests/bug41691.phpt new file mode 100644 index 0000000..3cf3d87 --- /dev/null +++ b/ext/spl/tests/bug41691.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #41691 (ArrayObject::exchangeArray hangs Apache) +--FILE-- +<?php + +class A extends ArrayObject { + public function __construct($dummy, $flags) { + parent::__construct($this, $flags); + } + public $a; + public $b; + public $c; +} + +$a = new A(null, ArrayObject::ARRAY_AS_PROPS ); +var_dump($a->exchangeArray(array('a'=>1,'b'=>1,'c'=>1))); + +echo "Done\n"; +?> +--EXPECTF-- +array(3) { + ["a"]=> + NULL + ["b"]=> + NULL + ["c"]=> + NULL +} +Done diff --git a/ext/spl/tests/bug41692.phpt b/ext/spl/tests/bug41692.phpt new file mode 100644 index 0000000..c9b7d8d --- /dev/null +++ b/ext/spl/tests/bug41692.phpt @@ -0,0 +1,64 @@ +--TEST-- +Bug #41692 (ArrayObject shows weird behaviour in respect to inheritance) +--FILE-- +<?php + +class Bar extends ArrayObject { + private $foo = array( 1, 2, 3 ); + function __construct() + { + parent::__construct($this->foo); + } +} + +$foo = new Bar(); +var_dump($foo); +$foo['foo'] = 23; + +$bar = new Bar(); +var_dump($bar); + +echo "Done\n"; +?> +--EXPECTF-- +object(Bar)#%d (2) { + ["foo":"Bar":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +object(Bar)#%d (2) { + ["foo":"Bar":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + } +} +Done diff --git a/ext/spl/tests/bug41828.phpt b/ext/spl/tests/bug41828.phpt new file mode 100644 index 0000000..6053e0e --- /dev/null +++ b/ext/spl/tests/bug41828.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #41828 (Segfault if extended constructor of RecursiveIterator doesn't call its parent) +--FILE-- +<?php +class foo extends RecursiveIteratorIterator { + + public function __construct($str) { + } + + public function bar() { + } +} + +$foo = new foo("This is bar"); +echo $foo->bar(); + +?> +==DONE== +<?php exit(0); ?> +--EXPECTF-- +Fatal error: main(): The foo instance wasn't initialized properly in %s on line %d diff --git a/ext/spl/tests/bug42364.phpt b/ext/spl/tests/bug42364.phpt new file mode 100644 index 0000000..971fcc5 --- /dev/null +++ b/ext/spl/tests/bug42364.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #42364 (Crash when using getRealPath with DirectoryIterator) +--FILE-- +<?php +$it = new DirectoryIterator(dirname(__FILE__)); + +$count = 0; + +foreach ($it as $e) { + $count++; + $type = gettype($e->getRealPath()); + if ($type != "string" && $type != "unicode") { + echo $e->getFilename(), " is a ", gettype($e->getRealPath()), "\n"; + } +} + +if ($count > 0) { + echo "Found $count entries!\n"; +} +?> +===DONE=== +--EXPECTF-- +Found %i entries! +===DONE=== diff --git a/ext/spl/tests/bug42654.phpt b/ext/spl/tests/bug42654.phpt new file mode 100644 index 0000000..20aad74 --- /dev/null +++ b/ext/spl/tests/bug42654.phpt @@ -0,0 +1,158 @@ +--TEST-- +Bug #42654 (RecursiveIteratorIterator modifies only part of leaves) +--FILE-- +<?php +$data = array(1 => 'val1', + array(2 => 'val2', + array(3 => 'val3'), + ), + 4 => 'val4' + ); + +$iterator = new RecursiveIteratorIterator(new +RecursiveArrayIterator($data)); +foreach($iterator as $foo) { + $key = $iterator->key(); + echo "update $key\n"; + var_dump($iterator->getInnerIterator()); + $iterator->offsetSet($key, 'alter'); + var_dump($iterator->getInnerIterator()); +} +$copy = $iterator->getArrayCopy(); +var_dump($copy); +?> +--EXPECTF-- +update 1 +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(3) { + [1]=> + string(4) "val1" + [2]=> + array(2) { + [2]=> + string(4) "val2" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } + [4]=> + string(4) "val4" + } +} +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(3) { + [1]=> + string(5) "alter" + [2]=> + array(2) { + [2]=> + string(4) "val2" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } + [4]=> + string(4) "val4" + } +} +update 2 +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(2) { + [2]=> + string(4) "val2" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } +} +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(2) { + [2]=> + string(5) "alter" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } +} +update 3 +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(1) { + [3]=> + string(4) "val3" + } +} +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(1) { + [3]=> + string(5) "alter" + } +} +update 4 +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(3) { + [1]=> + string(5) "alter" + [2]=> + array(2) { + [2]=> + string(4) "val2" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } + [4]=> + string(4) "val4" + } +} +object(RecursiveArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(3) { + [1]=> + string(5) "alter" + [2]=> + array(2) { + [2]=> + string(4) "val2" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } + [4]=> + string(5) "alter" + } +} +array(3) { + [1]=> + string(5) "alter" + [2]=> + array(2) { + [2]=> + string(4) "val2" + [3]=> + array(1) { + [3]=> + string(4) "val3" + } + } + [4]=> + string(5) "alter" +} diff --git a/ext/spl/tests/bug42703.phpt b/ext/spl/tests/bug42703.phpt new file mode 100644 index 0000000..5c52763 --- /dev/null +++ b/ext/spl/tests/bug42703.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug #42703 (Exception raised in an iterator::current() causes segfault in FilterIterator) +--FILE-- +<?php +class BlaIterator implements Iterator +{ + public function rewind() { } + + public function next() { } + + public function valid() { + return true; + } + + public function current() + { + throw new Exception('boo'); + } + + public function key() { } +} + +$it = new BlaIterator(); +$itit = new IteratorIterator($it); + +try { + foreach($itit as $key => $value) { + echo $key, $value; + } +} +catch (Exception $e) { + var_dump($e->getMessage()); +} + +var_dump($itit->current()); +var_dump($itit->key()); +?> +--EXPECTF-- +string(3) "boo" +NULL +NULL diff --git a/ext/spl/tests/bug44144.phpt b/ext/spl/tests/bug44144.phpt new file mode 100644 index 0000000..2933d2f --- /dev/null +++ b/ext/spl/tests/bug44144.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #44144 (spl_autoload_functions() should return object instance when appropriate) +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php +class Foo { + public function nonstaticMethod() {} +} +$foo = new Foo; +spl_autoload_register(array($foo, 'nonstaticMethod')); +$funcs = spl_autoload_functions(); +var_dump($funcs); +?> +--EXPECTF-- +array(1) { + [0]=> + array(2) { + [0]=> + object(Foo)#%d (0) { + } + [1]=> + string(15) "nonstaticMethod" + } +} + + diff --git a/ext/spl/tests/bug44615.phpt b/ext/spl/tests/bug44615.phpt new file mode 100644 index 0000000..1fd3d19 --- /dev/null +++ b/ext/spl/tests/bug44615.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: RecursiveArrayIterator bug 44615 +--CREDITS-- +Julien Pauli <doctorrock83@gmail.com> +#testfest phpcampparis 2008-06-07 +--FILE-- +<?php +$a = new stdClass(); + +$array = array(array('z',$a),array('q','s')); + +$rai = new RecursiveArrayIterator($array,RecursiveArrayIterator::CHILD_ARRAYS_ONLY); + +foreach (new RecursiveIteratorIterator($rai) as $t) { + var_dump($t); +} +echo "Second:\n"; +$rai = new RecursiveArrayIterator($array); +foreach (new RecursiveIteratorIterator($rai) as $t) { + var_dump($t); +} +?> +--EXPECTF-- +string(1) "z" +object(stdClass)#1 (0) { +} +string(1) "q" +string(1) "s" +Second: +string(1) "z" +string(1) "q" +string(1) "s" diff --git a/ext/spl/tests/bug45216.phpt b/ext/spl/tests/bug45216.phpt new file mode 100644 index 0000000..b3c4aa5 --- /dev/null +++ b/ext/spl/tests/bug45216.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject::fgetss (bug 45216) +--CREDITS-- +Perrick Penet <perrick@noparking.net> +#testfest phpcampparis 2008-06-07 +--FILE-- +<?php +$file = dirname(__FILE__) . '/foo.html'; +file_put_contents($file, 'text 0<div class="tested">text 1</div>'); +$handle = fopen($file, 'r'); + +$object = new SplFileObject($file); +var_dump($object->fgetss()); +var_dump(fgetss($handle)); +?> +--CLEAN-- +<?php +unlink(dirname(__FILE__) . '/foo.html'); +?> +--EXPECTF-- +string(12) "text 0text 1" +string(12) "text 0text 1" diff --git a/ext/spl/tests/bug45614.phpt b/ext/spl/tests/bug45614.phpt new file mode 100644 index 0000000..8f99934 --- /dev/null +++ b/ext/spl/tests/bug45614.phpt @@ -0,0 +1,56 @@ +--TEST-- +SPL: Bug#45614 (ArrayIterator can show 1st private prop of wrapped object) +--FILE-- +<?php +class C { + private $priv1 = 'secret1'; + private $priv2 = 'secret2'; + public $pub1 = 'public1'; + public $pub2 = 'public2'; + public $pub3 = 'public3'; +} + +function showFirstTwoItems($it) { + echo str_replace("\0", '\0', $it->key()) . " => " . $it->current() . +"\n"; + $it->next(); + echo str_replace("\0", '\0', $it->key()) . " => " . $it->current() . +"\n"; +} + +$ao = new ArrayObject(new C); +$ai = $ao->getIterator(); + +echo "--> Show the first two items:\n"; +showFirstTwoItems($ai); + +echo "\n--> Rewind and show the first two items:\n"; +$ai->rewind(); +showFirstTwoItems($ai); + +echo "\n--> Invalidate current position and show the first two items:\n"; +unset($ai[$ai->key()]); +$ai->current(); +showFirstTwoItems($ai); + +echo "\n--> Rewind, seek and show the first two items:\n"; +$ai->rewind(); +$ai->seek(0); +showFirstTwoItems($ai); +?> +--EXPECT-- +--> Show the first two items: +pub1 => public1 +pub2 => public2 + +--> Rewind and show the first two items: +pub1 => public1 +pub2 => public2 + +--> Invalidate current position and show the first two items: +pub1 => public1 +pub3 => public3 + +--> Rewind, seek and show the first two items: +pub1 => public1 +pub3 => public3 diff --git a/ext/spl/tests/bug45622.phpt b/ext/spl/tests/bug45622.phpt new file mode 100644 index 0000000..a8fe2c4 --- /dev/null +++ b/ext/spl/tests/bug45622.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: Bug #45622 (isset($arrayObject->p) misbehaves with ArrayObject::ARRAY_AS_PROPS set +--FILE-- +<?php + +class C extends ArrayObject { + public $p = 'object property'; +} + +$ao = new C(array('p'=>'array element')); +$ao->setFlags(ArrayObject::ARRAY_AS_PROPS); + +echo "\n--> Access the real property:\n"; +var_dump(isset($ao->p)); +var_dump($ao->p); + +echo "\n--> Remove the real property and access the array element:\n"; +unset($ao->p); +var_dump(isset($ao->p)); +var_dump($ao->p); + +echo "\n--> Remove the array element and try access again:\n"; +unset($ao->p); +var_dump(isset($ao->p)); +var_dump($ao->p); + +echo "\n--> Re-add the real property:\n"; +$ao->p = 'object property'; +var_dump(isset($ao->p)); +var_dump($ao->p); +?> +--EXPECTF-- + +--> Access the real property: +bool(true) +%unicode|string%(15) "object property" + +--> Remove the real property and access the array element: +bool(true) +%unicode|string%(13) "array element" + +--> Remove the array element and try access again: +bool(false) + +Notice: Undefined index: p in %s on line %d +NULL + +--> Re-add the real property: +bool(true) +%unicode|string%(15) "object property" + diff --git a/ext/spl/tests/bug45622b.phpt b/ext/spl/tests/bug45622b.phpt new file mode 100644 index 0000000..f101a84 --- /dev/null +++ b/ext/spl/tests/bug45622b.phpt @@ -0,0 +1,33 @@ +--TEST-- +Ensure fix to bug45622 doesn't cause __isset() to be called when ArrayObject::ARRAY_AS_PROPS is used. +--FILE-- +<?php +class UsesMagic extends ArrayObject { + function __get($n) { echo "In " . __METHOD__ . "!\n"; } + function __set($n, $v) { echo "In " . __METHOD__ . "!\n"; } + function __isset($n) { echo "In " . __METHOD__ . "!\n"; } + function __unset($n) { echo "In " . __METHOD__ . "!\n"; } +} +$ao = new UsesMagic(array(), ArrayObject::ARRAY_AS_PROPS); + +echo "Doesn't trigger __get.\n"; +echo $ao->prop1; + +echo "Doesn't trigger __set.\n"; +$ao->prop2 = 'foo'; + +echo "Doesn't trigger __unset.\n"; +unset($ao->prop3); + +echo "Shouldn't trigger __isset.\n"; +isset($ao->prop4); +?> +--EXPECTF-- +Doesn't trigger __get. + +Notice: Undefined index: prop1 in %s on line 11 +Doesn't trigger __set. +Doesn't trigger __unset. + +Notice: Undefined index: prop3 in %s on line 17 +Shouldn't trigger __isset.
\ No newline at end of file diff --git a/ext/spl/tests/bug45826.phpt b/ext/spl/tests/bug45826.phpt new file mode 100644 index 0000000..7993bfa --- /dev/null +++ b/ext/spl/tests/bug45826.phpt @@ -0,0 +1,88 @@ +--TEST-- +ArrayObject/ArrayIterator : serialization +--FILE-- +<?php +$o = new ArrayObject(); +$y = new StdClass; +$o->append($y); +$o->append($y); +$o->append($o); + +var_dump($o[0] === $o[1]); +var_dump($o[2] === $o); + +$s1 = serialize($o); +$s2 = $o->serialize(); +var_dump($s1); +var_dump($s2); + +$o1 =unserialize($s1); + +var_dump($o1[0] === $o1[1]); +var_dump($o1[2] === $o1); + +$o2 = new ArrayObject(); +$o2->unserialize($s2); + +var_dump($o2[0] === $o2[1]); +var_dump($o2[2] !== $o2); +var_dump($o2[2][2] === $o2[2]); + +echo "#### Extending ArrayObject\n"; +unset($o,$x,$s1,$s2,$o1,$o2); +class ArrayObject2 extends ArrayObject { + public function serialize() { + return parent::serialize(); + } + + public function unserialize($s) { + return parent::unserialize($s); + } +} + +$o = new ArrayObject2(); +$y = new StdClass; +$o->append($y); +$o->append($y); +$o->append($o); + +var_dump($o[0] === $o[1]); +var_dump($o[2] === $o); + +$s1 = serialize($o); +$s2 = $o->serialize(); +var_dump($s1); +var_dump($s2); + +$o1 =unserialize($s1); + +var_dump($o1[0] === $o1[1]); +var_dump($o1[2] === $o1); + +$o2 = new ArrayObject2(); +$o2->unserialize($s2); + +var_dump($o2[0] === $o2[1]); +var_dump($o2[2] !== $o2); +var_dump($o2[2][2] === $o2[2]); +?> +--EXPECT-- +bool(true) +bool(true) +string(84) "C:11:"ArrayObject":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}" +string(125) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:11:"ArrayObject":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}" +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +#### Extending ArrayObject +bool(true) +bool(true) +string(85) "C:12:"ArrayObject2":60:{x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:4;i:2;r:1;};m:a:0:{}}" +string(126) "x:i:0;a:3:{i:0;O:8:"stdClass":0:{}i:1;r:3;i:2;C:12:"ArrayObject2":45:{x:i:0;a:3:{i:0;r:3;i:1;r:3;i:2;r:5;};m:a:0:{}}};m:a:0:{}" +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/spl/tests/bug46031.phpt b/ext/spl/tests/bug46031.phpt new file mode 100644 index 0000000..9261ff0 --- /dev/null +++ b/ext/spl/tests/bug46031.phpt @@ -0,0 +1,9 @@ +--TEST-- +Bug #46031 (Segfault in AppendIterator::next) +--FILE-- +<?php +$x = new AppendIterator(); +var_dump($x->next()); +?> +--EXPECT-- +NULL diff --git a/ext/spl/tests/bug46051.phpt b/ext/spl/tests/bug46051.phpt new file mode 100644 index 0000000..49a5824 --- /dev/null +++ b/ext/spl/tests/bug46051.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #46051 (SplFileInfo::openFile - memory overlap) +--FILE-- +<?php + +$x = new splfileinfo(__FILE__); + +try { +$x->openFile(NULL, NULL, NULL); +} catch (Exception $e) { } + +var_dump($x->getPathName()); +--EXPECTF-- +%unicode|string%(%d) "%sbug46051.php" diff --git a/ext/spl/tests/bug46053.phpt b/ext/spl/tests/bug46053.phpt new file mode 100644 index 0000000..75da7f3 --- /dev/null +++ b/ext/spl/tests/bug46053.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #46053 (SplFileObject::seek - Endless loop) +--FILE-- +<?php + +$x = new splfileobject(__FILE__); +$x->getPathName(); +$x->seek(10); +$x->seek(0); +var_dump(trim($x->fgets())); +--EXPECTF-- +string(%d) "<?php" diff --git a/ext/spl/tests/bug46088.phpt b/ext/spl/tests/bug46088.phpt new file mode 100644 index 0000000..4785377 --- /dev/null +++ b/ext/spl/tests/bug46088.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #46088 (RegexIterator::accept - segfault) +--FILE-- +<?php + +$x = new RegexIterator(new ArrayIterator(range(1, 10)), '/\d/'); +var_dump($x->accept()); + +?> +--EXPECT-- +bool(false) diff --git a/ext/spl/tests/bug46115.phpt b/ext/spl/tests/bug46115.phpt new file mode 100644 index 0000000..71207d8 --- /dev/null +++ b/ext/spl/tests/bug46115.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #46115 (Memory leak when calling a method using Reflection) +--FILE-- +<?php +$h = new RecursiveArrayIterator(array()); +$x = new reflectionmethod('RecursiveArrayIterator', 'asort'); +$z = $x->invoke($h); +?> +DONE +--EXPECT-- +DONE diff --git a/ext/spl/tests/bug46160.phpt b/ext/spl/tests/bug46160.phpt new file mode 100644 index 0000000..e4dbdff --- /dev/null +++ b/ext/spl/tests/bug46160.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #46160 (SPL - Memory leak when exception is throwed in offsetSet method) +--FILE-- +<?php + +try { + $x = new splqueue; + $x->offsetSet(0, 0); +} catch (Exception $e) { } + +?> +DONE +--EXPECT-- +DONE diff --git a/ext/spl/tests/bug47534.phpt b/ext/spl/tests/bug47534.phpt new file mode 100644 index 0000000..d221c23 --- /dev/null +++ b/ext/spl/tests/bug47534.phpt @@ -0,0 +1,14 @@ +--TEST-- +SPL: RecursiveDirectoryIterator bug 47534 +--FILE-- +<?php +$it1 = new RecursiveDirectoryIterator(dirname(__FILE__), FileSystemIterator::CURRENT_AS_PATHNAME); +$it1->rewind(); +echo gettype($it1->current())."\n"; + +$it2 = new RecursiveDirectoryIterator(dirname(__FILE__)); +$it2->rewind(); +echo gettype($it2->current())."\n"; +--EXPECT-- +string +object diff --git a/ext/spl/tests/bug48023.phpt b/ext/spl/tests/bug48023.phpt new file mode 100644 index 0000000..ed0ff9e --- /dev/null +++ b/ext/spl/tests/bug48023.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #48023 (spl_autoload_register didn't addref closures) +--FILE-- +<?php +spl_autoload_register(function(){}); + +new Foo; + +?> +===DONE=== +--EXPECTF-- +Fatal error: Class 'Foo' not found in %s on line %d diff --git a/ext/spl/tests/bug48361.phpt b/ext/spl/tests/bug48361.phpt new file mode 100644 index 0000000..44b05ab --- /dev/null +++ b/ext/spl/tests/bug48361.phpt @@ -0,0 +1,14 @@ +--TEST-- +SPL: Bug #48361 SpleFileInfo::getPathName should return the dirname's path +--FILE-- +<?php +$info = new SplFileInfo(__FILE__); +var_dump($info->getRealPath()); +var_dump($info->getPathInfo()->getRealPath()); +?> +===DONE=== +--EXPECTF-- +string(%d) "%stests%sbug48361.php" +string(%d) "%stests" +===DONE=== + diff --git a/ext/spl/tests/bug48493.phpt b/ext/spl/tests/bug48493.phpt new file mode 100644 index 0000000..d0be7f8 --- /dev/null +++ b/ext/spl/tests/bug48493.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: Bug #48493 spl_autoload_unregister() can't handle prepended functions +--FILE-- +<?php +function autoload1() {} + +function autoload2() {} + +spl_autoload_register('autoload2'); +spl_autoload_register('autoload1', true, true); +var_dump(spl_autoload_functions()); + +spl_autoload_unregister('autoload2'); +var_dump(spl_autoload_functions()); +?> +--EXPECT-- +array(2) { + [0]=> + string(9) "autoload1" + [1]=> + string(9) "autoload2" +} +array(1) { + [0]=> + string(9) "autoload1" +} diff --git a/ext/spl/tests/bug49263.phpt b/ext/spl/tests/bug49263.phpt new file mode 100644 index 0000000..2075577 --- /dev/null +++ b/ext/spl/tests/bug49263.phpt @@ -0,0 +1,54 @@ +--TEST-- +SPL: SplObjectStorage serialization references +--SKIPIF-- +<?php if (!extension_loaded("spl")) print "skip"; ?> +--FILE-- +<?php +$o1 = new stdClass; +$o2 = new stdClass; + +$s = new splObjectStorage(); + +$s->attach($o1, array('prev' => 2, 'next' => $o2)); +$s->attach($o2, array('prev' => $o1)); + +$ss = serialize($s); +unset($s,$o1,$o2); +echo $ss."\n"; +var_dump(unserialize($ss)); +?> +===DONE=== +--EXPECTF-- +C:16:"SplObjectStorage":113:{x:i:2;O:8:"stdClass":0:{},a:2:{s:4:"prev";i:2;s:4:"next";O:8:"stdClass":0:{}};r:6;,a:1:{s:4:"prev";r:3;};m:a:0:{}} +object(SplObjectStorage)#2 (1) { + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#1 (0) { + } + ["inf"]=> + array(2) { + ["prev"]=> + int(2) + ["next"]=> + object(stdClass)#3 (0) { + } + } + } + ["%s"]=> + array(2) { + ["obj"]=> + object(stdClass)#3 (0) { + } + ["inf"]=> + array(1) { + ["prev"]=> + object(stdClass)#1 (0) { + } + } + } + } +} +===DONE=== diff --git a/ext/spl/tests/bug49723.phpt b/ext/spl/tests/bug49723.phpt new file mode 100644 index 0000000..221e806 --- /dev/null +++ b/ext/spl/tests/bug49723.phpt @@ -0,0 +1,16 @@ +--TEST-- +LimitIterator: do not seek if not needed +--FILE-- +<?php + +$it = new ArrayIterator(array()); + +$lit = new LimitIterator($it, 0, 5); + +foreach ($lit as $v) { + echo $v; +} +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/ext/spl/tests/bug49972.phpt b/ext/spl/tests/bug49972.phpt new file mode 100644 index 0000000..843c251 --- /dev/null +++ b/ext/spl/tests/bug49972.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #49972 (AppendIterator undefined function crash) +--FILE-- +<?php + +$iterator = new AppendIterator(); +$iterator->undefined(); + +?> +--EXPECTF-- +Fatal error: Call to undefined method AppendIterator::undefined() in %s on line %d diff --git a/ext/spl/tests/bug50579.phpt b/ext/spl/tests/bug50579.phpt new file mode 100644 index 0000000..e32262a --- /dev/null +++ b/ext/spl/tests/bug50579.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #50579 (RegexIterator::REPLACE doesn't work) +--FILE-- +<?php + +class foo extends ArrayIterator { + public function __construct( ) { + parent::__construct(array( + 'test1'=>'test888', + 'test2'=>'what?', + 'test3'=>'test999')); + } +} +$h = new foo; +$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE); +$i->replacement = '[$0]'; +foreach ($i as $name=>$value) { + echo $name . '=>' . $value . "\n"; +} + +$i->replacement = '$1'; +foreach ($i as $name=>$value) { + echo $name . '=>' . $value . "\n"; +} + +$h = new foo; +$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE); +$i->replacement = '[$1]'; +foreach ($i as $name=>$value) { + echo $name . '=>' . $value . "\n"; +} + +?> +--EXPECTF-- +test1=>[test888] +test3=>[test999] +test1=>888 +test3=>999 +test1=>[888] +test3=>[999] diff --git a/ext/spl/tests/bug51119.phpt b/ext/spl/tests/bug51119.phpt new file mode 100644 index 0000000..441aa12 --- /dev/null +++ b/ext/spl/tests/bug51119.phpt @@ -0,0 +1,34 @@ +--TEST-- +SPL: LimitIterator zero is valid offset +--FILE-- +<?php + +$array = array('a', 'b', 'c'); +$arrayIterator = new ArrayIterator($array); + +try { + $limitIterator = new LimitIterator($arrayIterator, 0); + foreach ($limitIterator as $item) { + echo $item . "\n"; + } +} catch (OutOfRangeException $e){ + print $e->getMessage() . "\n"; +} + +try { + $limitIterator = new LimitIterator($arrayIterator, -1); + foreach ($limitIterator as $item) { + echo $item . "\n"; + } +} catch (OutOfRangeException $e){ + print $e->getMessage() . "\n"; +} + +?> +===DONE=== +--EXPECT-- +a +b +c +Parameter offset must be >= 0 +===DONE=== diff --git a/ext/spl/tests/bug51374.phpt b/ext/spl/tests/bug51374.phpt new file mode 100644 index 0000000..a4d2853 --- /dev/null +++ b/ext/spl/tests/bug51374.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplFileObject wrongly initializes objects +--FILE-- +<?php +class Foo extends SplFileObject +{ + public $bam = array(); +} +$fileInfo = new SplFileInfo('php://temp'); +$fileInfo->setFileClass('Foo'); +$file = $fileInfo->openFile('r'); + +print var_dump($file->bam); // is null or UNKNOWN:0 +?> +===DONE=== +--EXPECT-- +array(0) { +} +===DONE=== diff --git a/ext/spl/tests/bug51532.phpt b/ext/spl/tests/bug51532.phpt new file mode 100644 index 0000000..3a0722b --- /dev/null +++ b/ext/spl/tests/bug51532.phpt @@ -0,0 +1,14 @@ +--TEST-- +SPL: Allow valid extension of SplFileObject::fscanf +--FILE-- +<?php + +class A extends SplFileObject { + public function fscanf($format) { + + } +} +?> +===DONE=== +--EXPECT-- +===DONE=== diff --git a/ext/spl/tests/bug52238.phpt b/ext/spl/tests/bug52238.phpt new file mode 100644 index 0000000..10da0b5 --- /dev/null +++ b/ext/spl/tests/bug52238.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #52238 - Crash when an Exception occurred in iterator_to_array +--FILE-- +<?php +class Foo implements IteratorAggregate +{ + public function bar() { + throw new Exception; + } + + public function getIterator() { + return new ArrayIterator($this->bar()); + } +} +var_dump(iterator_to_array(new Foo)); +?> +--EXPECTF-- +Fatal error: Uncaught exception 'Exception' in %s +Stack trace: +#0 %s: Foo->bar() +#1 [internal function]: Foo->getIterator() +#2 %s: iterator_to_array(Object(Foo)) +#3 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/bug52573.phpt b/ext/spl/tests/bug52573.phpt new file mode 100644 index 0000000..54587fa --- /dev/null +++ b/ext/spl/tests/bug52573.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #52573 (SplFileObject::fscanf Segmentation fault) +--FILE-- +<?php // test + +$result = null; +$f = new SplFileObject(__FILE__, 'r'); +var_dump($f->fscanf('<?php // %s', $result)); +var_dump($result); +var_dump($f->fscanf('<?php // %s')); +?> +--EXPECTF-- +int(1) +string(4) "test" +array(1) { + [0]=> + NULL +} diff --git a/ext/spl/tests/bug52861.phpt b/ext/spl/tests/bug52861.phpt new file mode 100644 index 0000000..30a3261 --- /dev/null +++ b/ext/spl/tests/bug52861.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #52861 (unset failes with ArrayObject and deep arrays) +--FILE-- +<?php +$arrayObject = new ArrayObject(array('foo' => array('bar' => array('baz' => 'boo')))); + +unset($arrayObject['foo']['bar']['baz']); +print_r($arrayObject->getArrayCopy()); +?> +--EXPECT-- +Array +( + [foo] => Array + ( + [bar] => Array + ( + ) + + ) + +) + diff --git a/ext/spl/tests/bug53071.phpt b/ext/spl/tests/bug53071.phpt new file mode 100644 index 0000000..c2c2605 --- /dev/null +++ b/ext/spl/tests/bug53071.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #53071 (Usage of SPLObjectStorage defeats gc_collect_cycles) +--FILE-- +<?php +gc_enable(); +class myClass +{ + public $member; +} +function LimitedScope() +{ + $myA = new myClass(); + $myB = new SplObjectStorage(); + $myC = new myClass(); + $myC->member = $myA; // myC has a referece to myA + $myB->Attach($myC); // myB attaches myC + $myA->member = $myB; // myA has myB, comleting the cycle +} +LimitedScope(); +var_dump(gc_collect_cycles()); + +echo "Done.\n"; + +?> +--EXPECTF-- +int(5) +Done. diff --git a/ext/spl/tests/bug53144.phpt b/ext/spl/tests/bug53144.phpt new file mode 100644 index 0000000..7cf179b --- /dev/null +++ b/ext/spl/tests/bug53144.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #53144 (Segfault in SplObjectStorage::removeAll) +--FILE-- +<?php + +$o1 = new StdClass; +$o2 = new StdClass; + +$b = new SplObjectStorage(); +$b[$o1] = "bar"; +$b[$o2] = "baz"; + +var_dump(count($b)); +$b->removeAll($b); +var_dump(count($b)); + +?> +--EXPECTF-- +int(2) +int(0)
\ No newline at end of file diff --git a/ext/spl/tests/bug53362.phpt b/ext/spl/tests/bug53362.phpt new file mode 100644 index 0000000..70ba6e2 --- /dev/null +++ b/ext/spl/tests/bug53362.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #53362 (Segmentation fault when extending SplFixedArray) +--FILE-- +<?php + +class obj extends SplFixedArray{ + public function offsetSet($offset, $value) { + var_dump($offset); + } +} + +$obj = new obj; + +$obj[]=2; +$obj[]=2; +$obj[]=2; + +?> +--EXPECTF-- +NULL +NULL +NULL diff --git a/ext/spl/tests/bug53515.phpt b/ext/spl/tests/bug53515.phpt new file mode 100644 index 0000000..8ecb02b --- /dev/null +++ b/ext/spl/tests/bug53515.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #53515 (property_exists incorrect on ArrayObject null and 0 values) +--FILE-- +<?php + +$a = array('a' => 1, 'b'=> true, 'c' => 0, 'd' => null, 'e' => false, 'f' => array()); +$o = new ArrayObject($a, ArrayObject::ARRAY_AS_PROPS); + +$a['z'] = ''; +$a[''] = ''; + +foreach ($a as $key => $value) { + echo $key . ': ' . (is_null($value) ? 'null' : @"$value") . + ' array_key_exists: ' . (array_key_exists($key, $a) ? 'true' : 'false') . + ' property_exists: ' . (property_exists($o, $key) ? 'true' : 'false'),"\n"; +} + +?> +--EXPECT-- +a: 1 array_key_exists: true property_exists: true +b: 1 array_key_exists: true property_exists: true +c: 0 array_key_exists: true property_exists: true +d: null array_key_exists: true property_exists: true +e: array_key_exists: true property_exists: true +f: Array array_key_exists: true property_exists: true +z: array_key_exists: true property_exists: false +: array_key_exists: true property_exists: false diff --git a/ext/spl/tests/bug54281.phpt b/ext/spl/tests/bug54281.phpt new file mode 100644 index 0000000..d42d9e5 --- /dev/null +++ b/ext/spl/tests/bug54281.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #54281 (Crash in spl_recursive_it_rewind_ex) +--FILE-- +<?php + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator { + function __construct($it, $max_depth) { } +} +$it = new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array()), 2); + +foreach($it as $k=>$v) { } + +?> +--EXPECTF-- +Fatal error: RecursiveIteratorIterator::rewind(): The RecursiveArrayIteratorIterator instance wasn't initialized properly in %s on line %d diff --git a/ext/spl/tests/bug54291.phpt b/ext/spl/tests/bug54291.phpt new file mode 100644 index 0000000..b8f596e --- /dev/null +++ b/ext/spl/tests/bug54291.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #54291 (Crash iterating DirectoryIterator for dir name starting with \0) +--FILE-- +<?php +$dir = new DirectoryIterator("\x00/abc"); +$dir->isFile(); +--EXPECTF-- +Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Failed to open directory ""' in %s:%d +Stack trace: +#0 %s(%d): DirectoryIterator->__construct('?/abc') +#1 {main} + thrown in %s on line %d + diff --git a/ext/spl/tests/bug54292.phpt b/ext/spl/tests/bug54292.phpt new file mode 100644 index 0000000..d9175f7 --- /dev/null +++ b/ext/spl/tests/bug54292.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #54292 (Wrong parameter causes crash in SplFileObject::__construct()) +--FILE-- +<?php + +try { + new SplFileObject('foo', array()); +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +?> +--EXPECTF-- +string(74) "SplFileObject::__construct() expects parameter 2 to be string, array given" diff --git a/ext/spl/tests/bug54304.phpt b/ext/spl/tests/bug54304.phpt new file mode 100644 index 0000000..32cbe48 --- /dev/null +++ b/ext/spl/tests/bug54304.phpt @@ -0,0 +1,26 @@ +--TEST-- +Bug #54304 (Setting replacement value for RegexIterator doesn't work) +--FILE-- +<?php +class foo extends ArrayIterator { + public function __construct( ) { + parent::__construct(array( + 'test3'=>'test999')); + } +} + +$h = new foo; +$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE); +$i->replacement = 42; +var_dump($i->replacement); +foreach ($i as $name=>$value) { + var_dump($name, $value); +} +var_dump($i->replacement); +?> +--EXPECT-- +int(42) +string(5) "test3" +string(2) "42" +int(42) + diff --git a/ext/spl/tests/bug54323.phpt b/ext/spl/tests/bug54323.phpt new file mode 100644 index 0000000..df6416a --- /dev/null +++ b/ext/spl/tests/bug54323.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #54323 (Accessing unset()'ed ArrayObject's property causes crash) +--FILE-- +<?php +class C { + public $prop = 'C::prop.orig'; +} +class MyArrayObject extends ArrayObject { +} +$c = new C; +$ao = new MyArrayObject($c); +testAccess($c, $ao); +function testAccess($c, $ao) { + foreach ($ao as $key=>$value) { + } + unset($ao['prop']); + var_dump($c->prop, $ao['prop']); +} +--EXPECTF-- +Notice: Undefined property: C::$prop in %sbug54323.php on line 14 + +Notice: Undefined index: prop in %sbug54323.php on line 14 +NULL +NULL diff --git a/ext/spl/tests/bug54384.phpt b/ext/spl/tests/bug54384.phpt new file mode 100644 index 0000000..a1ce7ed --- /dev/null +++ b/ext/spl/tests/bug54384.phpt @@ -0,0 +1,171 @@ +--TEST-- +Bug #54384: Several SPL classes crash when the parent constructor is not called +--FILE-- +<?php + +function test($f) { + try { + $f(); + echo "ran normally (unexpected)\n\n"; + } catch (LogicException $e) { + echo "exception (expected)\n"; + } +} + +echo "IteratorIterator... "; +class IteratorIteratorTest extends IteratorIterator { + function __construct(){} +} +test( function() { + $o = new IteratorIteratorTest; + $o->rewind(); +} ); + +echo "FilterIterator... "; +class FilterIteratorTest extends FilterIterator { + function __construct(){} + function accept(){} +} +test( function() { + $o = new FilterIteratorTest; + $o->rewind(); +} ); + +echo "RecursiveFilterIterator... "; +class RecursiveFilterIteratorTest extends RecursiveFilterIterator { + function __construct(){} + function accept(){} +} +test( function() { +$o = new RecursiveFilterIteratorTest; +$o->hasChildren(); +} ); + +echo "ParentIterator... "; +class ParentIteratorTest extends ParentIterator { + function __construct(){} +} +test ( function() { +$o = new ParentIteratorTest; +$o->accept(); +} ); + +echo "LimitIterator... "; +class LimitIteratorTest extends LimitIterator { + function __construct(){} +} +test ( function() { +$o = new LimitIteratorTest; +$o->rewind(); +} ); + +echo "CachingIterator... "; +class CachingIteratorTest extends CachingIterator { + function __construct(){} +} +test ( function() { +$o = new CachingIteratorTest; +$o->rewind(); +} ); + +echo "RecursiveCachingIterator... "; +class RecursiveCachingIteratorTest extends RecursiveCachingIterator { + function __construct(){} +} +test ( function() { +$o = new RecursiveCachingIteratorTest; +$o->rewind(); +} ); + +echo "NoRewindIterator... "; +class NoRewindIteratorTest extends NoRewindIterator { + function __construct(){} +} +test ( function() { +$o = new NoRewindIteratorTest; +$o->valid(); +} ); + +echo "RegexIterator... "; +class RegexIteratorTest extends RegexIterator { + function __construct(){} +} +test ( function() { +$o = new RegexIteratorTest; +$o->rewind(); +} ); + +echo "RecursiveRegexIterator... "; +class RecursiveRegexIteratorTest extends RecursiveRegexIterator { + function __construct(){} +} +test ( function() { +$o = new RecursiveRegexIteratorTest; +$o->hasChildren(); +} ); + +echo "GlobIterator... "; +class GlobIteratorTest extends GlobIterator { + function __construct(){} +} +test ( function() { +$o = new GlobIteratorTest; +$o->count(); +} ); + +echo "SplFileObject... "; +class SplFileObjectTest extends SplFileObject { + function __construct(){} +} +test ( function() { +$o = new SplFileObjectTest; +$o->rewind(); +} ); + +echo "SplTempFileObject... "; +class SplTempFileObjectTest extends SplTempFileObject { + function __construct(){} +} +test ( function() { +$o = new SplTempFileObjectTest; +$o->rewind(); +} ); + +echo "AppendIterator... "; +class AppendIteratorTest extends AppendIterator { + function __construct(){} +} +test ( function() { +$o = new AppendIteratorTest; +foreach ($o as $a) { +echo $a,"\n"; +} +} ); + +echo "InfiniteIterator... "; +class InfiniteIteratorTest extends InfiniteIterator { + function __construct(){} +} +test ( function() { +$o = new InfiniteIteratorTest; +foreach ($o as $a) { +echo $a,"\n"; +} +} ); + +--EXPECT-- +IteratorIterator... exception (expected) +FilterIterator... exception (expected) +RecursiveFilterIterator... exception (expected) +ParentIterator... exception (expected) +LimitIterator... exception (expected) +CachingIterator... exception (expected) +RecursiveCachingIterator... exception (expected) +NoRewindIterator... exception (expected) +RegexIterator... exception (expected) +RecursiveRegexIterator... exception (expected) +GlobIterator... exception (expected) +SplFileObject... exception (expected) +SplTempFileObject... exception (expected) +AppendIterator... exception (expected) +InfiniteIterator... exception (expected) diff --git a/ext/spl/tests/bug54970.phpt b/ext/spl/tests/bug54970.phpt new file mode 100644 index 0000000..62b1eed --- /dev/null +++ b/ext/spl/tests/bug54970.phpt @@ -0,0 +1,33 @@ +--TEST-- +Bug #54970 (SplFixedArray::setSize() isn't resizing) +--FILE-- +<?php + +$fa = new SplFixedArray(2); +$fa[0] = 'Hello'; +$fa[1] = 'World'; +$fa->setSize(3); +$fa[2] = '!'; +var_dump($fa); +$fa->setSize(2); +var_dump($fa); +var_dump($fa->getSize()); + + +?> +--EXPECTF-- +object(SplFixedArray)#%d (3) { + [0]=> + string(5) "Hello" + [1]=> + string(5) "World" + [2]=> + string(1) "!" +} +object(SplFixedArray)#%d (2) { + [0]=> + string(5) "Hello" + [1]=> + string(5) "World" +} +int(2) diff --git a/ext/spl/tests/bug54971.phpt b/ext/spl/tests/bug54971.phpt new file mode 100644 index 0000000..22cdfba --- /dev/null +++ b/ext/spl/tests/bug54971.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bug #54971 (Wrong result when using iterator_to_array with use_keys on true) +--SKIPIF-- +<?php +if (!extension_loaded('dom')) die("skip this test needs --enable-dom"); +?> +--FILE-- +<?php + +$source = <<<XML +<root> +<node>val1</node> +<node>val2</node> +</root> +XML; + + +$doc = new DOMDocument(); +$doc->loadXML($source); + +$xpath = new DOMXPath($doc); +$items = $xpath->query('//node'); + +print_r(array_map('get_class', iterator_to_array($items, false))); +print_r(array_map('get_class', iterator_to_array($items, true))); +?> +--EXPECT-- +Array +( + [0] => DOMElement + [1] => DOMElement +) +Array +( + [0] => DOMElement + [1] => DOMElement +) diff --git a/ext/spl/tests/bug60201.phpt b/ext/spl/tests/bug60201.phpt new file mode 100644 index 0000000..68a5daa --- /dev/null +++ b/ext/spl/tests/bug60201.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #60201 (SplFileObject::setCsvControl does not expose third argument via Reflection) +--FILE-- +<?php + +$method = new ReflectionMethod('SplFileObject', 'setCsvControl'); +$params = $method->getParameters(); +var_dump($params); + +?> +===DONE=== +--EXPECTF-- +array(3) { + [0]=> + &object(ReflectionParameter)#%d (1) { + ["name"]=> + string(9) "delimiter" + } + [1]=> + &object(ReflectionParameter)#%d (1) { + ["name"]=> + string(9) "enclosure" + } + [2]=> + &object(ReflectionParameter)#%d (1) { + ["name"]=> + string(6) "escape" + } +} +===DONE=== diff --git a/ext/spl/tests/bug61326.phpt b/ext/spl/tests/bug61326.phpt new file mode 100644 index 0000000..85b5779 --- /dev/null +++ b/ext/spl/tests/bug61326.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #61326: ArrayObject comparison +--FILE-- +<?php +$aobj1 = new ArrayObject(array(0)); +$aobj2 = new ArrayObject(array(1)); +var_dump($aobj1 == $aobj2); + +$aobj3 = new ArrayObject(array(0)); +var_dump($aobj1 == $aobj3); + +$aobj3->foo = 'bar'; +var_dump($aobj1 == $aobj3); +--EXPECT-- +bool(false) +bool(true) +bool(false) diff --git a/ext/spl/tests/bug61347.phpt b/ext/spl/tests/bug61347.phpt new file mode 100644 index 0000000..cb09185 --- /dev/null +++ b/ext/spl/tests/bug61347.phpt @@ -0,0 +1,40 @@ +--TEST-- +Bug #61347 (inconsist isset behavior of Arrayobject) +--FILE-- +<?php +$a = array('b' => NULL, 37 => NULL); +var_dump(isset($a['b'])); //false + +$b = new ArrayObject($a); +var_dump(isset($b['b'])); //false +var_dump(isset($b[37])); //false +var_dump(isset($b['no_exists'])); //false +var_dump(empty($b['b'])); //true +var_dump(empty($b[37])); //true + +var_dump(array_key_exists('b', $b)); //true +var_dump($b['b']); + +$a = array('b' => '', 37 => false); +$b = new ArrayObject($a); +var_dump(isset($b['b'])); //true +var_dump(isset($b[37])); //true +var_dump(isset($b['no_exists'])); //false +var_dump(empty($b['b'])); //true +var_dump(empty($b[37])); //true + + +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +NULL +bool(true) +bool(true) +bool(false) +bool(true) +bool(true) diff --git a/ext/spl/tests/bug61418.phpt b/ext/spl/tests/bug61418.phpt new file mode 100644 index 0000000..c5d9db9 --- /dev/null +++ b/ext/spl/tests/bug61418.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #61418: Segmentation fault using FiltesystemIterator & RegexIterator +--FILE-- +<?php +$fileIterator = new FilesystemIterator(__DIR__, FilesystemIterator::KEY_AS_FILENAME); +$regexpIterator = new RegexIterator($fileIterator, '#.*#'); +foreach ($fileIterator as $key => $file) +{ +} +unset($regexpIterator); +unset($fileIterator); + +$dirIterator = new DirectoryIterator(__DIR__); +$regexpIterator2 = new RegexIterator($dirIterator, '#.*#'); +foreach ($dirIterator as $key => $file) +{ +} +unset($regexpIterator2); +unset($dirIterator); +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/ext/spl/tests/bug61453.phpt b/ext/spl/tests/bug61453.phpt new file mode 100644 index 0000000..e5b1387 --- /dev/null +++ b/ext/spl/tests/bug61453.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #61453: SplObjectStorage does not identify objects correctly +--FILE-- +<?php +$limit = 1000; +$objects = new SplObjectStorage; +for($i = 0; $i < $limit; $i++){ + $object = new StdClass; + + if(isset($objects[$object])){ + die("this should never happen, but did after $i iteration"); + } + + $objects[$object] = 1; +} +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/ext/spl/tests/bug61527.phpt b/ext/spl/tests/bug61527.phpt new file mode 100644 index 0000000..ab13c69 --- /dev/null +++ b/ext/spl/tests/bug61527.phpt @@ -0,0 +1,92 @@ +--TEST-- +Bug #61527 (Recursive/ArrayIterator gives misleading notice when array empty or moved to the end) +--FILE-- +<?php +$ao = new ArrayObject(array()); +$ai = $ao->getIterator(); + +/* testing empty array, should no notice at all */ +$ai->next(); +var_dump($ai->key()); +var_dump($ai->current()); + +/* testing array changing */ +$ao2 = new ArrayObject(array(1 => 1, 2, 3, 4, 5)); +$ai2 = $ao2->getIterator(); + +$ao2->offsetUnset($ai2->key()); +$ai2->next(); + +/* now point to 2 */ +$ao2->offsetUnset($ai2->key()); +var_dump($ai2->key()); + +/* now point to 3 */ +$ao2->offsetUnset($ai2->key()); +var_dump($ai2->current()); + +$ai2->next(); +var_dump($ai2->key()); +var_dump($ai2->current()); + +/* should be at the end and no notice */ +$ai2->next(); +var_dump($ai2->key()); +var_dump($ai2->current()); + +$ai2->rewind(); +$ai2->next(); +$ai2->next(); +/* should reached the end */ +var_dump($ai2->next()); +var_dump($ai2->key()); + +/* testing RecursiveArrayIterator */ +$ao3 = new ArrayObject(array(), NULL, 'RecursiveArrayIterator'); +$ai3 = $ao3->getIterator(); + +var_dump($ai3->getChildren()); + +$ao4 = new ArrayObject(array(1, 2), NULL, 'RecursiveArrayIterator'); +$ai4 = $ao4->getIterator(); + +$ai4->next(); +$ai4->next(); +$ai4->next(); +var_dump($ai4->hasChildren()); + +$ai4->rewind(); +$ao4->offsetUnset($ai4->key()); +var_dump($ai4->hasChildren()); + +$ao4->offsetUnset($ai4->key()); +var_dump($ai4->getChildren()); +?> +==DONE== +<?php exit(0); ?> +--EXPECTF-- +NULL +NULL + +Notice: ArrayIterator::next(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d + +Notice: ArrayIterator::key(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d +NULL + +Notice: ArrayIterator::current(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d +NULL +int(5) +int(5) +NULL +NULL +NULL +NULL +NULL +bool(false) + +Notice: RecursiveArrayIterator::hasChildren(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d +bool(false) + +Notice: RecursiveArrayIterator::getChildren(): Array was modified outside object and internal position is no longer valid in %sbug61527.php on line %d +NULL +==DONE== diff --git a/ext/spl/tests/bug62073.phpt b/ext/spl/tests/bug62073.phpt new file mode 100644 index 0000000..3bd3553 --- /dev/null +++ b/ext/spl/tests/bug62073.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #62073 (different ways of iterating over an SplMaxHeap result in different keys) +--FILE-- +<?php +$heap = new SplMaxHeap(); +$heap->insert(42); +foreach ($heap as $key => $value) { + var_dump($key); + var_dump($value); + break; +} + +$heap = new SplMaxHeap(); +$heap->insert(42); +var_dump($heap->key()); +var_dump($heap->current()); +?> +--EXPECT-- +int(0) +int(42) +int(0) +int(42) diff --git a/ext/spl/tests/bug62262.phpt b/ext/spl/tests/bug62262.phpt new file mode 100644 index 0000000..0e006ec --- /dev/null +++ b/ext/spl/tests/bug62262.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #62262: RecursiveArrayIterator does not implement Countable +--FILE-- +<?php + +var_dump(new RecursiveArrayIterator(array()) instanceof Countable); + +?> +--EXPECT-- +bool(true) diff --git a/ext/spl/tests/bug62328.phpt b/ext/spl/tests/bug62328.phpt new file mode 100644 index 0000000..33a8aee --- /dev/null +++ b/ext/spl/tests/bug62328.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #62328 (cast_object takes precedence over __toString) +--CREDITS-- +leight at gmail dot com +--FILE-- +<?php + +class SplFileInfo62328 extends SplFileInfo +{ + public function __toString() + { + return '__toString'; + } +} + +$fi = new SplFileInfo62328(__FILE__); + +echo (string)$fi . PHP_EOL; +echo (string)$fi->__toString() . PHP_EOL; + +?> +--EXPECT-- +__toString +__toString diff --git a/ext/spl/tests/bug62433.phpt b/ext/spl/tests/bug62433.phpt new file mode 100644 index 0000000..bfb3568 --- /dev/null +++ b/ext/spl/tests/bug62433.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #62433 Inconsistent behavior of RecursiveDirectoryIterator to dot files (. and ..) +--FILE-- +<?php +$dots = array_keys(iterator_to_array(new RecursiveDirectoryIterator(__DIR__))); +$ndots = array_keys(iterator_to_array(new RecursiveDirectoryIterator(__DIR__, FilesystemIterator::SKIP_DOTS))); + +var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '.', $dots)); +var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '..', $dots)); + +var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '.', $ndots)); +var_dump(in_array(__DIR__ . DIRECTORY_SEPARATOR . '..', $ndots)); +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +bool(false) diff --git a/ext/spl/tests/bug62616.phpt b/ext/spl/tests/bug62616.phpt new file mode 100644 index 0000000..4e4be94 --- /dev/null +++ b/ext/spl/tests/bug62616.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #62616 (ArrayIterator::count() from IteratorIterator instance gives Segmentation fault) +--FILE-- +<?php +$ai = new ArrayIterator(array(0,1)); + +var_dump($ai->count()); + +$ii = new IteratorIterator($ai); + +var_dump($ii->count()); +?> +--EXPECTF-- +int(2) +int(2) diff --git a/ext/spl/tests/bug62904.phpt b/ext/spl/tests/bug62904.phpt new file mode 100644 index 0000000..7e392da --- /dev/null +++ b/ext/spl/tests/bug62904.phpt @@ -0,0 +1,19 @@ +--TEST-- +Bug #62904 (Crash when cloning an object which inherits SplFixedArray) +--FILE-- +<?php + +class foo extends SplFixedArray { + public function __construct($size) { + } +} + +$x = new foo(2); + +try { + $z = clone $x; +} catch (Exception $e) { + var_dump($e->getMessage()); +} +--EXPECTF-- +string(40) "The instance wasn't initialized properly" diff --git a/ext/spl/tests/bug62978.phpt b/ext/spl/tests/bug62978.phpt new file mode 100644 index 0000000..0d91609 --- /dev/null +++ b/ext/spl/tests/bug62978.phpt @@ -0,0 +1,50 @@ +--TEST-- +Bug #62987 (Assigning to ArrayObject[null][something] overrides all undefined variables) +--FILE-- +<?php +$a = new ArrayObject(); + +$b = array(); + +$a[null]['hurr'] = 'durr'; + +var_dump($a['epic_magic']); +var_dump($b['epic_magic']); +var_dump($c['epic_magic']); // Undefined var!! + +$d = array(); +var_dump($a['epic_magic']); // more magic! +var_dump($d['epic_magic']); + +$e = 'srsly?'; +var_dump($a['epic_magic']); // srsly. +var_dump(isset($a['epic_magic'])); + +$fp = fopen(__FILE__, 'r'); +var_dump($a[$fp]); + +fclose($fp); +--EXPECTF-- +Notice: Undefined index: epic_magic in %sbug62978.php on line %d +NULL + +Notice: Undefined index: epic_magic in %sbug62978.php on line %d +NULL + +Notice: Undefined variable: c in %sbug62978.php on line %d +NULL + +Notice: Undefined index: epic_magic in %sbug62978.php on line %d +NULL + +Notice: Undefined index: epic_magic in %sbug62978.php on line %d +NULL + +Notice: Undefined index: epic_magic in %sbug62978.php on line %d +NULL +bool(false) + +Strict Standards: Resource ID#%d used as offset, casting to integer (%d) in %sbug62978.php on line %d + +Notice: Undefined offset: %d in %sbug62978.php on line %d +NULL diff --git a/ext/spl/tests/bug63680.phpt b/ext/spl/tests/bug63680.phpt new file mode 100644 index 0000000..3a20c4b --- /dev/null +++ b/ext/spl/tests/bug63680.phpt @@ -0,0 +1,16 @@ +--TEST-- +Bug #63680 (Memleak in splfixedarray with cycle reference) +--FILE-- +<?php +function dummy() { + $a = new SplFixedArray(1); + $b = new SplFixedArray(1); + $a[0] = $b; + $b[0] = $a; +} + +dummy(); +var_dump(gc_collect_cycles()); +?> +--EXPECT-- +int(2) diff --git a/ext/spl/tests/bug64023.phpt b/ext/spl/tests/bug64023.phpt new file mode 100644 index 0000000..2c177f9 --- /dev/null +++ b/ext/spl/tests/bug64023.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #64023: Overloading __toString() in SplFileInfo has no effect +--FILE-- +<?php +class A extends \SplFileInfo +{ + public function __toString() {return ' -expected- ';} +} + +$a = new A('/'); + +// Works +echo $a, $a->__toString(), $a->__toString() . '', "\n"; + +// Does not work - outputs parent::__toString() +echo $a . '', "\n"; + +--EXPECT-- + -expected- -expected- -expected- + -expected- diff --git a/ext/spl/tests/bug64106.phpt b/ext/spl/tests/bug64106.phpt new file mode 100644 index 0000000..855caef --- /dev/null +++ b/ext/spl/tests/bug64106.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #64106: Segfault on SplFixedArray[][x] = y when extended +--FILE-- +<?php + +class MyFixedArray extends SplFixedArray { + public function offsetGet($offset) {} +} + +$array = new MyFixedArray(10); +$array[][1] = 10; + +?> +--EXPECTF-- +Notice: Indirect modification of overloaded element of MyFixedArray has no effect in %s on line %d diff --git a/ext/spl/tests/bug64228.phpt b/ext/spl/tests/bug64228.phpt new file mode 100644 index 0000000..3f30dd2 --- /dev/null +++ b/ext/spl/tests/bug64228.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #64228 (RecursiveDirectoryIterator always assumes SKIP_DOTS) +--FILE-- +<?php +$dirs = array(); +$empty_dir = __DIR__ . "/empty"; +@mkdir($empty_dir); + +$i = new RecursiveDirectoryIterator($empty_dir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO); // Note the absence of FilesystemIterator::SKIP_DOTS +foreach ($i as $key => $value) { + $dirs[] = $value->getFileName(); +} + +@rmdir($empty_dir); + +sort($dirs); +print_r($dirs); +?> +--EXPECT-- +Array +( + [0] => . + [1] => .. +) + diff --git a/ext/spl/tests/bug64264.phpt b/ext/spl/tests/bug64264.phpt new file mode 100644 index 0000000..e7b695b --- /dev/null +++ b/ext/spl/tests/bug64264.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #64264 (SPLFixedArray toArray problem) +--FILE-- +<?php +class MyFixedArray extends \SplFixedArray { + protected $foo; + protected $bar; +} + +$myFixedArr = new MyFixedArray(1); +$myFixedArr[0] = 'foo'; +$myFixedArr->setSize(2); +$myFixedArr[1] = 'bar'; +$myFixedArr->setSize(5); +$array = $myFixedArr->toArray(); +$array[2] = "ERROR"; +$array[3] = "ERROR"; +$array[4] = "ERROR"; +unset($array[4]); +$myFixedArr->setSize(2); + +print_r($myFixedArr->toArray()); +?> +--EXPECTF-- +Array +( + [0] => foo + [1] => bar +) diff --git a/ext/spl/tests/class_implements_basic.phpt b/ext/spl/tests/class_implements_basic.phpt new file mode 100644 index 0000000..1170b21 --- /dev/null +++ b/ext/spl/tests/class_implements_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: Test class_implements() function : basic +--FILE-- +<?php +/* Prototype : array class_implements(mixed what [, bool autoload ]) + * Description: Return all classes and interfaces implemented by SPL + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_implements() : basic ***\n"; + + +interface foo { } +class bar implements foo {} + +var_dump(class_implements(new bar)); +var_dump(class_implements('bar')); + + +?> +===DONE=== +--EXPECT-- +*** Testing class_implements() : basic *** +array(1) { + ["foo"]=> + string(3) "foo" +} +array(1) { + ["foo"]=> + string(3) "foo" +} +===DONE=== diff --git a/ext/spl/tests/class_implements_basic2.phpt b/ext/spl/tests/class_implements_basic2.phpt new file mode 100644 index 0000000..ea25e5b --- /dev/null +++ b/ext/spl/tests/class_implements_basic2.phpt @@ -0,0 +1,74 @@ +--TEST-- +SPL: Test class_implements() function : basic +--FILE-- +<?php +/* Prototype : array class_implements(mixed what [, bool autoload ]) + * Description: Return all classes and interfaces implemented by SPL + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_implements() : basic ***\n"; + + +interface foo { } +class fooImpl implements foo {} + +interface bar { } +class barImpl implements bar {} + +class foobarImpl implements foo, bar {} + +class fooViaBarImpl extends barImpl implements foo {} + +class fooExtended extends fooImpl {} + +s_var_dump(class_implements(new foobarImpl)); +s_var_dump(class_implements('foobarImpl')); +s_var_dump(class_implements(new fooViaBarImpl)); +s_var_dump(class_implements('fooViaBarImpl')); +s_var_dump(class_implements(new fooExtended)); +s_var_dump(class_implements('fooExtended')); + + +function s_var_dump($arr) { + krsort($arr); + var_dump($arr); +} +?> +===DONE=== +--EXPECT-- +*** Testing class_implements() : basic *** +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(1) { + ["foo"]=> + string(3) "foo" +} +array(1) { + ["foo"]=> + string(3) "foo" +} +===DONE=== diff --git a/ext/spl/tests/class_implements_variation.phpt b/ext/spl/tests/class_implements_variation.phpt new file mode 100644 index 0000000..52fdbca --- /dev/null +++ b/ext/spl/tests/class_implements_variation.phpt @@ -0,0 +1,45 @@ +--TEST-- +SPL: Test class_implements() function : variation - no interfaces and autoload +--FILE-- +<?php +/* Prototype : array class_implements(mixed what [, bool autoload ]) + * Description: Return all classes and interfaces implemented by SPL + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_implements() : variation ***\n"; + +echo "--- testing no interfaces ---\n"; +class fs {} +var_dump(class_implements(new fs)); +var_dump(class_implements('fs')); + +echo "\n--- testing autoload ---\n"; +var_dump(class_implements('non-existent')); +var_dump(class_implements('non-existent2', false)); + + +function __autoload($classname) { + echo "attempting to autoload $classname\n"; +} + +?> +===DONE=== +--EXPECTF-- +*** Testing class_implements() : variation *** +--- testing no interfaces --- +array(0) { +} +array(0) { +} + +--- testing autoload --- +attempting to autoload non-existent + +Warning: class_implements(): Class non-existent does not exist and could not be loaded in %s on line %d +bool(false) + +Warning: class_implements(): Class non-existent2 does not exist in %s on line %d +bool(false) +===DONE=== diff --git a/ext/spl/tests/class_implements_variation1.phpt b/ext/spl/tests/class_implements_variation1.phpt new file mode 100644 index 0000000..d8a45ce --- /dev/null +++ b/ext/spl/tests/class_implements_variation1.phpt @@ -0,0 +1,221 @@ +--TEST-- +SPL: Test class_implements() function : variation +--FILE-- +<?php +/* Prototype : array class_implements(mixed what [, bool autoload ]) + * Description: Return all classes and interfaces implemented by SPL + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_implements() : variation ***\n"; + + +// Define error handler +function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) { + if (error_reporting() != 0) { + // report non-silenced errors + echo "Error: $err_no - $err_msg, $filename($linenum)\n"; + } +} +set_error_handler('test_error_handler'); + +// Initialise function arguments not being substituted (if any) +$autoload = true; + +//resource +$res = fopen(__FILE__,'r'); + +//get an unset variable +$unset_var = 10; +unset ($unset_var); + +// define some classes +class classWithToString +{ + public function __toString() { + return "Class A object"; + } +} + +class classWithoutToString +{ +} + +// heredoc string +$heredoc = <<<EOT +hello world +EOT; + +// add arrays +$index_array = array (1, 2, 3); +$assoc_array = array ('one' => 1, 'two' => 2); + +//array of values to iterate over +$inputs = array( + + // int data + 'int 0' => 0, + 'int 1' => 1, + 'int 12345' => 12345, + 'int -12345' => -2345, + + // float data + 'float 10.5' => 10.5, + 'float -10.5' => -10.5, + 'float 12.3456789000e10' => 12.3456789000e10, + 'float -12.3456789000e10' => -12.3456789000e10, + 'float .5' => .5, + + // array data + 'empty array' => array(), + 'int indexed array' => $index_array, + 'associative array' => $assoc_array, + 'nested arrays' => array('foo', $index_array, $assoc_array), + + // null data + 'uppercase NULL' => NULL, + 'lowercase null' => null, + + // boolean data + 'lowercase true' => true, + 'lowercase false' =>false, + 'uppercase TRUE' =>TRUE, + 'uppercase FALSE' =>FALSE, + + // empty data + 'empty string DQ' => "", + 'empty string SQ' => '', + + // object data + 'instance of classWithToString' => new classWithToString(), + 'instance of classWithoutToString' => new classWithoutToString(), + + // undefined data + 'undefined var' => @$undefined_var, + + // unset data + 'unset var' => @$unset_var, + + //resource + 'resource' => $res, +); + +// loop through each element of the array for pattern + +foreach($inputs as $key =>$value) { + echo "\n--$key--\n"; + var_dump( class_implements($value, $autoload) ); +}; + +fclose($res); + +?> +===DONE=== +--EXPECTF-- +*** Testing class_implements() : variation *** + +--int 0-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--int 1-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--int 12345-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--int -12345-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--float 10.5-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--float -10.5-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--float 12.3456789000e10-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--float -12.3456789000e10-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--float .5-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--empty array-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--int indexed array-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--associative array-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--nested arrays-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--uppercase NULL-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--lowercase null-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--lowercase true-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--lowercase false-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--uppercase TRUE-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--uppercase FALSE-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--empty string DQ-- +Error: 2 - class_implements(): Class does not exist and could not be loaded, %s(%d) +bool(false) + +--empty string SQ-- +Error: 2 - class_implements(): Class does not exist and could not be loaded, %s(%d) +bool(false) + +--instance of classWithToString-- +array(0) { +} + +--instance of classWithoutToString-- +array(0) { +} + +--undefined var-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--unset var-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) + +--resource-- +Error: 2 - class_implements(): object or string expected, %s(%d) +bool(false) +===DONE=== diff --git a/ext/spl/tests/class_implements_variation2.phpt b/ext/spl/tests/class_implements_variation2.phpt new file mode 100644 index 0000000..f695357 --- /dev/null +++ b/ext/spl/tests/class_implements_variation2.phpt @@ -0,0 +1,259 @@ +--TEST-- +SPL: Test class_implements() function : variation +--FILE-- +<?php +/* Prototype : array class_implements(mixed what [, bool autoload ]) + * Description: Return all classes and interfaces implemented by SPL + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_implements() : variation ***\n"; + + +// Define error handler +function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) { + if (error_reporting() != 0) { + // report non-silenced errors + echo "Error: $err_no - $err_msg, $filename($linenum)\n"; + } +} +set_error_handler('test_error_handler'); + +// Initialise function arguments not being substituted (if any) +$class = 'Iterator'; + +//resource +$res = fopen(__FILE__,'r'); + +//get an unset variable +$unset_var = 10; +unset ($unset_var); + +// define some classes +class classWithToString +{ + public function __toString() { + return "Class A object"; + } +} + +class classWithoutToString +{ +} + +// heredoc string +$heredoc = <<<EOT +hello world +EOT; + +// add arrays +$index_array = array (1, 2, 3); +$assoc_array = array ('one' => 1, 'two' => 2); + +//array of values to iterate over +$inputs = array( + + // int data + 'int 0' => 0, + 'int 1' => 1, + 'int 12345' => 12345, + 'int -12345' => -2345, + + // float data + 'float 10.5' => 10.5, + 'float -10.5' => -10.5, + 'float 12.3456789000e10' => 12.3456789000e10, + 'float -12.3456789000e10' => -12.3456789000e10, + 'float .5' => .5, + + // array data + 'empty array' => array(), + 'int indexed array' => $index_array, + 'associative array' => $assoc_array, + 'nested arrays' => array('foo', $index_array, $assoc_array), + + // null data + 'uppercase NULL' => NULL, + 'lowercase null' => null, + + // boolean data + 'lowercase true' => true, + 'lowercase false' =>false, + 'uppercase TRUE' =>TRUE, + 'uppercase FALSE' =>FALSE, + + // empty data + 'empty string DQ' => "", + 'empty string SQ' => '', + + // object data + 'instance of classWithToString' => new classWithToString(), + 'instance of classWithoutToString' => new classWithoutToString(), + + // undefined data + 'undefined var' => @$undefined_var, + + // unset data + 'unset var' => @$unset_var, + + //resource + 'resource' => $res, +); + +// loop through each element of the array for pattern + +foreach($inputs as $key =>$value) { + echo "\n--$key--\n"; + var_dump( class_implements($class, $value) ); +}; + +fclose($res); + +?> +===DONE=== +--EXPECTF-- +*** Testing class_implements() : variation *** + +--int 0-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--int 1-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--int 12345-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--int -12345-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--float 10.5-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--float -10.5-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--float 12.3456789000e10-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--float -12.3456789000e10-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--float .5-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--empty array-- +Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--int indexed array-- +Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--associative array-- +Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--nested arrays-- +Error: 2 - class_implements() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--uppercase NULL-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--lowercase null-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--lowercase true-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--lowercase false-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--uppercase TRUE-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--uppercase FALSE-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--empty string DQ-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--empty string SQ-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--instance of classWithToString-- +Error: 2 - class_implements() expects parameter 2 to be boolean, object given, %s(%d) +bool(false) + +--instance of classWithoutToString-- +Error: 2 - class_implements() expects parameter 2 to be boolean, object given, %s(%d) +bool(false) + +--undefined var-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--unset var-- +array(1) { + ["Traversable"]=> + string(11) "Traversable" +} + +--resource-- +Error: 2 - class_implements() expects parameter 2 to be boolean, resource given, %s(%d) +bool(false) +===DONE=== diff --git a/ext/spl/tests/class_uses_basic.phpt b/ext/spl/tests/class_uses_basic.phpt new file mode 100644 index 0000000..8aeb7b5 --- /dev/null +++ b/ext/spl/tests/class_uses_basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: Test class_implements() function : basic +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ]) + * Description: Return all traits used by a class + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : basic ***\n"; + + +trait foo { } +class bar { use foo; } + +var_dump(class_uses(new bar)); +var_dump(class_uses('bar')); + + +?> +===DONE=== +--EXPECT-- +*** Testing class_uses() : basic *** +array(1) { + ["foo"]=> + string(3) "foo" +} +array(1) { + ["foo"]=> + string(3) "foo" +} +===DONE=== diff --git a/ext/spl/tests/class_uses_basic2.phpt b/ext/spl/tests/class_uses_basic2.phpt new file mode 100644 index 0000000..a0ffe8b --- /dev/null +++ b/ext/spl/tests/class_uses_basic2.phpt @@ -0,0 +1,69 @@ +--TEST-- +SPL: Test class_uses() function : basic +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ]) + * Description: Return all traits used by a class + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : basic ***\n"; + + +trait foo { } +class fooUser { use foo; } + +trait bar { } +class barUser { use bar; } + +class foobarUser { use foo, bar; } + +/** There is no semantics for traits in the inheritance chain. + Traits are flattend into a class, and that semantics is nothing + like a type, or interface, and thus, not propergated. */ +class fooViaBarUser extends barUser { use foo; } + +class fooExtended extends fooUser {} + +s_var_dump(class_uses(new foobarUser)); +s_var_dump(class_uses('foobarUser')); +s_var_dump(class_uses(new fooViaBarUser)); +s_var_dump(class_uses('fooViaBarUser')); +s_var_dump(class_uses(new fooExtended)); +s_var_dump(class_uses('fooExtended')); + + +function s_var_dump($arr) { + krsort($arr); + var_dump($arr); +} +?> +===DONE=== +--EXPECT-- +*** Testing class_uses() : basic *** +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(2) { + ["foo"]=> + string(3) "foo" + ["bar"]=> + string(3) "bar" +} +array(1) { + ["foo"]=> + string(3) "foo" +} +array(1) { + ["foo"]=> + string(3) "foo" +} +array(0) { +} +array(0) { +} +===DONE=== diff --git a/ext/spl/tests/class_uses_variation.phpt b/ext/spl/tests/class_uses_variation.phpt new file mode 100644 index 0000000..9c21521 --- /dev/null +++ b/ext/spl/tests/class_uses_variation.phpt @@ -0,0 +1,45 @@ +--TEST-- +SPL: Test class_uses() function : variation - no interfaces and autoload +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ]) + * Description: Return all traits used by a class + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : variation ***\n"; + +echo "--- testing no traits ---\n"; +class fs {} +var_dump(class_uses(new fs)); +var_dump(class_uses('fs')); + +echo "\n--- testing autoload ---\n"; +var_dump(class_uses('non-existent')); +var_dump(class_uses('non-existent2', false)); + + +function __autoload($classname) { + echo "attempting to autoload $classname\n"; +} + +?> +===DONE=== +--EXPECTF-- +*** Testing class_uses() : variation *** +--- testing no traits --- +array(0) { +} +array(0) { +} + +--- testing autoload --- +attempting to autoload non-existent + +Warning: class_uses(): Class non-existent does not exist and could not be loaded in %s on line %d +bool(false) + +Warning: class_uses(): Class non-existent2 does not exist in %s on line %d +bool(false) +===DONE=== diff --git a/ext/spl/tests/class_uses_variation1.phpt b/ext/spl/tests/class_uses_variation1.phpt new file mode 100644 index 0000000..aa0ba35 --- /dev/null +++ b/ext/spl/tests/class_uses_variation1.phpt @@ -0,0 +1,221 @@ +--TEST-- +SPL: Test class_uses() function : variation +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ]) + * Description: Return all traits used by a class + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : variation ***\n"; + + +// Define error handler +function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) { + if (error_reporting() != 0) { + // report non-silenced errors + echo "Error: $err_no - $err_msg, $filename($linenum)\n"; + } +} +set_error_handler('test_error_handler'); + +// Initialise function arguments not being substituted (if any) +$autoload = true; + +//resource +$res = fopen(__FILE__,'r'); + +//get an unset variable +$unset_var = 10; +unset ($unset_var); + +// define some classes +class classWithToString +{ + public function __toString() { + return "Class A object"; + } +} + +class classWithoutToString +{ +} + +// heredoc string +$heredoc = <<<EOT +hello world +EOT; + +// add arrays +$index_array = array (1, 2, 3); +$assoc_array = array ('one' => 1, 'two' => 2); + +//array of values to iterate over +$inputs = array( + + // int data + 'int 0' => 0, + 'int 1' => 1, + 'int 12345' => 12345, + 'int -12345' => -2345, + + // float data + 'float 10.5' => 10.5, + 'float -10.5' => -10.5, + 'float 12.3456789000e10' => 12.3456789000e10, + 'float -12.3456789000e10' => -12.3456789000e10, + 'float .5' => .5, + + // array data + 'empty array' => array(), + 'int indexed array' => $index_array, + 'associative array' => $assoc_array, + 'nested arrays' => array('foo', $index_array, $assoc_array), + + // null data + 'uppercase NULL' => NULL, + 'lowercase null' => null, + + // boolean data + 'lowercase true' => true, + 'lowercase false' =>false, + 'uppercase TRUE' =>TRUE, + 'uppercase FALSE' =>FALSE, + + // empty data + 'empty string DQ' => "", + 'empty string SQ' => '', + + // object data + 'instance of classWithToString' => new classWithToString(), + 'instance of classWithoutToString' => new classWithoutToString(), + + // undefined data + 'undefined var' => @$undefined_var, + + // unset data + 'unset var' => @$unset_var, + + //resource + 'resource' => $res, +); + +// loop through each element of the array for pattern + +foreach($inputs as $key =>$value) { + echo "\n--$key--\n"; + var_dump( class_uses($value, $autoload) ); +}; + +fclose($res); + +?> +===DONE=== +--EXPECTF-- +*** Testing class_uses() : variation *** + +--int 0-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--int 1-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--int 12345-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--int -12345-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--float 10.5-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--float -10.5-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--float 12.3456789000e10-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--float -12.3456789000e10-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--float .5-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--empty array-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--int indexed array-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--associative array-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--nested arrays-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--uppercase NULL-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--lowercase null-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--lowercase true-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--lowercase false-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--uppercase TRUE-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--uppercase FALSE-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--empty string DQ-- +Error: 2 - class_uses(): Class does not exist and could not be loaded, %s(%d) +bool(false) + +--empty string SQ-- +Error: 2 - class_uses(): Class does not exist and could not be loaded, %s(%d) +bool(false) + +--instance of classWithToString-- +array(0) { +} + +--instance of classWithoutToString-- +array(0) { +} + +--undefined var-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--unset var-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) + +--resource-- +Error: 2 - class_uses(): object or string expected, %s(%d) +bool(false) +===DONE=== diff --git a/ext/spl/tests/class_uses_variation2.phpt b/ext/spl/tests/class_uses_variation2.phpt new file mode 100644 index 0000000..36c9623 --- /dev/null +++ b/ext/spl/tests/class_uses_variation2.phpt @@ -0,0 +1,261 @@ +--TEST-- +SPL: Test class_uses() function : variation +--FILE-- +<?php +/* Prototype : array class_uses(mixed what [, bool autoload ]) + * Description: Return all traits used by a class + * Source code: ext/spl/php_spl.c + * Alias to functions: + */ + +echo "*** Testing class_uses() : variation ***\n"; + +trait foo {} +class fooUser { use foo; } + +// Define error handler +function test_error_handler($err_no, $err_msg, $filename, $linenum, $vars) { + if (error_reporting() != 0) { + // report non-silenced errors + echo "Error: $err_no - $err_msg, $filename($linenum)\n"; + } +} +set_error_handler('test_error_handler'); + +// Initialise function arguments not being substituted (if any) +$class = 'fooUser'; + +//resource +$res = fopen(__FILE__,'r'); + +//get an unset variable +$unset_var = 10; +unset ($unset_var); + +// define some classes +class classWithToString +{ + public function __toString() { + return "Class A object"; + } +} + +class classWithoutToString +{ +} + +// heredoc string +$heredoc = <<<EOT +hello world +EOT; + +// add arrays +$index_array = array (1, 2, 3); +$assoc_array = array ('one' => 1, 'two' => 2); + +//array of values to iterate over +$inputs = array( + + // int data + 'int 0' => 0, + 'int 1' => 1, + 'int 12345' => 12345, + 'int -12345' => -2345, + + // float data + 'float 10.5' => 10.5, + 'float -10.5' => -10.5, + 'float 12.3456789000e10' => 12.3456789000e10, + 'float -12.3456789000e10' => -12.3456789000e10, + 'float .5' => .5, + + // array data + 'empty array' => array(), + 'int indexed array' => $index_array, + 'associative array' => $assoc_array, + 'nested arrays' => array('foo', $index_array, $assoc_array), + + // null data + 'uppercase NULL' => NULL, + 'lowercase null' => null, + + // boolean data + 'lowercase true' => true, + 'lowercase false' =>false, + 'uppercase TRUE' =>TRUE, + 'uppercase FALSE' =>FALSE, + + // empty data + 'empty string DQ' => "", + 'empty string SQ' => '', + + // object data + 'instance of classWithToString' => new classWithToString(), + 'instance of classWithoutToString' => new classWithoutToString(), + + // undefined data + 'undefined var' => @$undefined_var, + + // unset data + 'unset var' => @$unset_var, + + //resource + 'resource' => $res, +); + +// loop through each element of the array for pattern + +foreach($inputs as $key =>$value) { + echo "\n--$key--\n"; + var_dump( class_uses($class, $value) ); +}; + +fclose($res); + +?> +===DONE=== +--EXPECTF-- +*** Testing class_uses() : variation *** + +--int 0-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--int 1-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--int 12345-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--int -12345-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--float 10.5-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--float -10.5-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--float 12.3456789000e10-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--float -12.3456789000e10-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--float .5-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--empty array-- +Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--int indexed array-- +Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--associative array-- +Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--nested arrays-- +Error: 2 - class_uses() expects parameter 2 to be boolean, array given, %s(%d) +bool(false) + +--uppercase NULL-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--lowercase null-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--lowercase true-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--lowercase false-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--uppercase TRUE-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--uppercase FALSE-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--empty string DQ-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--empty string SQ-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--instance of classWithToString-- +Error: 2 - class_uses() expects parameter 2 to be boolean, object given, %s(%d) +bool(false) + +--instance of classWithoutToString-- +Error: 2 - class_uses() expects parameter 2 to be boolean, object given, %s(%d) +bool(false) + +--undefined var-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--unset var-- +array(1) { + ["foo"]=> + string(3) "foo" +} + +--resource-- +Error: 2 - class_uses() expects parameter 2 to be boolean, resource given, %s(%d) +bool(false) +===DONE=== diff --git a/ext/spl/tests/countable_class_basic1.phpt b/ext/spl/tests/countable_class_basic1.phpt new file mode 100644 index 0000000..c64aad6 --- /dev/null +++ b/ext/spl/tests/countable_class_basic1.phpt @@ -0,0 +1,37 @@ +--TEST-- +SPL: Test shape of interface Countable. +--SKIPIF-- +<?php +// Skip the test case if Standard PHP Library(spl) is not installed + if( !extension_loaded('spl')) + { + die('skip spl is not installed'); + } +?> +--FILE-- +<?php +ReflectionClass::export('Countable'); +?> +--EXPECTF-- +Interface [ <internal%s> interface Countable ] { + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [1] { + Method [ <internal%s> abstract public method count ] { + + - Parameters [0] { + } + } + } +} diff --git a/ext/spl/tests/countable_count_variation1.phpt b/ext/spl/tests/countable_count_variation1.phpt new file mode 100644 index 0000000..642887d --- /dev/null +++ b/ext/spl/tests/countable_count_variation1.phpt @@ -0,0 +1,68 @@ +--TEST-- +SPL: Countable::count() with wrong return types and exception. +--FILE-- +<?php + +Class returnNull implements Countable { + function count() { + } +} + +Class returnString implements Countable { + function count() { + return "hello"; + } +} + +Class returnObject implements Countable { + function count() { + return new returnObject; + } +} + +Class returnArray implements Countable { + function count() { + return array(1,2,3); + } +} + +Class throwException implements Countable { + function count() { + throw new Exception('Thrown from count'); + } +} + + +echo "Count returns null:\n"; +var_dump(count(new returnNull)); + +echo "Count returns a string:\n"; +var_dump(count(new returnString)); + +echo "Count returns an object:\n"; +var_dump(count(new returnObject)); + +echo "Count returns an array:\n"; +var_dump(count(new returnArray)); + +echo "Count throws an exception:\n"; +try { + echo count(new throwException); +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECTF-- +Count returns null: +int(0) +Count returns a string: +int(0) +Count returns an object: + +Notice: Object of class returnObject could not be converted to int in %s on line 40 +int(1) +Count returns an array: +int(1) +Count throws an exception: +Thrown from count
\ No newline at end of file diff --git a/ext/spl/tests/dit_001.phpt b/ext/spl/tests/dit_001.phpt new file mode 100644 index 0000000..a56166d --- /dev/null +++ b/ext/spl/tests/dit_001.phpt @@ -0,0 +1,28 @@ +--TEST-- +SPL: Problem with casting to string +--SKIPIF-- +<?php +if (!defined('GLOB_ERR')) print "skip"; +--FILE-- +<?php +$d = new DirectoryIterator('.'); +var_dump($d); +var_dump(is_string($d)); +preg_match('/x/', $d); +var_dump(is_string($d)); +?> +===DONE=== +--EXPECTF-- +object(DirectoryIterator)#%d (4) { + %s"pathName"%s"SplFileInfo":private]=> + %s(%d) ".%c%s" + %s"fileName"%s"SplFileInfo":private]=> + %s(%d) "%s" + %s"glob"%s"DirectoryIterator":private]=> + bool(false) + %s"subPathName"%s"RecursiveDirectoryIterator":private]=> + %s(0) "" +} +bool(false) +bool(false) +===DONE=== diff --git a/ext/spl/tests/dit_001_noglob.phpt b/ext/spl/tests/dit_001_noglob.phpt new file mode 100644 index 0000000..acb2092 --- /dev/null +++ b/ext/spl/tests/dit_001_noglob.phpt @@ -0,0 +1,27 @@ +--TEST-- +SPL: Problem with casting to string (no glob version) +--SKIPIF-- +<?php +if (defined('GLOB_ERR')) print "skip"; +--FILE-- +<?php +$d = new DirectoryIterator('.'); +var_dump($d); +var_dump(is_string($d)); +preg_match('/x/', $d); +var_dump(is_string($d)); +?> +===DONE=== +--EXPECTF-- +object(DirectoryIterator)#%d (3) { + %s"pathName"%s"SplFileInfo":private]=> + %s(%d) ".%c%s" + %s"fileName"%s"SplFileInfo":private]=> + %s(%d) "%s" + %s"subPathName"%s"RecursiveDirectoryIterator":private]=> + %s(0) "" +} +bool(false) +bool(false) +===DONE=== + diff --git a/ext/spl/tests/dit_002.phpt b/ext/spl/tests/dit_002.phpt new file mode 100644 index 0000000..a266542 --- /dev/null +++ b/ext/spl/tests/dit_002.phpt @@ -0,0 +1,77 @@ +--TEST-- +SPL: DirectoryIterator defaults +--SKIPIF-- +<?php if (!extension_loaded("spl") || !extension_loaded('reflection') || !defined('GLOB_ERR')) print "skip"; ?> +--FILE-- +<?php + +$classes = array( + 'DirectoryIterator' => 0, + 'FilesystemIterator' => 1, + 'RecursiveDirectoryIterator' => 1, + 'GlobIterator' => 1, +); + +foreach ($classes as $class => $flags) { + echo "===$class===\n"; + $ref = new ReflectionClass($class); + $obj = $ref->newInstance('glob://*'); + echo get_class($obj->current()) . "\n"; + if ($flags) + { + var_dump($obj->getFlags()); + $flags = array( + FilesystemIterator::CURRENT_AS_FILEINFO => 0, + FilesystemIterator::CURRENT_AS_SELF => 0, + FilesystemIterator::CURRENT_AS_PATHNAME => 1, + ); + foreach($flags as $flag => $isstring) { + $obj->setFlags($flag); + $obj->rewind(); + var_dump($obj->getFlags()); + if ($isstring) { + $val = $obj->current(); + if (is_string($val)) { + var_dump(true); + } else { + var_dump($val); + } + } else { + echo get_class($obj->current()) . "\n"; + } + } + } +} +?> +===DONE=== +--EXPECTF-- +===DirectoryIterator=== +DirectoryIterator +===FilesystemIterator=== +SplFileInfo +int(%d) +int(0) +SplFileInfo +int(16) +FilesystemIterator +int(32) +bool(true) +===RecursiveDirectoryIterator=== +SplFileInfo +int(0) +int(0) +SplFileInfo +int(16) +RecursiveDirectoryIterator +int(32) +bool(true) +===GlobIterator=== +SplFileInfo +int(0) +int(0) +SplFileInfo +int(16) +GlobIterator +int(32) +bool(true) +===DONE=== diff --git a/ext/spl/tests/dit_003.phpt b/ext/spl/tests/dit_003.phpt new file mode 100644 index 0000000..4ffc292 --- /dev/null +++ b/ext/spl/tests/dit_003.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: FilesystemIterator and foreach +--FILE-- +<?php +$count = 0; +foreach(new FilesystemIterator(__DIR__) as $ent) +{ + ++$count; +} +var_dump($count > 0); +?> +===DONE=== +--EXPECTF-- +bool(true) +===DONE=== diff --git a/ext/spl/tests/dit_004.phpt b/ext/spl/tests/dit_004.phpt new file mode 100644 index 0000000..4ad0e4b --- /dev/null +++ b/ext/spl/tests/dit_004.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: DirectoryIterator and clone +--FILE-- +<?php +$a = new DirectoryIterator(__DIR__); +$b = clone $a; +var_dump((string)$b == (string)$a); +var_dump($a->key(), $b->key()); +$a->next(); +$a->next(); +$a->next(); +$c = clone $a; +var_dump((string)$c == (string)$a); +var_dump($a->key(), $c->key()); +?> +===DONE=== +--EXPECTF-- +bool(true) +int(0) +int(0) +bool(true) +int(3) +int(3) +===DONE=== diff --git a/ext/spl/tests/dit_005.phpt b/ext/spl/tests/dit_005.phpt new file mode 100644 index 0000000..52a3351 --- /dev/null +++ b/ext/spl/tests/dit_005.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: FilesystemIterator and clone +--FILE-- +<?php +$a = new FileSystemIterator(__DIR__); +$b = clone $a; +var_dump((string)$b == (string)$a); +var_dump($a->key() == $b->key()); +$a->next(); +$a->next(); +$a->next(); +$c = clone $a; +var_dump((string)$c == (string)$a); +var_dump($a->key() == $c->key()); +?> +===DONE=== +--EXPECTF-- +bool(true) +bool(true) +bool(true) +bool(true) +===DONE=== diff --git a/ext/spl/tests/dit_006.phpt b/ext/spl/tests/dit_006.phpt new file mode 100644 index 0000000..1e627a2 --- /dev/null +++ b/ext/spl/tests/dit_006.phpt @@ -0,0 +1,50 @@ +--TEST-- +SPL: DirectoryIterator and seek +--FILE-- +<?php +$di = new DirectoryIterator(__DIR__); +$di->seek(2); + +$n = 0; +while ($di->valid()) { + $n++; + $di->next(); +} + +echo "With seek(2) we get $n\n"; +$di->seek(0); + +$m = 0; +while ($di->valid()) { + $m++; + $di->next(); +} +echo "With seek(0) we get $m\n"; + +$o = 0; +$di->rewind(); +while ($di->valid()) { + $o++; + $di->next(); +} + +echo "Without seek we get $o\n"; + +$p = 0; +$di->seek($o+1); +while ($di->valid()) { + $p++; + $di->next(); +} + +var_dump($n !== $m, $m === $o, $p === 0); +?> +===DONE=== +--EXPECTF-- +With seek(2) we get %d +With seek(0) we get %d +Without seek we get %d +bool(true) +bool(true) +bool(true) +===DONE=== diff --git a/ext/spl/tests/dllist_001.phpt b/ext/spl/tests/dllist_001.phpt new file mode 100644 index 0000000..e27f23c --- /dev/null +++ b/ext/spl/tests/dllist_001.phpt @@ -0,0 +1,63 @@ +--TEST-- +SPL: DoublyLinkedList: std operations +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +// errors +try { + $dll->pop(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + $dll->shift(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +// data consistency +$a = 2; +$dll->push($a); +echo $dll->pop()."\n"; + +$a = 2; +$dll->unshift($a); +echo $dll->shift()."\n"; + +// peakable +$dll->push(1); +$dll->push(2); +echo $dll->top()."\n"; +echo $dll->bottom()."\n"; +$dll->pop(); +$dll->pop(); + +// countable +$dll->push(NULL); +$dll->push(NULL); +echo count($dll)."\n"; +echo $dll->count()."\n"; +var_dump($dll->pop()); +var_dump($dll->pop()); + +// clonable +$dll->push(2); +$dll_clone = clone $dll; +$dll_clone->pop(); +echo count($dll)."\n"; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Can't pop from an empty datastructure +Exception: Can't shift from an empty datastructure +2 +2 +2 +1 +2 +2 +NULL +NULL +1 +===DONE=== diff --git a/ext/spl/tests/dllist_002.phpt b/ext/spl/tests/dllist_002.phpt new file mode 100644 index 0000000..e956de6 --- /dev/null +++ b/ext/spl/tests/dllist_002.phpt @@ -0,0 +1,60 @@ +--TEST-- +SPL: DoublyLinkedList: iterators +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +$dll->push(2); +$dll->push(3); +$dll->push(4); + +$dll2 = clone $dll; + +// std iterator +foreach($dll as $k=>$v) { + echo "$k=>$v\n"; + // inner iterator + foreach($dll as $k2=>$v2) { + echo "->$k2=>$v2\n"; + } +} + +echo "# deleted\n"; + +foreach($dll as $k=>$v) { + echo "$k=>$v\n"; + unset($dll); +} + +echo "# while popping\n"; + +foreach($dll2 as $k=>$v) { + echo "$k=>$v\n"; + echo "popped ".$dll2->pop()."\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +0=>2 +->0=>2 +->1=>3 +->2=>4 +1=>3 +->0=>2 +->1=>3 +->2=>4 +2=>4 +->0=>2 +->1=>3 +->2=>4 +# deleted +0=>2 +1=>3 +2=>4 +# while popping +0=>2 +popped 4 +1=>3 +popped 3 +===DONE=== diff --git a/ext/spl/tests/dllist_003.phpt b/ext/spl/tests/dllist_003.phpt new file mode 100644 index 0000000..9a95568 --- /dev/null +++ b/ext/spl/tests/dllist_003.phpt @@ -0,0 +1,43 @@ +--TEST-- +SPL: DoublyLinkedList: iterator modes +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +$dll->push(2); +$dll->push(3); +$dll->push(4); + +$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO); + +foreach ($dll as $k => $v) { + echo "$k=>$v\n"; +} + +$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO); +foreach ($dll as $k => $v) { + echo "$k=>$v\n"; +} + +$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO | SplDoublyLinkedList::IT_MODE_DELETE); +var_dump($dll->count()); +foreach ($dll as $k => $v) { + echo "$k=>$v\n"; +} +var_dump($dll->count()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +2=>4 +1=>3 +0=>2 +0=>2 +1=>3 +2=>4 +int(3) +0=>2 +0=>3 +0=>4 +int(0) +===DONE=== diff --git a/ext/spl/tests/dllist_004.phpt b/ext/spl/tests/dllist_004.phpt new file mode 100644 index 0000000..44d9611 --- /dev/null +++ b/ext/spl/tests/dllist_004.phpt @@ -0,0 +1,61 @@ +--TEST-- +SPL: DoublyLinkedList: Stacks +--FILE-- +<?php +$stack = new SplStack(); +// errors +try { + $stack->pop(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + $stack->shift(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +// data consistency +$a = 2; +$stack->push($a); +echo $stack->pop()."\n"; + +// peakable +$stack->push(1); +$stack->push(2); +echo $stack->top()."\n"; + +// iterable +foreach ($stack as $elem) { + echo "[$elem]\n"; +} + +// countable +$stack->push(NULL); +$stack->push(NULL); +echo count($stack)."\n"; +echo $stack->count()."\n"; +var_dump($stack->pop()); +var_dump($stack->pop()); + +// clonable +$stack->push(2); +$stack_clone = clone $stack; +$stack_clone->pop(); +echo count($stack)."\n"; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Can't pop from an empty datastructure +Exception: Can't shift from an empty datastructure +2 +2 +[2] +[1] +4 +4 +NULL +NULL +3 +===DONE=== diff --git a/ext/spl/tests/dllist_005.phpt b/ext/spl/tests/dllist_005.phpt new file mode 100644 index 0000000..33161ba --- /dev/null +++ b/ext/spl/tests/dllist_005.phpt @@ -0,0 +1,61 @@ +--TEST-- +SPL: DoublyLinkedList: Queues +--FILE-- +<?php +$queue = new SplQueue(); +// errors +try { + $queue->dequeue(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + $queue->shift(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +// data consistency +$a = 2; +$queue->enqueue($a); +echo $queue->dequeue()."\n"; + +// peakable +$queue->enqueue(1); +$queue->enqueue(2); +echo $queue->top()."\n"; + +// iterable +foreach ($queue as $elem) { + echo "[$elem]\n"; +} + +// countable +$queue->enqueue(NULL); +$queue->enqueue(NULL); +echo count($queue)."\n"; +echo $queue->count()."\n"; +var_dump($queue->dequeue()); +var_dump($queue->dequeue()); + +// clonable +$queue->enqueue(2); +$queue_clone = clone $queue; +$queue_clone->dequeue(); +echo count($queue)."\n"; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Can't shift from an empty datastructure +Exception: Can't shift from an empty datastructure +2 +2 +[1] +[2] +4 +4 +int(1) +int(2) +3 +===DONE=== diff --git a/ext/spl/tests/dllist_006.phpt b/ext/spl/tests/dllist_006.phpt new file mode 100644 index 0000000..b4055dc --- /dev/null +++ b/ext/spl/tests/dllist_006.phpt @@ -0,0 +1,62 @@ +--TEST-- +SPL: DoublyLinkedList: ArrayAccess +--FILE-- +<?php +$a = new SplDoublyLinkedList(); +$a->push(1); +$a->push(2); +$a->push(3); + +$a[] = "foo"; +$a[3] = 4; + +var_dump($a[0]); +var_dump($a[1]); +var_dump($a[2]); +var_dump($a[3]); + +echo "Unsetting..\n"; +var_dump($a[2]); +unset($a[2]); +var_dump($a[2]); + + +try { + var_dump($a["1"]); +} catch (OutOfRangeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + var_dump($a["a"]); +} catch (OutOfRangeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + var_dump($a["0"]); +} catch (OutOfRangeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + var_dump($a["9"]); +} catch (OutOfRangeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) +Unsetting.. +int(3) +int(4) +int(2) +Exception: Offset invalid or out of range +int(1) +Exception: Offset invalid or out of range +===DONE=== diff --git a/ext/spl/tests/dllist_007.phpt b/ext/spl/tests/dllist_007.phpt new file mode 100644 index 0000000..38f801f --- /dev/null +++ b/ext/spl/tests/dllist_007.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: DoublyLinkedList: Iterator +--FILE-- +<?php +$a = new SplDoublyLinkedList(); +$a->push(1); +$a->push(2); +$a->push(3); + +$a->rewind(); +while ($a->valid()) { + var_dump($a->current(), $a->next()); +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(1) +NULL +int(2) +NULL +int(3) +NULL +===DONE=== diff --git a/ext/spl/tests/dllist_008.phpt b/ext/spl/tests/dllist_008.phpt new file mode 100644 index 0000000..ab37d83 --- /dev/null +++ b/ext/spl/tests/dllist_008.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: SplDoublyLinkedList with overriden count() +--FILE-- +<?php +$obj = new SplDoublyLinkedList(); +$obj[] = 1; +$obj[] = 2; +var_dump(count($obj)); +class SplDoublyLinkedList2 extends SplDoublyLinkedList{ + public function count() { + return -parent::count(); + } +} +$obj = new SplDoublyLinkedList2(); +$obj[] = 1; +$obj[] = 2; +var_dump(count($obj)); +?> +--EXPECT-- +int(2) +int(-2) diff --git a/ext/spl/tests/dllist_010.phpt b/ext/spl/tests/dllist_010.phpt new file mode 100644 index 0000000..7e38955 --- /dev/null +++ b/ext/spl/tests/dllist_010.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: DoublyLinkedList: prev +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +$dll->push(1); +$dll->push(2); +$dll->push(3); +$dll->push(4); + + +$dll->rewind(); +$dll->prev(); +var_dump($dll->current()); +$dll->rewind(); +var_dump($dll->current()); +$dll->next(); +var_dump($dll->current()); +$dll->next(); +$dll->next(); +var_dump($dll->current()); +$dll->prev(); +var_dump($dll->current()); + +?> +===DONE=== +--EXPECT-- +NULL +int(1) +int(2) +int(4) +int(3) +===DONE=== diff --git a/ext/spl/tests/dllist_011.phpt b/ext/spl/tests/dllist_011.phpt new file mode 100644 index 0000000..b9be872 --- /dev/null +++ b/ext/spl/tests/dllist_011.phpt @@ -0,0 +1,13 @@ +--TEST-- +SPL: DoublyLinkedList: prev +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +$dll->rewind(); +$dll->prev(); +var_dump($dll->current()); +?> +===DONE=== +--EXPECT-- +NULL +===DONE=== diff --git a/ext/spl/tests/dllist_012.phpt b/ext/spl/tests/dllist_012.phpt new file mode 100644 index 0000000..4eec9bd --- /dev/null +++ b/ext/spl/tests/dllist_012.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: DoublyLinkedList: recursive var_dump +--FILE-- +<?php +$a = new SplDoublyLinkedList; +$a[] = $a; + +var_dump($a); +?> +===DONE=== +--EXPECTF-- +object(SplDoublyLinkedList)#%d (2) { + ["flags":"SplDoublyLinkedList":private]=> + int(0) + ["dllist":"SplDoublyLinkedList":private]=> + array(1) { + [0]=> + *RECURSION* + } +} +===DONE=== diff --git a/ext/spl/tests/dllist_memleak.phpt b/ext/spl/tests/dllist_memleak.phpt new file mode 100644 index 0000000..9bae68b --- /dev/null +++ b/ext/spl/tests/dllist_memleak.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: DoublyLinkedList: memory leak when iterator pointer isn't at the last element +--FILE-- +<?php +$dll = new SplDoublyLinkedList(); +$dll->push(1); +$dll->push(2); +$dll->push(3); +$dll->push(4); + + +$dll->rewind(); +echo $dll->current()."\n"; +$dll->next(); +$dll->next(); +echo $dll->current()."\n"; + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +1 +3 +===DONE=== diff --git a/ext/spl/tests/fileobject_001.phpt b/ext/spl/tests/fileobject_001.phpt new file mode 100644 index 0000000..61f688d --- /dev/null +++ b/ext/spl/tests/fileobject_001.phpt @@ -0,0 +1,88 @@ +--TEST-- +SPL: SplFileObject::seek'ing +--FILE-- +<?php + +$o = new SplFileObject(dirname(__FILE__) . '/fileobject_001a.txt'); + +var_dump($o->key()); +var_dump($o->current()); +$o->setFlags(SplFileObject::DROP_NEW_LINE); +var_dump($o->key()); +var_dump($o->current()); +var_dump($o->key()); +$o->next(); +var_dump($o->key()); +var_dump($o->current()); +var_dump($o->key()); +$o->rewind(); +var_dump($o->key()); +var_dump($o->current()); +var_dump($o->key()); +$o->seek(4); +var_dump($o->key()); +var_dump($o->current()); +var_dump($o->key()); + +echo "===A===\n"; +foreach($o as $n => $l) +{ + var_dump($n, $l); +} + +echo "===B===\n"; +$o = new SplFileObject(dirname(__FILE__) . '/fileobject_001b.txt'); +$o->setFlags(SplFileObject::DROP_NEW_LINE); +foreach($o as $n => $l) +{ + var_dump($n, $l); +} + +?> +===DONE=== +--EXPECT-- +int(0) +string(2) "0 +" +int(0) +string(2) "0 +" +int(0) +int(1) +string(1) "1" +int(1) +int(0) +string(1) "0" +int(0) +int(4) +string(1) "4" +int(4) +===A=== +int(0) +string(1) "0" +int(1) +string(1) "1" +int(2) +string(1) "2" +int(3) +string(1) "3" +int(4) +string(1) "4" +int(5) +string(1) "5" +int(6) +string(0) "" +===B=== +int(0) +string(1) "0" +int(1) +string(1) "1" +int(2) +string(1) "2" +int(3) +string(1) "3" +int(4) +string(1) "4" +int(5) +string(1) "5" +===DONE=== diff --git a/ext/spl/tests/fileobject_001a.txt b/ext/spl/tests/fileobject_001a.txt new file mode 100755 index 0000000..e8371f0 --- /dev/null +++ b/ext/spl/tests/fileobject_001a.txt @@ -0,0 +1,6 @@ +0 +1 +2 +3 +4 +5 diff --git a/ext/spl/tests/fileobject_001b.txt b/ext/spl/tests/fileobject_001b.txt new file mode 100755 index 0000000..0c4a8b5 --- /dev/null +++ b/ext/spl/tests/fileobject_001b.txt @@ -0,0 +1,6 @@ +0 +1 +2 +3 +4 +5
\ No newline at end of file diff --git a/ext/spl/tests/fileobject_002.phpt b/ext/spl/tests/fileobject_002.phpt new file mode 100644 index 0000000..8031e98 --- /dev/null +++ b/ext/spl/tests/fileobject_002.phpt @@ -0,0 +1,122 @@ +--TEST-- +SPL: SplFileObject::fgetc +--FILE-- +<?php + +function test($name) +{ + echo "===$name===\n"; + + $o = new SplFileObject(dirname(__FILE__) . '/' . $name); + + var_dump($o->key()); + while(($c = $o->fgetc()) !== false) + { + var_dump($o->key(), $c, $o->eof()); + } + echo "===EOF?===\n"; + var_dump($o->eof()); + var_dump($o->key()); + var_dump($o->eof()); +} + +test('fileobject_001a.txt'); +test('fileobject_001b.txt'); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +===fileobject_001a.txt=== +int(0) +int(0) +string(1) "0" +bool(false) +int(1) +string(1) " +" +bool(false) +int(1) +string(1) "1" +bool(false) +int(2) +string(1) " +" +bool(false) +int(2) +string(1) "2" +bool(false) +int(3) +string(1) " +" +bool(false) +int(3) +string(1) "3" +bool(false) +int(4) +string(1) " +" +bool(false) +int(4) +string(1) "4" +bool(false) +int(5) +string(1) " +" +bool(false) +int(5) +string(1) "5" +bool(false) +int(6) +string(1) " +" +bool(false) +===EOF?=== +bool(true) +int(6) +bool(true) +===fileobject_001b.txt=== +int(0) +int(0) +string(1) "0" +bool(false) +int(1) +string(1) " +" +bool(false) +int(1) +string(1) "1" +bool(false) +int(2) +string(1) " +" +bool(false) +int(2) +string(1) "2" +bool(false) +int(3) +string(1) " +" +bool(false) +int(3) +string(1) "3" +bool(false) +int(4) +string(1) " +" +bool(false) +int(4) +string(1) "4" +bool(false) +int(5) +string(1) " +" +bool(false) +int(5) +string(1) "5" +bool(false) +===EOF?=== +bool(true) +int(5) +bool(true) +===DONE=== diff --git a/ext/spl/tests/fileobject_003.phpt b/ext/spl/tests/fileobject_003.phpt new file mode 100644 index 0000000..6cc650b --- /dev/null +++ b/ext/spl/tests/fileobject_003.phpt @@ -0,0 +1,114 @@ +--TEST-- +SPL: SplFileInfo cloning +--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()); + + try { + $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); + } catch (LogicException $e) { + echo "LogicException: ".$e->getMessage()."\n"; + } + try { + $fo = $o->openFile(); + var_dump($fo->getPathName(), $fo->getFileName(), $fo->getPath()); + } catch (LogicException $e) { + echo "LogicException: ".$e->getMessage()."\n"; + } +} + +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 (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%s" + ["fileName":"SplFileInfo":private]=> + string(%d) "fileobject_001a.txt" +} +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%s" + ["fileName":"SplFileInfo":private]=> + string(%d) "fileobject_001a.txt" +} +bool(false) +bool(true) +bool(true) +%s(%d) "%sfileobject_001a.txt" +string(%d) "%sfileobject_001a.txt" +bool(true) +string(19) "fileobject_001a.txt" +bool(true) +string(%d) "%stests" +bool(true) +string(%d) "%sfileobject_001a.txt" +string(19) "fileobject_001a.txt" +string(%d) "%stests" +===1=== +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%s" + ["fileName":"SplFileInfo":private]=> + string(%d) "%s" +} +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%s" + ["fileName":"SplFileInfo":private]=> + string(%d) "%s" +} +bool(false) +bool(true) +bool(true) +LogicException: Cannot use SplFileObject with directories +LogicException: Cannot use SplFileObject with directories +===2=== +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%s" + ["fileName":"SplFileInfo":private]=> + string(%d) "%s" +} +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%s" + ["fileName":"SplFileInfo":private]=> + string(%d) "%s" +} +bool(false) +bool(true) +bool(true) +LogicException: Cannot use SplFileObject with directories +LogicException: Cannot use SplFileObject with directories +===DONE=== diff --git a/ext/spl/tests/fileobject_004.phpt b/ext/spl/tests/fileobject_004.phpt new file mode 100644 index 0000000..02e6725 --- /dev/null +++ b/ext/spl/tests/fileobject_004.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject realpath and include_path +--FILE-- +<?php + +set_include_path('tests'); + +chdir(dirname(dirname(__FILE__))); // ext/spl + + +$fo = new SplFileObject('fileobject_004.phpt', 'r', true); + +var_dump($fo->getPath()); +var_dump($fo->getFilename()); +var_dump($fo->getRealPath()); +?> +==DONE== +--EXPECTF-- +string(%d) "%sspl%stests" +string(19) "fileobject_004.phpt" +string(%d) "%sspl%stests%sfileobject_004.phpt" +==DONE== diff --git a/ext/spl/tests/fileobject_005.phpt b/ext/spl/tests/fileobject_005.phpt new file mode 100644 index 0000000..fa9e6db --- /dev/null +++ b/ext/spl/tests/fileobject_005.phpt @@ -0,0 +1,42 @@ +--TEST-- +SPL: SplFileObject truncate tests +--CREDITS-- +Mark Ammann +#Hackday Webtuesday 2008-05-24 +--FILE-- +<?php + +set_include_path(dirname(dirname(__FILE__))); + +$path = dirname(__FILE__).DIRECTORY_SEPARATOR.'fileobject_005.txt'; +touch($path); + +$fo = new SplFileObject('tests'.DIRECTORY_SEPARATOR.'fileobject_005.txt', 'w+', true); +$fo->fwrite("blahlubba"); +var_dump($fo->ftruncate(4)); + +$fo->rewind(); +var_dump($fo->fgets(8)); + +$fo->rewind(); +$fo->fwrite("blahlubba"); + +// This should throw a warning and return NULL since an argument is missing +var_dump($fo->ftruncate()); + +?> +==DONE== +--CLEAN-- +<?php +$path = dirname(__FILE__).DIRECTORY_SEPARATOR.'fileobject_005.txt'; +unlink($path); +?> +--EXPECTF-- +bool(true) + +Warning: SplFileObject::fgets() expects exactly 0 parameters, 1 given in %s on line %d +NULL + +Warning: SplFileObject::ftruncate() expects exactly 1 parameter, 0 given in %s on line %d +NULL +==DONE==
\ No newline at end of file diff --git a/ext/spl/tests/fileobject_checktype_basic.phpt b/ext/spl/tests/fileobject_checktype_basic.phpt new file mode 100644 index 0000000..650204e --- /dev/null +++ b/ext/spl/tests/fileobject_checktype_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: SplFileObject::isFile/isDir/isLink +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--FILE-- +<?php +$s = new SplFileObject(__FILE__); +var_dump($s->isFile()); +var_dump($s->isDir()); +var_dump($s->isLink()); +?> +--EXPECT-- +bool(true) +bool(false) +bool(false) diff --git a/ext/spl/tests/fileobject_getbasename_basic.phpt b/ext/spl/tests/fileobject_getbasename_basic.phpt new file mode 100644 index 0000000..34fecdc --- /dev/null +++ b/ext/spl/tests/fileobject_getbasename_basic.phpt @@ -0,0 +1,13 @@ +--TEST-- +SPL: SplFileObject::getBasename +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--FILE-- +<?php +$file = __FILE__; +$s = new SplFileObject( __FILE__ ); +echo $s->getBasename(); +?> +--EXPECT-- +fileobject_getbasename_basic.php diff --git a/ext/spl/tests/fileobject_getcurrentline_basic.phpt b/ext/spl/tests/fileobject_getcurrentline_basic.phpt new file mode 100644 index 0000000..607fce6 --- /dev/null +++ b/ext/spl/tests/fileobject_getcurrentline_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplFileObject::getCurrentLine +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--FILE-- +<?php +//line 2 +//line 3 +//line 4 +//line 5 +$s = new SplFileObject(__FILE__); +$s->seek(1); +echo $s->getCurrentLine(); +echo $s->getCurrentLine(); +?> +--EXPECT-- +//line 3 +//line 4 diff --git a/ext/spl/tests/fileobject_getfileinfo_basic.phpt b/ext/spl/tests/fileobject_getfileinfo_basic.phpt new file mode 100644 index 0000000..97d0de2 --- /dev/null +++ b/ext/spl/tests/fileobject_getfileinfo_basic.phpt @@ -0,0 +1,44 @@ +--TEST-- +SPL: SplFileObject::getFileInfo +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--INI-- +include_path=. +--FILE-- +<?php +$file = __FILE__; +$s = new SplFileObject( $file ); +var_dump($fi = $s->getFileInfo(), (string)$fi); + +$d = new SplFileInfo( __DIR__ ); +echo "\n"; +var_dump($fi = $d->getFileInfo(), (string)$fi); +$d = new SplFileInfo( __DIR__."/" ); +echo "\n"; +var_dump($fi = $d->getFileInfo(), (string)$fi); +?> +--EXPECTF-- +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%sext%espl%etests%efileobject_getfileinfo_basic.php" + ["fileName":"SplFileInfo":private]=> + string(%d) "fileobject_getfileinfo_basic.php" +} +string(%d) "%sext%espl%etests%efileobject_getfileinfo_basic.php" + +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%sext%espl%etests" + ["fileName":"SplFileInfo":private]=> + string(%d) "tests" +} +string(%d) "%sext%espl%etests" + +object(SplFileInfo)#%d (2) { + ["pathName":"SplFileInfo":private]=> + string(%d) "%sext%espl%etests" + ["fileName":"SplFileInfo":private]=> + string(%d) "tests" +} +string(%d) "%sext%espl%etests" diff --git a/ext/spl/tests/fileobject_getmaxlinelen_basic.phpt b/ext/spl/tests/fileobject_getmaxlinelen_basic.phpt new file mode 100644 index 0000000..b08a711 --- /dev/null +++ b/ext/spl/tests/fileobject_getmaxlinelen_basic.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: SplFileObject::getMaxLineLen() +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--INI-- +include_path=. +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->setMaxLineLen( 7 ); +echo $s->getMaxLineLen(); +?> +--EXPECT-- +7 diff --git a/ext/spl/tests/fileobject_getmaxlinelen_error001.phpt b/ext/spl/tests/fileobject_getmaxlinelen_error001.phpt new file mode 100644 index 0000000..3c0c9ee --- /dev/null +++ b/ext/spl/tests/fileobject_getmaxlinelen_error001.phpt @@ -0,0 +1,14 @@ +--TEST-- +SPL: SplFileObject::getMaxLineLen error 001 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--INI-- +include_path=. +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->getMaxLineLen('string'); + +?> +--EXPECTF-- +Warning: SplFileObject::getMaxLineLen() expects exactly 0 parameters, 1 given in %s on line %d diff --git a/ext/spl/tests/fileobject_getsize_basic.phpt b/ext/spl/tests/fileobject_getsize_basic.phpt new file mode 100644 index 0000000..da9f708 --- /dev/null +++ b/ext/spl/tests/fileobject_getsize_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplFileObject::getSize +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--INI-- +include_path=. +--FILE-- +<?php +$file = __DIR__ ."/data.txt"; +file_put_contents($file, "foobar"); + +$s = new SplFileObject( $file ); +echo $s->getSize(); +?> +--CLEAN-- +<?php +$file = __DIR__ ."/data.txt"; +unlink($file); +?> +--EXPECT-- +6 diff --git a/ext/spl/tests/fileobject_setmaxlinelen_basic.phpt b/ext/spl/tests/fileobject_setmaxlinelen_basic.phpt new file mode 100644 index 0000000..c230766 --- /dev/null +++ b/ext/spl/tests/fileobject_setmaxlinelen_basic.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: SplFileObject::setMaxLineLen +--CREDITS-- +H�vard Eide <nucleuz at gmail.com> +#Testfest php.no +--INI-- +include_path=. +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->setMaxLineLen( 3); +echo $s->getCurrentLine(); +?> +--EXPECT-- +<? diff --git a/ext/spl/tests/fileobject_setmaxlinelen_error001.phpt b/ext/spl/tests/fileobject_setmaxlinelen_error001.phpt new file mode 100644 index 0000000..6bfdfdc --- /dev/null +++ b/ext/spl/tests/fileobject_setmaxlinelen_error001.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: SplFileObject::setMaxLineLen error 001() +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +try { + $s->setMaxLineLen(-1); +} +catch (DomainException $e) { + echo 'DomainException thrown'; +} + +?> +--EXPECT-- +DomainException thrown diff --git a/ext/spl/tests/fileobject_setmaxlinelen_error002.phpt b/ext/spl/tests/fileobject_setmaxlinelen_error002.phpt new file mode 100644 index 0000000..dad59fc --- /dev/null +++ b/ext/spl/tests/fileobject_setmaxlinelen_error002.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplFileObject::setMaxLineLen error 002 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->setMaxLineLen(); + +?> +--EXPECTF-- +Warning: SplFileObject::setMaxLineLen() expects exactly 1 parameter, 0 given in %s on line %d diff --git a/ext/spl/tests/fileobject_setmaxlinelen_error003.phpt b/ext/spl/tests/fileobject_setmaxlinelen_error003.phpt new file mode 100644 index 0000000..8dc50d5 --- /dev/null +++ b/ext/spl/tests/fileobject_setmaxlinelen_error003.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplFileObject::setMaxLineLen error 003 +--CREDITS-- +Erwin Poeze <erwin.poeze at gmail.com> +--FILE-- +<?php +$s = new SplFileObject( __FILE__ ); +$s->setMaxLineLen('string'); + +?> +--EXPECTF-- +Warning: SplFileObject::setMaxLineLen() expects parameter 1 to be long, string given in %s on line %d diff --git a/ext/spl/tests/filesystemiterator_flags.phpt b/ext/spl/tests/filesystemiterator_flags.phpt new file mode 100644 index 0000000..6353456 --- /dev/null +++ b/ext/spl/tests/filesystemiterator_flags.phpt @@ -0,0 +1,40 @@ +--TEST-- +SPL: FilesystemIterator::getFlags() basic tests +--CREDITS-- +Joshua Thijssen <jthijssen@noxlogic.nl> +--FILE-- +<?php + +$it = new FileSystemIterator("."); +printflags($it); + +$it->setFlags(FileSystemIterator::CURRENT_AS_SELF | + FileSystemIterator::KEY_AS_FILENAME | + FileSystemIterator::SKIP_DOTS | + FileSystemIterator::UNIX_PATHS); +printflags($it); + +$it->setFlags(-1); +printflags($it); + +function printflags($it) { + printf("%08X\n", $it->getFlags()); + printf("%08X\n", ($it->getFlags() & FileSystemIterator::CURRENT_MODE_MASK)); + printf("%08X\n", ($it->getFlags() & FileSystemIterator::KEY_MODE_MASK)); + printf("%08X\n", ($it->getFlags() & FileSystemIterator::OTHER_MODE_MASK)); +} + +?> +--EXPECT-- +00001000 +00000000 +00000000 +00001000 +00003110 +00000010 +00000100 +00003000 +00003FF0 +000000F0 +00000F00 +00003000 diff --git a/ext/spl/tests/fixedarray_001.phpt b/ext/spl/tests/fixedarray_001.phpt new file mode 100644 index 0000000..8276333 --- /dev/null +++ b/ext/spl/tests/fixedarray_001.phpt @@ -0,0 +1,60 @@ +--TEST-- +SPL: FixedArray: std operations +--FILE-- +<?php +$a = new SplFixedArray(0); +// errors +try { + $a[0] = "value1"; +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + var_dump($a["asdf"]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + unset($a[-1]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +$a->setSize(10); + + +$a[0] = "value0"; +$a[1] = "value1"; +$a[2] = "value2"; +$a[3] = "value3"; +$ref = "value4"; +$ref2 =&$ref; +$a[4] = $ref; +$ref = "value5"; + +unset($a[1]); + +var_dump($a[0], $a[2], $a[3], $a[4]); + +// countable + +var_dump(count($a), $a->getSize(), count($a) == $a->getSize()); + +// clonable +$b = clone $a; +$a[0] = "valueNew"; +var_dump($b[0]); +?> +===DONE=== +--EXPECTF-- +Exception: Index invalid or out of range +Exception: Index invalid or out of range +Exception: Index invalid or out of range +string(6) "value0" +string(6) "value2" +string(6) "value3" +string(6) "value4" +int(10) +int(10) +bool(true) +string(6) "value0" +===DONE=== diff --git a/ext/spl/tests/fixedarray_002.phpt b/ext/spl/tests/fixedarray_002.phpt new file mode 100644 index 0000000..534d41f --- /dev/null +++ b/ext/spl/tests/fixedarray_002.phpt @@ -0,0 +1,100 @@ +--TEST-- +SPL: FixedArray: overloading +--FILE-- +<?php +class A extends SplFixedArray { + public function count() { + return 2; + } + + public function offsetGet($n) { + echo "A::offsetGet\n"; + return parent::offsetGet($n); + } + public function offsetSet($n, $v) { + echo "A::offsetSet\n"; + return parent::offsetSet($n, $v); + } + public function offsetUnset($n) { + echo "A::offsetUnset\n"; + return parent::offsetUnset($n); + } + public function offsetExists($n) { + echo "A::offsetExists\n"; + return parent::offsetExists($n); + } +} + +$a = new A; + +// errors +try { + $a[0] = "value1"; +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + var_dump($a["asdf"]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + unset($a[-1]); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +$a->setSize(10); + + +$a[0] = "value0"; +$a[1] = "value1"; +$a[2] = "value2"; +$a[3] = "value3"; +$ref = "value4"; +$ref2 =&$ref; +$a[4] = $ref; +$ref = "value5"; + +unset($a[1]); +var_dump(isset($a[1]), isset($a[2]), empty($a[1]), empty($a[2])); + +var_dump($a[0], $a[2], $a[3], $a[4]); + +// countable + +var_dump(count($a), $a->getSize(), count($a) == $a->getSize()); +?> +===DONE=== +--EXPECTF-- +A::offsetSet +Exception: Index invalid or out of range +A::offsetGet +Exception: Index invalid or out of range +A::offsetUnset +Exception: Index invalid or out of range +A::offsetSet +A::offsetSet +A::offsetSet +A::offsetSet +A::offsetSet +A::offsetUnset +A::offsetExists +A::offsetExists +A::offsetExists +A::offsetExists +bool(false) +bool(true) +bool(true) +bool(false) +A::offsetGet +A::offsetGet +A::offsetGet +A::offsetGet +string(6) "value0" +string(6) "value2" +string(6) "value3" +string(6) "value4" +int(2) +int(10) +bool(false) +===DONE=== diff --git a/ext/spl/tests/fixedarray_003.phpt b/ext/spl/tests/fixedarray_003.phpt new file mode 100644 index 0000000..b6c5eb5 --- /dev/null +++ b/ext/spl/tests/fixedarray_003.phpt @@ -0,0 +1,86 @@ +--TEST-- +SPL: FixedArray: Iterators +--FILE-- +<?php +class A extends SplFixedArray { + + public function current() { + echo "A::current\n"; + return parent::current(); + } + public function key() { + echo "A::key\n"; + return parent::key(); + } + public function rewind() { + echo "A::rewind\n"; + return parent::rewind(); + } + public function valid() { + echo "A::valid\n"; + return parent::valid(); + } + public function next() { + echo "A::next\n"; + return parent::next(); + } +} + +echo "==Direct instance==\n"; +$a = new SplFixedArray(5); +$a[0] = "a"; +$a[1] = "c"; +$a[2] = "d"; +$a[3] = "e"; +$a[4] = "f"; +foreach ($a as $k => $v) { + echo "$k => $v\n"; +} +echo "==Child instance==\n"; +$a = new A(5); +$a[0] = "a"; +$a[1] = "c"; +$a[2] = "d"; +$a[3] = "e"; +$a[4] = "f"; +foreach ($a as $k => $v) { + echo "$k => $v\n"; +} +?> +===DONE=== +--EXPECTF-- +==Direct instance== +0 => a +1 => c +2 => d +3 => e +4 => f +==Child instance== +A::rewind +A::valid +A::current +A::key +0 => a +A::next +A::valid +A::current +A::key +1 => c +A::next +A::valid +A::current +A::key +2 => d +A::next +A::valid +A::current +A::key +3 => e +A::next +A::valid +A::current +A::key +4 => f +A::next +A::valid +===DONE=== diff --git a/ext/spl/tests/fixedarray_004.phpt b/ext/spl/tests/fixedarray_004.phpt new file mode 100644 index 0000000..cb62e0c --- /dev/null +++ b/ext/spl/tests/fixedarray_004.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: FixedArray: adding new elements +--FILE-- +<?php + +$a = new SplFixedArray(10); + +try { + $a[] = 1; +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +?> +===DONE=== +--EXPECTF-- +string(29) "Index invalid or out of range" +===DONE=== diff --git a/ext/spl/tests/fixedarray_005.phpt b/ext/spl/tests/fixedarray_005.phpt new file mode 100644 index 0000000..9ccc693 --- /dev/null +++ b/ext/spl/tests/fixedarray_005.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: FixedArray: Trying to instantiate passing object to constructor parameter +--FILE-- +<?php + +$b = new stdClass; + +$a = new SplFixedArray($b); + +?> +--EXPECTF-- +Warning: SplFixedArray::__construct() expects parameter 1 to be long, object given in %s on line %d diff --git a/ext/spl/tests/fixedarray_006.phpt b/ext/spl/tests/fixedarray_006.phpt new file mode 100644 index 0000000..8641821 --- /dev/null +++ b/ext/spl/tests/fixedarray_006.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: FixedArray: Assigning objects +--FILE-- +<?php + +$b = 10000; +$a = new SplFixedArray($b); + +try { + for ($i = 0; $i < 100; $i++) { + $a[] = new stdClass; + } +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +print "ok\n"; + +?> +--EXPECT-- +Index invalid or out of range +ok diff --git a/ext/spl/tests/fixedarray_007.phpt b/ext/spl/tests/fixedarray_007.phpt new file mode 100644 index 0000000..308ce31 --- /dev/null +++ b/ext/spl/tests/fixedarray_007.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: FixedArray: Assigning the itself object +--FILE-- +<?php + +$b = 10; +$a = new SplFixedArray($b); + +try { + $a[1] = $a; +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +foreach ($a as $c) { + if ($c) { + echo $c->getSize(), "\n"; + } +} + +print "ok\n"; + +?> +--EXPECT-- +10 +ok diff --git a/ext/spl/tests/fixedarray_008.phpt b/ext/spl/tests/fixedarray_008.phpt new file mode 100644 index 0000000..8775d61 --- /dev/null +++ b/ext/spl/tests/fixedarray_008.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: FixedArray: Assigning the itself object testing the reference +--FILE-- +<?php + +$b = 3; +$a = new SplFixedArray($b); + +$a[0] = 1; +$a[1] = 2; +$a[2] = $a; + +$a[2][0] = 3; + +foreach ($a as $x) { + if (is_object($x)) { + var_dump($x[0]); + } else { + var_dump($x); + } +} + +var_dump($a->getSize()); + +?> +--EXPECT-- +int(3) +int(2) +int(3) +int(3) diff --git a/ext/spl/tests/fixedarray_009.phpt b/ext/spl/tests/fixedarray_009.phpt new file mode 100644 index 0000000..936d210 --- /dev/null +++ b/ext/spl/tests/fixedarray_009.phpt @@ -0,0 +1,10 @@ +--TEST-- +SPL: FixedArray: Trying to instantiate passing string to construtor parameter +--FILE-- +<?php + +$a = new SplFixedArray('FOO'); + +?> +--EXPECTF-- +Warning: SplFixedArray::__construct() expects parameter 1 to be long, string given in %s on line %d diff --git a/ext/spl/tests/fixedarray_010.phpt b/ext/spl/tests/fixedarray_010.phpt new file mode 100644 index 0000000..472e8b0 --- /dev/null +++ b/ext/spl/tests/fixedarray_010.phpt @@ -0,0 +1,50 @@ +--TEST-- +SPL: FixedArray: Setting size +--FILE-- +<?php + +$a = new SplFixedArray(0); +$a = new SplFixedArray(3); + +$a[0] = 1; + +$a->setSize(2); +$a->setSize(3); +$a->setSize(0); + +$a = new SplFixedArray(0); +$a->setSize(0); +var_dump($a->getSize()); + +$a = new SplFixedArray(10); +$a->setSize(10); +var_dump($a->getSize()); + +$a = new SplFixedArray(1); +$a->setSize(5); +var_dump($a->getSize()); + +$a = new SplFixedArray(20); +$a->setSize(3); +var_dump($a->getSize()); + +$a = new SplFixedArray(3); + +$a[0] = "test"; +$a[1] = array(1,2,"blah"); +$a[2] = 1; +$a[0] = "test"; + +$a->setSize(0); +var_dump($a->getSize()); + +print "ok\n"; + +?> +--EXPECT-- +int(0) +int(10) +int(5) +int(3) +int(0) +ok diff --git a/ext/spl/tests/fixedarray_011.phpt b/ext/spl/tests/fixedarray_011.phpt new file mode 100644 index 0000000..eddf320 --- /dev/null +++ b/ext/spl/tests/fixedarray_011.phpt @@ -0,0 +1,14 @@ +--TEST-- +SPL: FixedArray: Testing setSize() with NULL +--FILE-- +<?php + +$a = new SplFixedArray(100); + +$a->setSize(NULL); + +print "ok\n"; + +?> +--EXPECT-- +ok diff --git a/ext/spl/tests/fixedarray_012.phpt b/ext/spl/tests/fixedarray_012.phpt new file mode 100644 index 0000000..3461b3a --- /dev/null +++ b/ext/spl/tests/fixedarray_012.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: FixedArray: Assigning the object to another variable using [] +--FILE-- +<?php + +$a = new SplFixedArray(100); + +try { + $b = &$a[]; +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +print "ok\n"; + +?> +--EXPECT-- +Index invalid or out of range +ok diff --git a/ext/spl/tests/fixedarray_013.phpt b/ext/spl/tests/fixedarray_013.phpt new file mode 100644 index 0000000..52ae3c1 --- /dev/null +++ b/ext/spl/tests/fixedarray_013.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: FixedArray: Passing the object using [] as parameter +--FILE-- +<?php + +$a = new SplFixedArray(100); + + +function test(SplFixedArray &$arr) { + print "ok\n"; +} + +try { + test($a[]); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Index invalid or out of range diff --git a/ext/spl/tests/fixedarray_014.phpt b/ext/spl/tests/fixedarray_014.phpt new file mode 100644 index 0000000..de8e214 --- /dev/null +++ b/ext/spl/tests/fixedarray_014.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: FixedArray: Trying to access inexistent item +--FILE-- +<?php + +try { + $a = new SplFixedArray(NULL); + echo $a[0]++; +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Index invalid or out of range diff --git a/ext/spl/tests/fixedarray_015.phpt b/ext/spl/tests/fixedarray_015.phpt new file mode 100644 index 0000000..60fc4d1 --- /dev/null +++ b/ext/spl/tests/fixedarray_015.phpt @@ -0,0 +1,49 @@ +--TEST-- +SPL: FixedArray: accessing uninitialized array +--FILE-- +<?php + +$a = new SplFixedArray(''); + +try { + var_dump($a[1]); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +try { + $a[1] = 1; +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(count($a[1])); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump($a->getSize()); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +try { + foreach ($a as $v) { + } +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump($a->setSize(10)); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +echo "Done\n"; +?> +--EXPECTF-- +Warning: SplFixedArray::__construct() expects parameter 1 to be long, string given in %s on line %d +Index invalid or out of range +Index invalid or out of range +Index invalid or out of range +int(0) +bool(true) +Done diff --git a/ext/spl/tests/fixedarray_016.phpt b/ext/spl/tests/fixedarray_016.phpt new file mode 100644 index 0000000..fb61ee3 --- /dev/null +++ b/ext/spl/tests/fixedarray_016.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: FixedArray: var_dump +--FILE-- +<?php +$a = new SplFixedArray(2); +$a[0] = "foo"; +var_dump(empty($a[0]), empty($a[1]), $a); +?> +--EXPECTF-- +bool(false) +bool(true) +object(SplFixedArray)#%d (2) { + [0]=> + string(3) "foo" + [1]=> + NULL +} diff --git a/ext/spl/tests/fixedarray_017.phpt b/ext/spl/tests/fixedarray_017.phpt new file mode 100644 index 0000000..fb61ee3 --- /dev/null +++ b/ext/spl/tests/fixedarray_017.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: FixedArray: var_dump +--FILE-- +<?php +$a = new SplFixedArray(2); +$a[0] = "foo"; +var_dump(empty($a[0]), empty($a[1]), $a); +?> +--EXPECTF-- +bool(false) +bool(true) +object(SplFixedArray)#%d (2) { + [0]=> + string(3) "foo" + [1]=> + NULL +} diff --git a/ext/spl/tests/fixedarray_018.phpt b/ext/spl/tests/fixedarray_018.phpt new file mode 100644 index 0000000..84ab109 --- /dev/null +++ b/ext/spl/tests/fixedarray_018.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: FixedArray: overriden count() +--FILE-- +<?php +$obj = new SplFixedArray(2); +var_dump(count($obj)); +class SplFixedArray2 extends SplFixedArray { + public function count() { + return -parent::count(); + } +} +$obj = new SplFixedArray2(2); +var_dump(count($obj)); +?> +--EXPECT-- +int(2) +int(-2) diff --git a/ext/spl/tests/fixedarray_019.phpt b/ext/spl/tests/fixedarray_019.phpt new file mode 100644 index 0000000..f28edfd --- /dev/null +++ b/ext/spl/tests/fixedarray_019.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: FixedArray: overriden iterator methods +--FILE-- +<?php +class SplFixedArray2 extends SplFixedArray { + public function rewind() { + echo "rewind\n"; + return parent::rewind(); + } + public function valid() { + echo "valid\n"; + return parent::valid(); + } + public function next() { + echo "next\n"; + return parent::next(); + } + public function current() { + echo "current\n"; + return parent::current(); + } + public function key() { + echo "key\n"; + return parent::key(); + } +} + +$fa = new SplFixedArray2(3); +foreach($fa as $k=>$v) { + echo "$k=>"; + var_dump($v); +} +?> +--EXPECT-- +rewind +valid +current +key +0=>NULL +next +valid +current +key +1=>NULL +next +valid +current +key +2=>NULL +next +valid diff --git a/ext/spl/tests/fixedarray_020.phpt b/ext/spl/tests/fixedarray_020.phpt new file mode 100644 index 0000000..c0ff6e3 --- /dev/null +++ b/ext/spl/tests/fixedarray_020.phpt @@ -0,0 +1,36 @@ +--TEST-- +SPL: FixedArray: fromArray/toArray + get_properties +--FILE-- +<?php +$a = array(1=>'foo', 2=>'bar', 0=>'gee'); +$fa = SplFixedArray::fromArray($a, false); +var_dump(count($fa), $fa->toArray() === array_values($a)); + +$fa = SplFixedArray::fromArray($a, true); +var_dump(count($fa), $fa->toArray() === $a, $fa->toArray() === (array)$fa); + +try { + echo "From Array with string keys, no preserve\n"; + SplFixedArray::fromArray(array("foo"=>"bar"), false); + echo "No exception\n"; +} catch (Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + echo "From Array with string keys, preserve\n"; + SplFixedArray::fromArray(array("foo"=>"bar"), true); + echo "No exception\n"; +} catch (Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +?> +--EXPECT-- +int(3) +bool(true) +int(3) +bool(false) +bool(true) +From Array with string keys, no preserve +No exception +From Array with string keys, preserve +Exception: array must contain only positive integer keys diff --git a/ext/spl/tests/fixedarray_021.phpt b/ext/spl/tests/fixedarray_021.phpt new file mode 100644 index 0000000..97b0a70 --- /dev/null +++ b/ext/spl/tests/fixedarray_021.phpt @@ -0,0 +1,78 @@ +--TEST-- +SPL: FixedArray: misc small tests +--FILE-- +<?php + +/* empty count */ +$a = new SplFixedArray(); + +var_dump(count($a)); +var_dump($a->count()); + +/* negative init value */ +try { + $b = new SplFixedArray(-10); +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +/* resize and negative value */ +$b = new SplFixedArray(); +try { + $b->setSize(-5); +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +/* calling __construct() twice */ +$c = new SplFixedArray(0); +var_dump($c->__construct()); + +/* fromArray() from empty array */ +$d = new SplFixedArray(); +$d->fromArray(array()); + +var_dump(count($a)); +var_dump($a->count()); +var_dump($a); + +/* foreach by ref */ +$e = new SplFixedArray(10); +$e[0] = 1; +$e[1] = 5; +$e[2] = 10; + +try { + foreach ($e as $k=>&$v) { + var_dump($v); + } +} catch (Exception $e) { + var_dump($e->getMessage()); +} + +//non-long indexes +$a = new SplFixedArray(4); +$a["2"] = "foo"; +$a["1"] = "foo"; +$a["3"] = "0"; + +var_dump(isset($a["0"], $a[-1]), $a["1"]); +var_dump(empty($a["3"])); + +?> +==DONE== +--EXPECTF-- +int(0) +int(0) +string(35) "array size cannot be less than zero" +string(35) "array size cannot be less than zero" +NULL +int(0) +int(0) +object(SplFixedArray)#%d (0) { +} +string(52) "An iterator cannot be used with foreach by reference" +bool(false) +string(3) "foo" +bool(true) +==DONE== diff --git a/ext/spl/tests/heap_001.phpt b/ext/spl/tests/heap_001.phpt new file mode 100644 index 0000000..da4dde8 --- /dev/null +++ b/ext/spl/tests/heap_001.phpt @@ -0,0 +1,53 @@ +--TEST-- +SPL: SplMaxHeap: std operations +--FILE-- +<?php +$h = new SplMaxHeap(); + +// errors +try { + $h->extract(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + + +$h->insert(1); +$h->insert(2); +$h->insert(3); +$h->insert(3); +$h->insert(3); + +echo $h->count()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->count()."\n"; + +echo "--\n"; + +$b = 4; +$h->insert($b); +$b = 5; + +$h2 = clone $h; +echo $h->extract()."\n"; +echo $h2->extract()."\n"; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Can't extract from an empty heap +5 +3 +3 +3 +2 +1 +0 +-- +4 +4 +===DONE=== diff --git a/ext/spl/tests/heap_002.phpt b/ext/spl/tests/heap_002.phpt new file mode 100644 index 0000000..387510f --- /dev/null +++ b/ext/spl/tests/heap_002.phpt @@ -0,0 +1,50 @@ +--TEST-- +SPL: SplMinHeap: std operations +--FILE-- +<?php +$h = new SplMinHeap(); + +// errors +try { + $h->extract(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + + +$h->insert(1); +$h->insert(2); +$h->insert(3); +$h->insert(3); +$h->insert(3); + +echo $h->count()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->extract()."\n"; +echo $h->count()."\n"; + +echo "--\n"; + +$b = 4; +$h->insert($b); +$b = 5; + +echo $h->extract()."\n"; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Can't extract from an empty heap +5 +1 +2 +3 +3 +3 +0 +-- +4 +===DONE=== diff --git a/ext/spl/tests/heap_003.phpt b/ext/spl/tests/heap_003.phpt new file mode 100644 index 0000000..87f95e9 --- /dev/null +++ b/ext/spl/tests/heap_003.phpt @@ -0,0 +1,44 @@ +--TEST-- +SPL: SplHeap: comparison callback +--FILE-- +<?php +class myHeap extends SplHeap { + public function compare($a, $b) { + if ($a > $b) { + $result = 1; + } else if ($a < $b) { + $result = -1; + } else { + $result = 0; + } + return $result; + } +} + +$h = new myHeap; + +$in = range(0,10); +shuffle($in); +foreach ($in as $i) { + $h->insert($i); +} + +foreach ($h as $out) { + echo $out."\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 +===DONE=== diff --git a/ext/spl/tests/heap_004.phpt b/ext/spl/tests/heap_004.phpt new file mode 100644 index 0000000..7b00ebf --- /dev/null +++ b/ext/spl/tests/heap_004.phpt @@ -0,0 +1,67 @@ +--TEST-- +SPL: SplHeap: exceptions +--FILE-- +<?php +class myHeap extends SplHeap { + public function compare($a, $b) { + throw new exception("foo"); + } +} + +$h = new myHeap; + +try { + $h->insert(1); + echo "inserted 1\n"; + $h->insert(2); + echo "inserted 2\n"; + $h->insert(3); + echo "inserted 3\n"; +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + $h->insert(4); + echo "inserted 4\n"; +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +echo "Recovering..\n"; +$h->recoverFromCorruption(); + +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +inserted 1 +Exception: foo +Exception: Heap is corrupted, heap properties are no longer ensured. +Exception: Heap is corrupted, heap properties are no longer ensured. +Exception: Heap is corrupted, heap properties are no longer ensured. +Recovering.. +int(1) +int(2) +===DONE=== diff --git a/ext/spl/tests/heap_005.phpt b/ext/spl/tests/heap_005.phpt new file mode 100644 index 0000000..1291cda --- /dev/null +++ b/ext/spl/tests/heap_005.phpt @@ -0,0 +1,121 @@ +--TEST-- +SPL: SplMinHeap: large unordered input iterated +--FILE-- +<?php +$input = range(1,100); +shuffle($input); + +$h = new SplMinHeap(); + +foreach($input as $i) { + $h->insert($i); +} + +foreach ($h as $k => $o) { + echo "$k => $o\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +99 => 1 +98 => 2 +97 => 3 +96 => 4 +95 => 5 +94 => 6 +93 => 7 +92 => 8 +91 => 9 +90 => 10 +89 => 11 +88 => 12 +87 => 13 +86 => 14 +85 => 15 +84 => 16 +83 => 17 +82 => 18 +81 => 19 +80 => 20 +79 => 21 +78 => 22 +77 => 23 +76 => 24 +75 => 25 +74 => 26 +73 => 27 +72 => 28 +71 => 29 +70 => 30 +69 => 31 +68 => 32 +67 => 33 +66 => 34 +65 => 35 +64 => 36 +63 => 37 +62 => 38 +61 => 39 +60 => 40 +59 => 41 +58 => 42 +57 => 43 +56 => 44 +55 => 45 +54 => 46 +53 => 47 +52 => 48 +51 => 49 +50 => 50 +49 => 51 +48 => 52 +47 => 53 +46 => 54 +45 => 55 +44 => 56 +43 => 57 +42 => 58 +41 => 59 +40 => 60 +39 => 61 +38 => 62 +37 => 63 +36 => 64 +35 => 65 +34 => 66 +33 => 67 +32 => 68 +31 => 69 +30 => 70 +29 => 71 +28 => 72 +27 => 73 +26 => 74 +25 => 75 +24 => 76 +23 => 77 +22 => 78 +21 => 79 +20 => 80 +19 => 81 +18 => 82 +17 => 83 +16 => 84 +15 => 85 +14 => 86 +13 => 87 +12 => 88 +11 => 89 +10 => 90 +9 => 91 +8 => 92 +7 => 93 +6 => 94 +5 => 95 +4 => 96 +3 => 97 +2 => 98 +1 => 99 +0 => 100 +===DONE=== diff --git a/ext/spl/tests/heap_006.phpt b/ext/spl/tests/heap_006.phpt new file mode 100644 index 0000000..3218bdf --- /dev/null +++ b/ext/spl/tests/heap_006.phpt @@ -0,0 +1,121 @@ +--TEST-- +SPL: SplMaxHeap: large unordered input iterated +--FILE-- +<?php +$input = range(1,100); +shuffle($input); + +$h = new SplMaxHeap(); + +foreach($input as $i) { + $h->insert($i); +} + +foreach ($h as $k => $o) { + echo "$k => $o\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +99 => 100 +98 => 99 +97 => 98 +96 => 97 +95 => 96 +94 => 95 +93 => 94 +92 => 93 +91 => 92 +90 => 91 +89 => 90 +88 => 89 +87 => 88 +86 => 87 +85 => 86 +84 => 85 +83 => 84 +82 => 83 +81 => 82 +80 => 81 +79 => 80 +78 => 79 +77 => 78 +76 => 77 +75 => 76 +74 => 75 +73 => 74 +72 => 73 +71 => 72 +70 => 71 +69 => 70 +68 => 69 +67 => 68 +66 => 67 +65 => 66 +64 => 65 +63 => 64 +62 => 63 +61 => 62 +60 => 61 +59 => 60 +58 => 59 +57 => 58 +56 => 57 +55 => 56 +54 => 55 +53 => 54 +52 => 53 +51 => 52 +50 => 51 +49 => 50 +48 => 49 +47 => 48 +46 => 47 +45 => 46 +44 => 45 +43 => 44 +42 => 43 +41 => 42 +40 => 41 +39 => 40 +38 => 39 +37 => 38 +36 => 37 +35 => 36 +34 => 35 +33 => 34 +32 => 33 +31 => 32 +30 => 31 +29 => 30 +28 => 29 +27 => 28 +26 => 27 +25 => 26 +24 => 25 +23 => 24 +22 => 23 +21 => 22 +20 => 21 +19 => 20 +18 => 19 +17 => 18 +16 => 17 +15 => 16 +14 => 15 +13 => 14 +12 => 13 +11 => 12 +10 => 11 +9 => 10 +8 => 9 +7 => 8 +6 => 7 +5 => 6 +4 => 5 +3 => 4 +2 => 3 +1 => 2 +0 => 1 +===DONE=== diff --git a/ext/spl/tests/heap_007.phpt b/ext/spl/tests/heap_007.phpt new file mode 100644 index 0000000..e8d5c99 --- /dev/null +++ b/ext/spl/tests/heap_007.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: SplHeap: iteration through methods +--FILE-- +<?php +$h = new SplMaxHeap(); + +$h->insert(1); +$h->insert(5); +$h->insert(0); +$h->insert(4); + +$h->rewind(); +echo "count(\$h) = ".count($h)."\n"; +echo "\$h->count() = ".$h->count()."\n"; + +while ($h->valid()) { + $k = $h->key(); + $v = $h->current(); + echo "$k=>$v\n"; + $h->next(); +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +count($h) = 4 +$h->count() = 4 +3=>5 +2=>4 +1=>1 +0=>0 +===DONE=== diff --git a/ext/spl/tests/heap_008.phpt b/ext/spl/tests/heap_008.phpt new file mode 100644 index 0000000..178f546 --- /dev/null +++ b/ext/spl/tests/heap_008.phpt @@ -0,0 +1,34 @@ +--TEST-- +SPL: SplHeap: var_dump +--FILE-- +<?php +$h = new SplMaxHeap(); + +$h->insert(1); +$h->insert(5); +$h->insert(0); +$h->insert(4); + +var_dump($h); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(SplMaxHeap)#1 (3) { + ["flags":"SplHeap":private]=> + int(0) + ["isCorrupted":"SplHeap":private]=> + bool(false) + ["heap":"SplHeap":private]=> + array(4) { + [0]=> + int(5) + [1]=> + int(4) + [2]=> + int(0) + [3]=> + int(1) + } +} +===DONE=== diff --git a/ext/spl/tests/heap_009.phpt b/ext/spl/tests/heap_009.phpt new file mode 100644 index 0000000..f660b24 --- /dev/null +++ b/ext/spl/tests/heap_009.phpt @@ -0,0 +1,56 @@ +--TEST-- +SPL: SplHeap and friends, throw: An iterator cannot be used with foreach by reference +--CREDITS-- +Thomas Koch <thomas@koch.ro> +#Hackday Webtuesday 2008-05-24 +--FILE-- +<?php +function testForException( $heap ) +{ + try + { + foreach( $heap as &$item ); + } + catch( RuntimeException $e ) + { + echo $e->getMessage(),"\n"; + } +} + +// 1. SplMinHeap emtpy +$heap = new SplMinHeap; +testForException( $heap ); + +// 2. SplMinHeap non-emtpy +$heap = new SplMinHeap; +$heap->insert( 1 ); +testForException( $heap ); + +// 3. SplMaxHeap emtpy +$heap = new SplMaxHeap; +testForException( $heap ); + +// 4. SplMaxHeap non-emtpy +$heap = new SplMaxHeap; +$heap->insert( 1 ); +testForException( $heap ); + +// 5. SplPriorityQueue empty +$heap = new SplPriorityQueue; +testForException( $heap ); + +// 6. SplPriorityQueue non-empty +$heap = new SplPriorityQueue; +$heap->insert( 1, 2 ); +testForException( $heap ); + +?> +==DONE== +--EXPECT-- +An iterator cannot be used with foreach by reference +An iterator cannot be used with foreach by reference +An iterator cannot be used with foreach by reference +An iterator cannot be used with foreach by reference +An iterator cannot be used with foreach by reference +An iterator cannot be used with foreach by reference +==DONE== diff --git a/ext/spl/tests/heap_010.phpt b/ext/spl/tests/heap_010.phpt new file mode 100644 index 0000000..8c7d8d5 --- /dev/null +++ b/ext/spl/tests/heap_010.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: SplHeap with overriden count() +--FILE-- +<?php +$obj = new SplMaxHeap(); +$obj->insert(1); +$obj->insert(2); +var_dump(count($obj)); +class SplMaxHeap2 extends SplMaxHeap{ + public function count() { + return -parent::count(); + } +} +$obj = new SplMaxHeap2(); +$obj->insert(1); +$obj->insert(2); +var_dump(count($obj)); +?> +--EXPECT-- +int(2) +int(-2) diff --git a/ext/spl/tests/heap_011.phpt b/ext/spl/tests/heap_011.phpt new file mode 100644 index 0000000..1689abf --- /dev/null +++ b/ext/spl/tests/heap_011.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: SplHeap with overriden compare() +--FILE-- +<?php +class SplMinHeap2 extends SplMinHeap { + public function compare($a, $b) { + return -parent::compare($a,$b); + } +} +$h = new SplMinHeap2(); +$h->insert(1); +$h->insert(6); +$h->insert(5); +$h->insert(2); +var_dump($h->top()); + +class SplMaxHeap2 extends SplMaxHeap { + public function compare($a, $b) { + return -parent::compare($a,$b); + } +} +$h = new SplMaxHeap2(); +$h->insert(1); +$h->insert(6); +$h->insert(5); +$h->insert(2); +var_dump($h->top()); +?> +--EXPECT-- +int(6) +int(1) diff --git a/ext/spl/tests/heap_012.phpt b/ext/spl/tests/heap_012.phpt new file mode 100644 index 0000000..f86f14f --- /dev/null +++ b/ext/spl/tests/heap_012.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplHeap recursive var_dump +--FILE-- +<?php +$a = new SplMaxHeap; +$a->insert($a); +var_dump($a) +?> +===DONE=== +--EXPECTF-- +object(SplMaxHeap)#%d (3) { + ["flags":"SplHeap":private]=> + int(0) + ["isCorrupted":"SplHeap":private]=> + bool(false) + ["heap":"SplHeap":private]=> + array(1) { + [0]=> + *RECURSION* + } +} +===DONE=== diff --git a/ext/spl/tests/heap_corruption.phpt b/ext/spl/tests/heap_corruption.phpt new file mode 100644 index 0000000..284ee1d --- /dev/null +++ b/ext/spl/tests/heap_corruption.phpt @@ -0,0 +1,62 @@ +--TEST-- +SPL: SplHeap - heap corruption via compare exception (with top element deletion) +--CREDITS-- +Mike Sullivan <mikesul@php.net> +#TestFest 2009 (London) +--FILE-- +<?php + +class myHeap extends SplHeap +{ + public $allow_compare = true; + + public function compare($v1, $v2) + { + if ($this->allow_compare == true) + { + if ($v1 > $v2) + { + return 1; + } + else if ($v1 < $v2) + { + return -1; + } + else + { + return 0; + } + } + else + { + throw new Exception('Compare exception'); + } + } +} + +$heap = new myHeap(); +$heap->insert(1); +$heap->insert(2); +$heap->insert(3); +$heap->insert(4); + +$heap->allow_compare = false; + +try { + $heap->extract(); +} +catch (Exception $e) { + echo "Compare Exception: " . $e->getMessage() . PHP_EOL; +} + +try { + $heap->top(); +} +catch (Exception $e) { + echo "Corruption Exception: " . $e->getMessage() . PHP_EOL; +} + +?> +--EXPECT-- +Compare Exception: Compare exception +Corruption Exception: Heap is corrupted, heap properties are no longer ensured.
\ No newline at end of file diff --git a/ext/spl/tests/heap_current_variation_001.phpt b/ext/spl/tests/heap_current_variation_001.phpt new file mode 100644 index 0000000..eb6df2b --- /dev/null +++ b/ext/spl/tests/heap_current_variation_001.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplHeap::current - get current value from empty heap +--CREDITS-- +Mike Sullivan <mikesul@php.net> +#TestFest 2009 (London) +--FILE-- +<?php + +class myHeap extends SplHeap +{ + public function compare($v1, $v2) + { + throw new Exception(''); + } +} + +$heap = new myHeap(); +var_dump($heap->current()); + +?> +--EXPECT-- +NULL
\ No newline at end of file diff --git a/ext/spl/tests/heap_isempty_variation_001.phpt b/ext/spl/tests/heap_isempty_variation_001.phpt new file mode 100644 index 0000000..dac470f --- /dev/null +++ b/ext/spl/tests/heap_isempty_variation_001.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: SplHeap: isEmpty argument variation. +--FILE-- +<?php +class SplHeap2 extends SplHeap{ + + public function compare() { + return -parent::compare(); + } +} + +$h = new SplHeap2; +$h->isEmpty(1); +?> +--EXPECTF-- +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s diff --git a/ext/spl/tests/heap_it_current_empty.phpt b/ext/spl/tests/heap_it_current_empty.phpt new file mode 100644 index 0000000..24230db --- /dev/null +++ b/ext/spl/tests/heap_it_current_empty.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplHeap current, check looping through an empty heap gives you no values +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplMinHeap(); + +foreach ($h as $val) { echo 'FAIL'; } +?> +--EXPECT-- diff --git a/ext/spl/tests/heap_top_variation_001.phpt b/ext/spl/tests/heap_top_variation_001.phpt new file mode 100644 index 0000000..9953cf9 --- /dev/null +++ b/ext/spl/tests/heap_top_variation_001.phpt @@ -0,0 +1,14 @@ +--TEST-- +SPL: SplHeap top, illegal number of args +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplMinHeap(); +$h->insert(5); +// top doesn't take any args, lets see what happens if we give it one +$h->top('bogus'); +?> +--EXPECTF-- +Warning: SplHeap::top() expects exactly 0 parameters, 1 given in %s diff --git a/ext/spl/tests/heap_top_variation_002.phpt b/ext/spl/tests/heap_top_variation_002.phpt new file mode 100644 index 0000000..cd6a8d0 --- /dev/null +++ b/ext/spl/tests/heap_top_variation_002.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: SplHeap top, corrupted heap +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +// override heap to force corruption by throwing exception in compare +class SplMinHeap2 extends SplMinHeap { + public function compare($a, $b) { + throw new Exception('Corrupt heap'); + } +} + +$h = new SplMinHeap2(); + +// insert 2 elements to hit our overridden compare +$h->insert(4); +try { + $h->insert(5); +} catch (Exception $e) {} + +// call top, should fail with corrupted heap +try { + $h->top(); +} catch (Exception $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +Heap is corrupted, heap properties are no longer ensured. diff --git a/ext/spl/tests/heap_top_variation_003.phpt b/ext/spl/tests/heap_top_variation_003.phpt new file mode 100644 index 0000000..7a91a9c --- /dev/null +++ b/ext/spl/tests/heap_top_variation_003.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: SplHeap top of empty heap +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplMinHeap(); +try { + $h->top(); +} catch (Exception $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +Can't peek at an empty heap diff --git a/ext/spl/tests/iterator_001.phpt b/ext/spl/tests/iterator_001.phpt new file mode 100644 index 0000000..26df62e --- /dev/null +++ b/ext/spl/tests/iterator_001.phpt @@ -0,0 +1,171 @@ +--TEST-- +SPL: Iterator aggregating inner iterator's methods +--FILE-- +<?php + +class NumericArrayIterator implements Iterator +{ + protected $a; + protected $i = 0; + + public function __construct($a) + { + echo __METHOD__ . "\n"; + $this->a = $a; + } + + public function rewind() + { + echo __METHOD__ . "\n"; + $this->i = 0; + } + + public function valid() + { + $ret = $this->i < count($this->a); + echo __METHOD__ . '(' . ($ret ? 'true' : 'false') . ")\n"; + return $ret; + } + + 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++; + } + + public function greaterThan($comp) + { + echo get_class($this) . '::' . __FUNCTION__ . '(' . $comp . ")\n"; + return $this->current() > $comp; + } +} + +class SeekableNumericArrayIterator extends NumericArrayIterator implements SeekableIterator +{ + public function seek($index) + { + if ($index < count($this->a)) { + $this->i = $index; + } + echo __METHOD__ . '(' . $index . ")\n"; + } +} + +$a = array(1, 2, 3, 4, 5); +$it = new LimitIterator(new NumericArrayIterator($a), 1, 3); +foreach ($it as $v) +{ + print $v . ' is ' . ($it->greaterThan(2) ? 'greater than 2' : 'less than or equal 2') . "\n"; +} + +echo "===SEEKABLE===\n"; +$a = array(1, 2, 3, 4, 5); +$it = new LimitIterator(new SeekableNumericArrayIterator($a), 1, 3); +foreach($it as $v) +{ + print $v . ' is ' . ($it->greaterThan(2) ? 'greater than 2' : 'less than or equal 2') . "\n"; +} + +echo "===STACKED===\n"; +echo "Shows '2 is greater than 2' because the test is actually done with the current value which is 3.\n"; +$a = array(1, 2, 3, 4, 5); +$it = new CachingIterator(new LimitIterator(new SeekableNumericArrayIterator($a), 1, 3)); +foreach($it as $v) +{ + print $v . ' is ' . ($it->greaterThan(2) ? 'greater than 2' : 'less than or equal 2') . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +NumericArrayIterator::__construct +NumericArrayIterator::rewind +NumericArrayIterator::valid(true) +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +NumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +2 is less than or equal 2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +NumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +3 is greater than 2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +NumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +4 is greater than 2 +NumericArrayIterator::next +===SEEKABLE=== +NumericArrayIterator::__construct +NumericArrayIterator::rewind +SeekableNumericArrayIterator::seek(1) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +SeekableNumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +2 is less than or equal 2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +SeekableNumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +3 is greater than 2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +SeekableNumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +4 is greater than 2 +NumericArrayIterator::next +===STACKED=== +Shows '2 is greater than 2' because the test is actually done with the current value which is 3. +NumericArrayIterator::__construct +NumericArrayIterator::rewind +SeekableNumericArrayIterator::seek(1) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +SeekableNumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +2 is greater than 2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +SeekableNumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +3 is greater than 2 +NumericArrayIterator::next +SeekableNumericArrayIterator::greaterThan(2) +NumericArrayIterator::current +4 is greater than 2 +===DONE=== diff --git a/ext/spl/tests/iterator_002.phpt b/ext/spl/tests/iterator_002.phpt new file mode 100644 index 0000000..527fe6b --- /dev/null +++ b/ext/spl/tests/iterator_002.phpt @@ -0,0 +1,55 @@ +--TEST-- +SPL: Iterator using getInnerIterator +--FILE-- +<?php + +class RecursiceArrayIterator extends ArrayIterator implements RecursiveIterator +{ + function hasChildren() + { + return is_array($this->current()); + } + + function getChildren() + { + return new RecursiceArrayIterator($this->current()); + } +} + +class CrashIterator extends FilterIterator implements RecursiveIterator +{ + function accept() + { + return true; + } + + function hasChildren() + { + return $this->getInnerIterator()->hasChildren(); + } + + function getChildren() + { + return new RecursiceArrayIterator($this->getInnerIterator()->current()); + } +} + +$array = array(1, 2 => array(21, 22 => array(221, 222), 23 => array(231)), 3); + +$dir = new RecursiveIteratorIterator(new CrashIterator(new RecursiceArrayIterator($array)), RecursiveIteratorIterator::LEAVES_ONLY); + +foreach ($dir as $file) { + print "$file\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1 +21 +221 +222 +231 +3 +===DONE=== diff --git a/ext/spl/tests/iterator_003.phpt b/ext/spl/tests/iterator_003.phpt new file mode 100644 index 0000000..11d37b3 --- /dev/null +++ b/ext/spl/tests/iterator_003.phpt @@ -0,0 +1,95 @@ +--TEST-- +SPL: CachingIterator and __toString() +--FILE-- +<?php + +class Student +{ + private $id; + private $name; + + public function __construct($id, $name) + { + $this->id = $id; + $this->name = $name; + } + + public function __toString() + { + return $this->id . ', ' . $this->name; + } + + public function getId() + { + return $this->id; + } +} + +class StudentIdFilter extends FilterIterator +{ + private $id; + + public function __construct(ArrayObject $students, Student $other) + { + FilterIterator::__construct($students->getIterator()); + $this->id = $other->getId(); + } + + public function accept() + { + echo "ACCEPT ".$this->current()->getId()." == ".$this->id."\n"; + return $this->current()->getId() == $this->id; + } +} + +class StudentList implements IteratorAggregate +{ + private $students; + + public function __construct() + { + $this->students = new ArrayObject(array()); + } + + public function add(Student $student) + { + if (!$this->contains($student)) { + $this->students[] = $student; + } + } + + public function contains(Student $student) + { + foreach ($this->students as $s) + { + if ($s->getId() == $student->getId()) { + return true; + } + } + return false; + } + + public function getIterator() { + return new CachingIterator($this->students->getIterator(), true); + } +} + +$students = new StudentList(); +$students->add(new Student('01234123', 'Joe')); +$students->add(new Student('00000014', 'Bob')); +$students->add(new Student('00000014', 'Foo')); + +// The goal is to verify we can access the cached string value even if it was +// generated by a call to __toString(). To check this we need to access the +// iterator's __toString() method. +$it = $students->getIterator(); +foreach ($it as $student) { + echo $it->__toString(), "\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +01234123, Joe +00000014, Bob +===DONE=== diff --git a/ext/spl/tests/iterator_004.phpt b/ext/spl/tests/iterator_004.phpt new file mode 100644 index 0000000..e07cd32 --- /dev/null +++ b/ext/spl/tests/iterator_004.phpt @@ -0,0 +1,142 @@ +--TEST-- +SPL: SeekableIterator and string keys +--FILE-- +<?php + +class NumericArrayIterator implements Iterator +{ + protected $a; + protected $i; + + public function __construct($a) + { + echo __METHOD__ . "\n"; + $this->a = $a; + } + + public function rewind() + { + echo __METHOD__ . "\n"; + $this->i = 0; + } + + public function valid() + { + $ret = $this->i < count($this->a); + echo __METHOD__ . '(' . ($ret ? 'true' : 'false') . ")\n"; + return $ret; + } + + 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++; + } +} + +class SeekableNumericArrayIterator extends NumericArrayIterator implements SeekableIterator +{ + public function seek($index) + { + if ($index < count($this->a)) { + $this->i = $index; + } + echo __METHOD__ . '(' . $index . ")\n"; + } +} + +$a = array(1, 2, 3, 4, 5); +foreach (new LimitIterator(new NumericArrayIterator($a), 1, 3) as $v) +{ + print "$v\n"; +} + +echo "===SEEKABLE===\n"; +$a = array(1, 2, 3, 4, 5); +foreach(new LimitIterator(new SeekableNumericArrayIterator($a), 1, 3) as $v) +{ + print "$v\n"; +} + +echo "===SEEKING===\n"; +$a = array(1, 2, 3, 4, 5); +$l = new LimitIterator(new SeekableNumericArrayIterator($a)); +for($i = 1; $i < 4; $i++) +{ + $l->seek($i); + print $l->current() . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +NumericArrayIterator::__construct +NumericArrayIterator::rewind +NumericArrayIterator::valid(true) +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +3 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +4 +NumericArrayIterator::next +===SEEKABLE=== +NumericArrayIterator::__construct +NumericArrayIterator::rewind +SeekableNumericArrayIterator::seek(1) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +2 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +3 +NumericArrayIterator::next +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +4 +NumericArrayIterator::next +===SEEKING=== +NumericArrayIterator::__construct +SeekableNumericArrayIterator::seek(1) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +2 +SeekableNumericArrayIterator::seek(2) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +3 +SeekableNumericArrayIterator::seek(3) +NumericArrayIterator::valid(true) +NumericArrayIterator::current +NumericArrayIterator::key +4 +===DONE=== diff --git a/ext/spl/tests/iterator_005.phpt b/ext/spl/tests/iterator_005.phpt new file mode 100644 index 0000000..640ca9f --- /dev/null +++ b/ext/spl/tests/iterator_005.phpt @@ -0,0 +1,52 @@ +--TEST-- +SPL: IteratorIterator and ArrayIterator/Object +--FILE-- +<?php + +class ArrayIteratorEx extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + return parent::rewind(); + } +} + +$it = new ArrayIteratorEx(range(0,3)); + +foreach(new IteratorIterator($it) as $v) +{ + var_dump($v); +} + +class ArrayObjectEx extends ArrayObject +{ + function getIterator() + { + echo __METHOD__ . "\n"; + return parent::getIterator(); + } +} + +$it = new ArrayObjectEx(range(0,3)); + +foreach(new IteratorIterator($it) as $v) +{ + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +ArrayIteratorEx::rewind +int(0) +int(1) +int(2) +int(3) +ArrayObjectEx::getIterator +int(0) +int(1) +int(2) +int(3) +===DONE=== diff --git a/ext/spl/tests/iterator_006.phpt b/ext/spl/tests/iterator_006.phpt new file mode 100644 index 0000000..54da89c --- /dev/null +++ b/ext/spl/tests/iterator_006.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: IteratorIterator and SimpleXMlElement +--SKIPIF-- +<?php if (!extension_loaded('simplexml')) print "skip SimpleXML required"; ?> +--FILE-- +<?php + +$root = simplexml_load_string(b'<?xml version="1.0"?> +<root> + <child>Hello</child> + <child>World</child> +</root> +'); + +foreach (new IteratorIterator($root->child) as $child) { + echo $child."\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +Hello +World +===DONE=== diff --git a/ext/spl/tests/iterator_007.phpt b/ext/spl/tests/iterator_007.phpt new file mode 100644 index 0000000..d26c01e --- /dev/null +++ b/ext/spl/tests/iterator_007.phpt @@ -0,0 +1,166 @@ +--TEST-- +SPL: NoRewindIterator +--FILE-- +<?php + +class ArrayIteratorEx extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } +} + +class NoRewindIteratorEx extends NoRewindIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } +} + +$it = new NoRewindIteratorEx(new ArrayIteratorEx(range(0,3))); + +echo "===0===\n"; +foreach ($it->getInnerIterator() as $v) { + var_dump($v); +} + +echo "===1===\n"; +foreach ($it as $v) { + var_dump($v); +} + +$pos =0; + +$it = new NoRewindIteratorEx(new ArrayIteratorEx(range(0,3))); + +echo "===2===\n"; +foreach ($it as $v) { + var_dump($v); + if ($pos++ > 1) { + break; + } +} + +echo "===3===\n"; +foreach ($it as $v) { + var_dump($v); +} + +echo "===4===\n"; +foreach ($it as $v) { + var_dump($v); +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +===0=== +ArrayIteratorEx::rewind +ArrayIteratorEx::valid +ArrayIteratorEx::current +int(0) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +int(1) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +int(2) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +int(3) +ArrayIteratorEx::next +ArrayIteratorEx::valid +===1=== +NoRewindIteratorEx::rewind +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +===2=== +NoRewindIteratorEx::rewind +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +NoRewindIteratorEx::current +ArrayIteratorEx::current +int(0) +NoRewindIteratorEx::next +ArrayIteratorEx::next +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +NoRewindIteratorEx::current +ArrayIteratorEx::current +int(1) +NoRewindIteratorEx::next +ArrayIteratorEx::next +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +NoRewindIteratorEx::current +ArrayIteratorEx::current +int(2) +===3=== +NoRewindIteratorEx::rewind +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +NoRewindIteratorEx::current +int(2) +NoRewindIteratorEx::next +ArrayIteratorEx::next +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +NoRewindIteratorEx::current +ArrayIteratorEx::current +int(3) +NoRewindIteratorEx::next +ArrayIteratorEx::next +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +===4=== +NoRewindIteratorEx::rewind +NoRewindIteratorEx::valid +ArrayIteratorEx::valid +===DONE=== diff --git a/ext/spl/tests/iterator_008.phpt b/ext/spl/tests/iterator_008.phpt new file mode 100644 index 0000000..04f8c00 --- /dev/null +++ b/ext/spl/tests/iterator_008.phpt @@ -0,0 +1,89 @@ +--TEST-- +SPL: InfiniteIterator +--FILE-- +<?php + +class ArrayIteratorEx extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } +} + +$it = new InfiniteIterator(new ArrayIteratorEx(range(0,2))); + +$pos =0; + +foreach ($it as $v) { + var_dump($v); + if ($pos++ > 5) { + break; + } +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +ArrayIteratorEx::rewind +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(0) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(1) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(2) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::rewind +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(0) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(1) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(2) +ArrayIteratorEx::next +ArrayIteratorEx::valid +ArrayIteratorEx::rewind +ArrayIteratorEx::valid +ArrayIteratorEx::current +ArrayIteratorEx::key +int(0) +===DONE=== diff --git a/ext/spl/tests/iterator_009.phpt b/ext/spl/tests/iterator_009.phpt new file mode 100644 index 0000000..0bfe74e --- /dev/null +++ b/ext/spl/tests/iterator_009.phpt @@ -0,0 +1,45 @@ +--TEST-- +SPL: EmptyIterator +--FILE-- +<?php + +class EmptyIteratorEx extends EmptyIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } +} + +foreach (new EmptyIteratorEx() as $v) { + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +EmptyIteratorEx::rewind +EmptyIteratorEx::valid +===DONE=== diff --git a/ext/spl/tests/iterator_010.phpt b/ext/spl/tests/iterator_010.phpt new file mode 100644 index 0000000..39d1000 --- /dev/null +++ b/ext/spl/tests/iterator_010.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: EmptyIterator +--FILE-- +<?php + +echo "===EmptyIterator===\n"; + +foreach(new LimitIterator(new EmptyIterator(), 0, 3) as $key => $val) +{ + echo "$key=>$val\n"; +} + +?> +===DONE=== +<?php exit(0); +--EXPECTF-- +===EmptyIterator=== +===DONE=== diff --git a/ext/spl/tests/iterator_011.phpt b/ext/spl/tests/iterator_011.phpt new file mode 100644 index 0000000..fca159a --- /dev/null +++ b/ext/spl/tests/iterator_011.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: InfiniteIterator +--FILE-- +<?php + +echo "===EmptyIterator===\n"; + +foreach(new LimitIterator(new InfiniteIterator(new EmptyIterator()), 0, 3) as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===InfiniteIterator===\n"; + +$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D')); +$it = new InfiniteIterator($it); +$it = new LimitIterator($it, 2, 5); +foreach($it as $val=>$key) +{ + echo "$val=>$key\n"; +} + +echo "===Infinite/LimitIterator===\n"; + +$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D')); +$it = new LimitIterator($it, 1, 2); +$it = new InfiniteIterator($it); +$it = new LimitIterator($it, 2, 5); +foreach($it as $val=>$key) +{ + echo "$val=>$key\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===EmptyIterator=== +===InfiniteIterator=== +2=>C +3=>D +0=>A +1=>B +2=>C +===Infinite/LimitIterator=== +1=>B +2=>C +1=>B +2=>C +1=>B +===DONE=== diff --git a/ext/spl/tests/iterator_012.phpt b/ext/spl/tests/iterator_012.phpt new file mode 100644 index 0000000..81bc02f --- /dev/null +++ b/ext/spl/tests/iterator_012.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: NoRewindIterator +--FILE-- +<?php + +echo "===Current===\n"; + +$it = new NoRewindIterator(new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C'))); + +echo $it->key() . '=>' . $it->current() . "\n"; + +echo "===Next===\n"; + +$it->next(); + +echo "===Foreach===\n"; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===Current=== +0=>A +===Next=== +===Foreach=== +1=>B +2=>C +===DONE=== diff --git a/ext/spl/tests/iterator_013.phpt b/ext/spl/tests/iterator_013.phpt new file mode 100644 index 0000000..119631c --- /dev/null +++ b/ext/spl/tests/iterator_013.phpt @@ -0,0 +1,66 @@ +--TEST-- +SPL: AppendIterator +--FILE-- +<?php + +echo "===Empty===\n"; + +$it = new AppendIterator; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Append===\n"; + +$it->append(new ArrayIterator(array(0 => 'A', 1 => 'B'))); + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Rewind===\n"; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Append===\n"; + +$it->append(new ArrayIterator(array(2 => 'C', 3 => 'D'))); + +foreach(new NoRewindIterator($it) as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Rewind===\n"; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===Empty=== +===Append=== +0=>A +1=>B +===Rewind=== +0=>A +1=>B +===Append=== +2=>C +3=>D +===Rewind=== +0=>A +1=>B +2=>C +3=>D +===DONE=== diff --git a/ext/spl/tests/iterator_014.phpt b/ext/spl/tests/iterator_014.phpt new file mode 100644 index 0000000..119fad0 --- /dev/null +++ b/ext/spl/tests/iterator_014.phpt @@ -0,0 +1,138 @@ +--TEST-- +SPL: RecursiveIteratorIterator and beginChildren/endChildren +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . " = false\n"; + return false; + } + else + { + return true; + } + } + + function getChildren() + { + echo __METHOD__ . "\n"; + return parent::getChildren(); + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } +} + +foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d"))) as $k=>$v) +{ + echo "$k=>$v\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>a +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>ba +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +1=>bbb +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(2) +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(3) +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bcaa +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(3) +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(1) +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>ca +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +3=>d +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::valid +MyRecursiveArrayIterator::valid = false +===DONE=== diff --git a/ext/spl/tests/iterator_015.phpt b/ext/spl/tests/iterator_015.phpt new file mode 100644 index 0000000..aa30f79 --- /dev/null +++ b/ext/spl/tests/iterator_015.phpt @@ -0,0 +1,62 @@ +--TEST-- +SPL: RecursiveIteratorIterator and beginChildren/endChildren +--FILE-- +<?php + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + function rewind() + { + echo "<ul>\n"; + parent::rewind(); + } + function beginChildren() + { + echo str_repeat(' ',$this->getDepth())."<ul>\n"; + } + + function endChildren() + { + echo str_repeat(' ',$this->getDepth())."</ul>\n"; + } + function valid() + { + if (!parent::valid()) { + echo "<ul>\n"; + return false; + } + return true; + } +} + +$arr = array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d"); +$obj = new RecursiveArrayIterator($arr); +$rit = new RecursiveArrayIteratorIterator($obj); +foreach($rit as $k=>$v) +{ + echo str_repeat(' ',$rit->getDepth()+1)."$k=>$v\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +<ul> + 0=>a + <ul> + 0=>ba + <ul> + 0=>bba + 1=>bbb + </ul> + <ul> + <ul> + 0=>bcaa + </ul> + </ul> + </ul> + <ul> + 0=>ca + </ul> + 3=>d +<ul> +===DONE=== diff --git a/ext/spl/tests/iterator_016.phpt b/ext/spl/tests/iterator_016.phpt new file mode 100644 index 0000000..f231c6e --- /dev/null +++ b/ext/spl/tests/iterator_016.phpt @@ -0,0 +1,76 @@ +--TEST-- +SPL: RecursiveIteratorIterator and beginChildren/endChildren +--FILE-- +<?php + +class Menu extends ArrayObject +{ + function getIterator() + { + echo __METHOD__ . "\n"; + return new RecursiveArrayIterator($this); + } +} + +class MenuOutput extends RecursiveIteratorIterator +{ + function __construct(Menu $it) + { + parent::__construct($it); + } + function rewind() + { + echo "<ul>\n"; + parent::rewind(); + } + function beginChildren() + { + echo str_repeat(' ',$this->getDepth())."<ul>\n"; + } + + function endChildren() + { + echo str_repeat(' ',$this->getDepth())."</ul>\n"; + } + function valid() + { + if (!parent::valid()) { + echo "<ul>\n"; + return false; + } + return true; + } +} + +$arr = array("a", array("ba", array("bba", "bbb"), array(array("bcaa"))), array("ca"), "d"); +$obj = new Menu($arr); +$rit = new MenuOutput($obj); +foreach($rit as $k=>$v) +{ + echo str_repeat(' ',$rit->getDepth()+1)."$k=>$v\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Menu::getIterator +<ul> + 0=>a + <ul> + 0=>ba + <ul> + 0=>bba + 1=>bbb + </ul> + <ul> + <ul> + 0=>bcaa + </ul> + </ul> + </ul> + <ul> + 0=>ca + </ul> + 3=>d +<ul> +===DONE=== diff --git a/ext/spl/tests/iterator_017.phpt b/ext/spl/tests/iterator_017.phpt new file mode 100644 index 0000000..39d1000 --- /dev/null +++ b/ext/spl/tests/iterator_017.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: EmptyIterator +--FILE-- +<?php + +echo "===EmptyIterator===\n"; + +foreach(new LimitIterator(new EmptyIterator(), 0, 3) as $key => $val) +{ + echo "$key=>$val\n"; +} + +?> +===DONE=== +<?php exit(0); +--EXPECTF-- +===EmptyIterator=== +===DONE=== diff --git a/ext/spl/tests/iterator_018.phpt b/ext/spl/tests/iterator_018.phpt new file mode 100644 index 0000000..9c234bb --- /dev/null +++ b/ext/spl/tests/iterator_018.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: InfiniteIterator +--FILE-- +<?php + +echo "===EmptyIterator===\n"; + +foreach(new LimitIterator(new InfiniteIterator(new EmptyIterator()), 0, 3) as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===InfiniteIterator===\n"; + +$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D')); +$it = new InfiniteIterator($it); +$it = new LimitIterator($it, 2, 5); +foreach($it as $val=>$key) +{ + echo "$val=>$key\n"; +} + +echo "===Infinite/LimitIterator===\n"; + +$it = new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D')); +$it = new LimitIterator($it, 1, 2); +$it = new InfiniteIterator($it); +$it = new LimitIterator($it, 2, 5); +foreach($it as $val=>$key) +{ + echo "$val=>$key\n"; +} + +?> +===DONE=== +<?php exit(0); +--EXPECTF-- +===EmptyIterator=== +===InfiniteIterator=== +2=>C +3=>D +0=>A +1=>B +2=>C +===Infinite/LimitIterator=== +1=>B +2=>C +1=>B +2=>C +1=>B +===DONE=== diff --git a/ext/spl/tests/iterator_019.phpt b/ext/spl/tests/iterator_019.phpt new file mode 100644 index 0000000..81bc02f --- /dev/null +++ b/ext/spl/tests/iterator_019.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: NoRewindIterator +--FILE-- +<?php + +echo "===Current===\n"; + +$it = new NoRewindIterator(new ArrayIterator(array(0 => 'A', 1 => 'B', 2 => 'C'))); + +echo $it->key() . '=>' . $it->current() . "\n"; + +echo "===Next===\n"; + +$it->next(); + +echo "===Foreach===\n"; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===Current=== +0=>A +===Next=== +===Foreach=== +1=>B +2=>C +===DONE=== diff --git a/ext/spl/tests/iterator_020.phpt b/ext/spl/tests/iterator_020.phpt new file mode 100644 index 0000000..119631c --- /dev/null +++ b/ext/spl/tests/iterator_020.phpt @@ -0,0 +1,66 @@ +--TEST-- +SPL: AppendIterator +--FILE-- +<?php + +echo "===Empty===\n"; + +$it = new AppendIterator; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Append===\n"; + +$it->append(new ArrayIterator(array(0 => 'A', 1 => 'B'))); + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Rewind===\n"; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Append===\n"; + +$it->append(new ArrayIterator(array(2 => 'C', 3 => 'D'))); + +foreach(new NoRewindIterator($it) as $key=>$val) +{ + echo "$key=>$val\n"; +} + +echo "===Rewind===\n"; + +foreach($it as $key=>$val) +{ + echo "$key=>$val\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===Empty=== +===Append=== +0=>A +1=>B +===Rewind=== +0=>A +1=>B +===Append=== +2=>C +3=>D +===Rewind=== +0=>A +1=>B +2=>C +3=>D +===DONE=== diff --git a/ext/spl/tests/iterator_021.phpt b/ext/spl/tests/iterator_021.phpt new file mode 100644 index 0000000..4f2395a --- /dev/null +++ b/ext/spl/tests/iterator_021.phpt @@ -0,0 +1,180 @@ +--TEST-- +SPL: RecursiveIteratorIterator and hasChildren +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . " = false\n"; + return false; + } + else + { + return true; + } + } + + function getChildren() + { + echo __METHOD__ . "\n"; + return parent::getChildren(); + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + private $max_depth; + private $over = 0; + private $skip = false; + + function __construct($it, $max_depth) + { + $this->max_depth = $max_depth; + parent::__construct($it); + } + + function rewind() + { + echo __METHOD__ . "\n"; + $this->skip = false; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + if ($this->skip) + { + $this->skip = false; + $this->next(); + } + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } + + function callHasChildren() + { + $this->skip = false; + $has = parent::callHasChildren(); + $res = $this->getDepth() < $this->max_depth && $has; + echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n"; + if ($has && !$res) + { + $this->over++; + if ($this->over == 2) { + $this->skip = true; + } + } + return $res; + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } +} + +foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) +{ + if (is_array($v)) $v = join('',$v); + echo "$k=>$v\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>a +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>ba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +1=>bbb +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bcaa +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +MyRecursiveArrayIterator::getChildren +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>ca +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +3=>d +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::valid +MyRecursiveArrayIterator::valid = false +===DONE=== diff --git a/ext/spl/tests/iterator_022.phpt b/ext/spl/tests/iterator_022.phpt new file mode 100644 index 0000000..8d05531 --- /dev/null +++ b/ext/spl/tests/iterator_022.phpt @@ -0,0 +1,186 @@ +--TEST-- +SPL: RecursiveIteratorIterator and callHasChildren/callGetChildren +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function getChildren() + { + echo __METHOD__ . "\n"; + return $this->current(); + } + + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . " = false\n"; + return false; + } + else + { + return true; + } + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + private $max_depth; + private $over = 0; + private $skip = false; + + function __construct($it, $max_depth) + { + $this->max_depth = $max_depth; + parent::__construct($it); + } + + function rewind() + { + echo __METHOD__ . "\n"; + $this->skip = false; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + if ($this->skip) + { + $this->skip = false; + $this->next(); + } + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } + + function callHasChildren() + { + $this->skip = false; + $has = parent::callHasChildren(); + $res = $this->getDepth() < $this->max_depth && $has; + echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n"; + if ($has && !$res) + { + $this->over++; + if ($this->over == 2) { + $this->skip = true; + } + } + return $res; + } + + function callGetChildren() + { + if ($this->over == 2) + { + echo __METHOD__ . "(skip)\n"; + return NULL; + } + echo __METHOD__ . "(ok:{$this->over})\n"; + return new MyRecursiveArrayIterator($this->current()); + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } +} + +try +{ + foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) + { + if (is_array($v)) $v = join('',$v); + echo "$k=>$v\n"; + } +} +catch(UnexpectedValueException $e) +{ + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>a +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(ok:0) +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>ba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(ok:0) +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +1=>bbb +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(ok:0) +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bcaa +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(skip) +Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator +===DONE=== diff --git a/ext/spl/tests/iterator_023.phpt b/ext/spl/tests/iterator_023.phpt new file mode 100644 index 0000000..1b6b468 --- /dev/null +++ b/ext/spl/tests/iterator_023.phpt @@ -0,0 +1,193 @@ +--TEST-- +SPL: RecursiveIteratorIterator and catch getChildren +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function getChildren() + { + echo __METHOD__ . "\n"; + return $this->current(); + } + + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . " = false\n"; + return false; + } + else + { + return true; + } + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + private $max_depth; + private $over = 0; + private $skip = false; + + function __construct($it, $max_depth) + { + $this->max_depth = $max_depth; + parent::__construct($it, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD); + } + + function rewind() + { + echo __METHOD__ . "\n"; + $this->skip = false; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + if ($this->skip) + { + $this->skip = false; + $this->next(); + } + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "\n"; + parent::next(); + } + + function callHasChildren() + { + $this->skip = false; + $has = parent::callHasChildren(); + $res = $this->getDepth() < $this->max_depth && $has; + echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n"; + if ($has && !$res) + { + $this->over++; + if ($this->over == 2) { + $this->skip = true; + } + } + return $res; + } + + function callGetChildren() + { + if ($this->over == 2) + { + echo __METHOD__ . "(throw)\n"; + throw new Exception("Thrown in callGetChildren()"); + } + echo __METHOD__ . "(ok:{$this->over})\n"; + return new MyRecursiveArrayIterator($this->current()); + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + } +} + +try +{ + foreach(new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2) as $k=>$v) + { + if (is_array($v)) $v = join('',$v); + echo "$k=>$v\n"; + } +} +catch(UnexpectedValueException $e) +{ + echo $e->getMessage() . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>a +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(ok:0) +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>ba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(ok:0) +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bba +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +1=>bbb +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(ok:0) +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +0=>bcaa +RecursiveArrayIteratorIterator::next +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(2) +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +RecursiveArrayIteratorIterator::callGetChildren(throw) +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::current +RecursiveArrayIteratorIterator::key +3=>d +RecursiveArrayIteratorIterator::next +MyRecursiveArrayIterator::valid = false +RecursiveArrayIteratorIterator::valid +MyRecursiveArrayIterator::valid = false +===DONE=== diff --git a/ext/spl/tests/iterator_024.phpt b/ext/spl/tests/iterator_024.phpt new file mode 100644 index 0000000..0c7dea1 --- /dev/null +++ b/ext/spl/tests/iterator_024.phpt @@ -0,0 +1,49 @@ +--TEST-- +SPL: RecursiveIteratorIterator with custom iterator class +--FILE-- +<?php + +$ar = array(1, 2, array(31, 32, array(331)), 4); + +foreach(new RecursiveIteratorIterator(new ArrayObject($ar, 0, "RecursiveArrayIterator")) as $v) echo "$v\n"; + +$it = new ArrayObject($ar); +var_dump($it->getIteratorClass()); + +try +{ + foreach(new RecursiveIteratorIterator(new ArrayObject($ar)) as $v) echo "$v\n"; +} +catch (InvalidArgumentException $e) +{ + echo $e->getMessage() . "\n"; +} + +echo "===MANUAL===\n"; + +$it->setIteratorClass("RecursiveArrayIterator"); +var_dump($it->getIteratorClass()); +foreach(new RecursiveIteratorIterator($it) as $v) echo "$v\n"; + + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1 +2 +31 +32 +331 +4 +string(13) "ArrayIterator" +An instance of RecursiveIterator or IteratorAggregate creating it is required +===MANUAL=== +string(22) "RecursiveArrayIterator" +1 +2 +31 +32 +331 +4 +===DONE=== diff --git a/ext/spl/tests/iterator_025.phpt b/ext/spl/tests/iterator_025.phpt new file mode 100644 index 0000000..e582b1f --- /dev/null +++ b/ext/spl/tests/iterator_025.phpt @@ -0,0 +1,92 @@ +--TEST-- +SPL: RecursiveIteratorIterator and begin/endIteration() +--FILE-- +<?php + +class MyRecursiveIteratorIterator extends RecursiveIteratorIterator +{ + function beginIteration() + { + echo __METHOD__ . "()\n"; + } + + function endIteration() + { + echo __METHOD__ . "()\n"; + } +} + +$ar = array(1, 2, array(31, 32, array(331)), 4); + +$it = new MyRecursiveIteratorIterator(new ArrayObject($ar, 0, "RecursiveArrayIterator")); + +foreach($it as $v) echo "$v\n"; + +echo "===MORE===\n"; + +foreach($it as $v) echo "$v\n"; + +echo "===MORE===\n"; + +$it->rewind(); +foreach($it as $v) echo "$v\n"; +var_dump($it->valid()); + +echo "===MANUAL===\n"; + +$it->rewind(); +while($it->valid()) +{ + echo $it->current() . "\n"; + $it->next(); + break; +} +$it->rewind(); +while($it->valid()) +{ + echo $it->current() . "\n"; + $it->next(); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +MyRecursiveIteratorIterator::beginIteration() +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +===MORE=== +MyRecursiveIteratorIterator::beginIteration() +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +===MORE=== +MyRecursiveIteratorIterator::beginIteration() +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +bool(false) +===MANUAL=== +MyRecursiveIteratorIterator::beginIteration() +1 +1 +2 +31 +32 +331 +4 +MyRecursiveIteratorIterator::endIteration() +===DONE=== diff --git a/ext/spl/tests/iterator_026.phpt b/ext/spl/tests/iterator_026.phpt new file mode 100644 index 0000000..8eb77a7 --- /dev/null +++ b/ext/spl/tests/iterator_026.phpt @@ -0,0 +1,38 @@ +--TEST-- +SPL: CachingIterator::hasNext() +--FILE-- +<?php + +$ar = array(1, 2, array(31, 32, array(331)), 4); + +$it = new RecursiveArrayIterator($ar); +$it = new RecursiveCachingIterator($it); +$it = new RecursiveIteratorIterator($it); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; + echo "hasNext: " . ($it->getInnerIterator()->hasNext() ? "yes" : "no") . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +0=>1 +hasNext: yes +1=>2 +hasNext: yes + +Notice: Array to string conversion in %siterator_026.php on line %d +0=>31 +hasNext: yes +1=>32 +hasNext: yes + +Notice: Array to string conversion in %siterator_026.php on line %d +0=>331 +hasNext: no +3=>4 +hasNext: no +===DONE=== diff --git a/ext/spl/tests/iterator_027.phpt b/ext/spl/tests/iterator_027.phpt new file mode 100644 index 0000000..fd9ba70 --- /dev/null +++ b/ext/spl/tests/iterator_027.phpt @@ -0,0 +1,83 @@ +--TEST-- +SPL: CachingIterator::FULL_CACHE +--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_028.phpt b/ext/spl/tests/iterator_028.phpt new file mode 100644 index 0000000..8b53b21 --- /dev/null +++ b/ext/spl/tests/iterator_028.phpt @@ -0,0 +1,112 @@ +--TEST-- +SPL: RecursiveIteratorIterator and setMaxDepth() +--FILE-- +<?php + +$ar = array(1, 2, array(31, 32, array(331, array(3321, array(33221)))), 4); + +$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($ar)); + +echo "===?===\n"; +var_dump($it->getMaxDepth()); +foreach($it as $v) echo $it->getDepth() . ": $v\n"; + +echo "===2===\n"; +$it->setMaxDepth(2); +var_dump($it->getMaxDepth()); +foreach($it as $v) echo $it->getDepth() . ": $v\n"; + +echo "===X===\n"; +$it->setMaxDepth(); +var_dump($it->getMaxDepth()); +foreach($it as $v) echo $it->getDepth() . ": $v\n"; + +echo "===3===\n"; +$it->setMaxDepth(3); +var_dump($it->getMaxDepth()); +foreach($it as $v) echo $it->getDepth() . ": $v\n"; + +echo "===5===\n"; +$it->setMaxDepth(5); +var_dump($it->getMaxDepth()); +foreach($it as $v) echo $it->getDepth() . ": $v\n"; + +echo "===0===\n"; +$it->setMaxDepth(0); +var_dump($it->getMaxDepth()); +foreach($it as $v) echo $it->getDepth() . ": $v\n"; + +echo "===-1===\n"; +$it->setMaxDepth(-1); +var_dump($it->getMaxDepth()); +try +{ + $it->setMaxDepth(4); + $it->setMaxDepth(-2); +} +catch(Exception $e) +{ + var_dump($e->getMessage()); +} +var_dump($it->getMaxDepth()); +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +===?=== +bool(false) +0: 1 +0: 2 +1: 31 +1: 32 +2: 331 +3: 3321 +4: 33221 +0: 4 +===2=== +int(2) +0: 1 +0: 2 +1: 31 +1: 32 +2: 331 +0: 4 +===X=== +bool(false) +0: 1 +0: 2 +1: 31 +1: 32 +2: 331 +3: 3321 +4: 33221 +0: 4 +===3=== +int(3) +0: 1 +0: 2 +1: 31 +1: 32 +2: 331 +3: 3321 +0: 4 +===5=== +int(5) +0: 1 +0: 2 +1: 31 +1: 32 +2: 331 +3: 3321 +4: 33221 +0: 4 +===0=== +int(0) +0: 1 +0: 2 +0: 4 +===-1=== +bool(false) +string(33) "Parameter max_depth must be >= -1" +int(4) +===DONE=== diff --git a/ext/spl/tests/iterator_029.phpt b/ext/spl/tests/iterator_029.phpt new file mode 100644 index 0000000..e5bfde0 --- /dev/null +++ b/ext/spl/tests/iterator_029.phpt @@ -0,0 +1,38 @@ +--TEST-- +SPL: RegexIterator +--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_030.phpt b/ext/spl/tests/iterator_030.phpt new file mode 100644 index 0000000..29d147f --- /dev/null +++ b/ext/spl/tests/iterator_030.phpt @@ -0,0 +1,44 @@ +--TEST-- +SPL: EmptyIterator access +--FILE-- +<?php + +$it = new EmptyIterator; + +var_dump($it->valid()); +$it->rewind(); +var_dump($it->valid()); +$it->next(); +var_dump($it->valid()); + +try +{ + var_dump($it->key()); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +try +{ + var_dump($it->current()); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +var_dump($it->valid()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +bool(false) +bool(false) +bool(false) +Accessing the key of an EmptyIterator +Accessing the value of an EmptyIterator +bool(false) +===DONE=== diff --git a/ext/spl/tests/iterator_031.phpt b/ext/spl/tests/iterator_031.phpt new file mode 100644 index 0000000..40342f4 --- /dev/null +++ b/ext/spl/tests/iterator_031.phpt @@ -0,0 +1,116 @@ +--TEST-- +SPL: AppendIterator::append() rewinds when neccessary +--FILE-- +<?php + +class MyArrayIterator extends ArrayIterator +{ + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } +} + +$it = new MyArrayIterator(array(1,2)); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; +} + +class MyAppendIterator extends AppendIterator +{ + function __construct() + { + echo __METHOD__ . "\n"; + } + + function rewind() + { + echo __METHOD__ . "\n"; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "\n"; + return parent::valid(); + } + + function append(Iterator $what) + { + echo __METHOD__ . "\n"; + parent::append($what); + } + + function parent__construct() + { + parent::__construct(); + } +} + +$ap = new MyAppendIterator; + +try +{ + $ap->append($it); +} +catch(LogicException $e) +{ + echo $e->getMessage() . "\n"; +} + +$ap->parent__construct(); + +try +{ + $ap->parent__construct($it); +} +catch(BadMethodCallException $e) +{ + echo $e->getMessage() . "\n"; +} + +$ap->append($it); +$ap->append($it); +$ap->append($it); + +foreach($ap as $k=>$v) +{ + echo "$k=>$v\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +MyArrayIterator::rewind +0=>1 +1=>2 +MyAppendIterator::__construct +MyAppendIterator::append +The object is in an invalid state as the parent constructor was not called +AppendIterator::getIterator() must be called exactly once per instance +MyAppendIterator::append +MyArrayIterator::rewind +MyAppendIterator::append +MyAppendIterator::append +MyAppendIterator::rewind +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyArrayIterator::rewind +MyAppendIterator::valid +0=>1 +MyAppendIterator::valid +1=>2 +MyAppendIterator::valid +===DONE=== diff --git a/ext/spl/tests/iterator_032.phpt b/ext/spl/tests/iterator_032.phpt new file mode 100644 index 0000000..84eb8e6 --- /dev/null +++ b/ext/spl/tests/iterator_032.phpt @@ -0,0 +1,50 @@ +--TEST-- +SPL: LimitIterator::getPosition() +--FILE-- +<?php + +$it = new LimitIterator(new ArrayIterator(array(1,2,3,4)), 1, 2); + +foreach($it as $k=>$v) +{ + echo "$k=>$v\n"; + var_dump($it->getPosition()); +} + +try +{ + $it->seek(0); +} +catch(OutOfBoundsException $e) +{ + echo $e->getMessage() . "\n"; +} + +$it->seek(2); +var_dump($it->current()); + +try +{ + $it->seek(3); +} +catch(OutOfBoundsException $e) +{ + echo $e->getMessage() . "\n"; +} + +$it->next(); +var_dump($it->valid()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +1=>2 +int(1) +2=>3 +int(2) +Cannot seek to 0 which is below the offset 1 +int(3) +Cannot seek to 3 which is behind offset 1 plus count 2 +bool(false) +===DONE=== diff --git a/ext/spl/tests/iterator_033.phpt b/ext/spl/tests/iterator_033.phpt new file mode 100644 index 0000000..548759c --- /dev/null +++ b/ext/spl/tests/iterator_033.phpt @@ -0,0 +1,44 @@ +--TEST-- +SPL: ParentIterator +--FILE-- +<?php + +$it = new ParentIterator(new RecursiveArrayIterator(array(1,array(21,22, array(231)),3))); + +foreach(new RecursiveIteratorIterator($it) as $k=>$v) +{ + var_dump($k); + var_dump($v); +} + +echo "==SECOND==\n"; + +foreach(new RecursiveIteratorIterator($it, 1) as $k=>$v) +{ + var_dump($k); + var_dump($v); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +==SECOND== +int(1) +array(3) { + [0]=> + int(21) + [1]=> + int(22) + [2]=> + array(1) { + [0]=> + int(231) + } +} +int(2) +array(1) { + [0]=> + int(231) +} +===DONE=== diff --git a/ext/spl/tests/iterator_034.phpt b/ext/spl/tests/iterator_034.phpt new file mode 100644 index 0000000..3329e74 --- /dev/null +++ b/ext/spl/tests/iterator_034.phpt @@ -0,0 +1,188 @@ +--TEST-- +SPL: RecursiveIteratorIterator and break deep +--FILE-- +<?php + +class MyRecursiveArrayIterator extends RecursiveArrayIterator +{ + function valid() + { + if (!parent::valid()) + { + echo __METHOD__ . "() = false\n"; + return false; + } + else + { + return true; + } + } + + function getChildren() + { + echo __METHOD__ . "()\n"; + return parent::getChildren(); + } + + function rewind() + { + echo __METHOD__ . "()\n"; + parent::rewind(); + } +} + +class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator +{ + private $max_depth; + private $over = 0; + + function __construct($it, $max_depth) + { + $this->max_depth = $max_depth; + parent::__construct($it); + } + + function rewind() + { + echo __METHOD__ . "() - BEGIN\n"; + parent::rewind(); + echo __METHOD__ . "() - DONE\n"; + } + + function valid() + { + echo __METHOD__ . "()\n"; + return parent::valid(); + } + + function current() + { + echo __METHOD__ . "()\n"; + return parent::current(); + } + + function key() + { + echo __METHOD__ . "()\n"; + return parent::key(); + } + + function next() + { + echo __METHOD__ . "()\n"; + parent::next(); + } + + function callHasChildren() + { + $has = parent::callHasChildren(); + $res = $this->getDepth() < $this->max_depth && $has; + echo __METHOD__ . "(".$this->getDepth().") = ".($res?"yes":"no")."/".($has?"yes":"no")."\n"; + return $res; + } + + function beginChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + parent::beginChildren(); + } + + function endChildren() + { + echo __METHOD__ . "(".$this->getDepth().")\n"; + parent::endChildren(); + } +} + +$p = 0; +$it = new RecursiveArrayIteratorIterator(new MyRecursiveArrayIterator(array("a", array("ba", array("bba", "bbb"), array(array("bcaa"), array("bcba"))), array("ca"), "d")), 2); +foreach($it as $k=>$v) +{ + if (is_array($v)) $v = join('',$v); + echo "$k=>$v\n"; + if ($p++ == 5) + { + echo "===BREAK===\n"; + break; + } +} + +echo "===FOREND===\n"; + +$it->rewind(); + +echo "===CHECK===\n"; + +var_dump($it->valid()); +var_dump($it->current() == "a"); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +RecursiveArrayIteratorIterator::rewind() - BEGIN +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::rewind() - DONE +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>a +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(0) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(1) +RecursiveArrayIteratorIterator::callHasChildren(1) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>ba +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>bba +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(2) = no/no +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +1=>bbb +RecursiveArrayIteratorIterator::next() +MyRecursiveArrayIterator::valid() = false +RecursiveArrayIteratorIterator::endChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(1) = yes/yes +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::beginChildren(2) +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +0=>bcaa +RecursiveArrayIteratorIterator::next() +RecursiveArrayIteratorIterator::callHasChildren(2) = no/yes +RecursiveArrayIteratorIterator::valid() +RecursiveArrayIteratorIterator::current() +RecursiveArrayIteratorIterator::key() +1=>bcba +===BREAK=== +===FOREND=== +RecursiveArrayIteratorIterator::rewind() - BEGIN +RecursiveArrayIteratorIterator::endChildren(1) +RecursiveArrayIteratorIterator::endChildren(0) +MyRecursiveArrayIterator::rewind() +RecursiveArrayIteratorIterator::callHasChildren(0) = no/no +RecursiveArrayIteratorIterator::rewind() - DONE +===CHECK=== +RecursiveArrayIteratorIterator::valid() +bool(true) +RecursiveArrayIteratorIterator::current() +bool(true) +===DONE=== diff --git a/ext/spl/tests/iterator_035.phpt b/ext/spl/tests/iterator_035.phpt new file mode 100644 index 0000000..9ce098b --- /dev/null +++ b/ext/spl/tests/iterator_035.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: ArrayIterator and values assigned by reference +--FILE-- +<?php + +$tmp = 1; + +$a = new ArrayIterator(); +$a[] = $tmp; +$a[] = &$tmp; + +echo "Done\n"; +?> +--EXPECTF-- +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 100644 index 0000000..9a9e66b --- /dev/null +++ b/ext/spl/tests/iterator_036.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: CachingIterator and __toString and flags = 0 +--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 100644 index 0000000..2aa61bb --- /dev/null +++ b/ext/spl/tests/iterator_037.phpt @@ -0,0 +1,131 @@ +--TEST-- +SPL: CachingIterator and __toString +--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 100644 index 0000000..9b890e2 --- /dev/null +++ b/ext/spl/tests/iterator_038.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: RoRewindIterator and string keys +--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 100644 index 0000000..17c9bc1 --- /dev/null +++ b/ext/spl/tests/iterator_039.phpt @@ -0,0 +1,121 @@ +--TEST-- +SPL: LimitIterator and backward seeking +--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 100644 index 0000000..ae00c81 --- /dev/null +++ b/ext/spl/tests/iterator_040.phpt @@ -0,0 +1,47 @@ +--TEST-- +SPL: RecursiveFilterIterator +--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 100644 index 0000000..e00ac6b --- /dev/null +++ b/ext/spl/tests/iterator_041.phpt @@ -0,0 +1,117 @@ +--TEST-- +SPL: iterator_to_array() and exceptions +--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 100644 index 0000000..ec999a5 --- /dev/null +++ b/ext/spl/tests/iterator_041a.phpt @@ -0,0 +1,107 @@ +--TEST-- +SPL: iterator_to_array() and exceptions from destruct +--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 100644 index 0000000..e7ea8b8 --- /dev/null +++ b/ext/spl/tests/iterator_041b.phpt @@ -0,0 +1,123 @@ +--TEST-- +SPL: iterator_to_array() and exceptions from delayed destruct +--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++; + } + try { + $e = null; + } catch (Exception $e) { + } + } + } +} + +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() +State 7: __destruct() +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() +State 7: __destruct() +int(2) +===DONE=== diff --git a/ext/spl/tests/iterator_042.phpt b/ext/spl/tests/iterator_042.phpt new file mode 100644 index 0000000..95fea2f --- /dev/null +++ b/ext/spl/tests/iterator_042.phpt @@ -0,0 +1,123 @@ +--TEST-- +SPL: AppendIterator and its ArrayIterator +--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 (1) { + %s"storage"%s"ArrayIterator":private]=> + array(2) { + [0]=> + object(ArrayIterator)#%d (1) { + %s"storage"%s"ArrayIterator":private]=> + array(1) { + [0]=> + int(1) + } + } + [1]=> + object(ArrayIterator)#%d (1) { + %s"storage"%s"ArrayIterator":private]=> + array(2) { + [0]=> + int(21) + [1]=> + int(22) + } + } + } +} +object(ArrayIterator)#%d (1) { + %s"storage"%s"ArrayIterator":private]=> + array(3) { + [0]=> + object(ArrayIterator)#%d (1) { + %s"storage"%s"ArrayIterator":private]=> + array(1) { + [0]=> + int(1) + } + } + [1]=> + object(ArrayIterator)#%d (1) { + %s"storage"%s"ArrayIterator":private]=> + array(2) { + [0]=> + int(21) + [1]=> + int(22) + } + } + [2]=> + object(ArrayIterator)#5 (1) { + %s"storage"%s"ArrayIterator":private]=> + array(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 100644 index 0000000..301a593 --- /dev/null +++ b/ext/spl/tests/iterator_043.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: RecursiveCachingIterator and uninitialized getChildren() +--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 100644 index 0000000..1271cca --- /dev/null +++ b/ext/spl/tests/iterator_044.phpt @@ -0,0 +1,165 @@ +--TEST-- +SPL: CachingIterator and offsetGet/Exists using flag FULL_CACHE +--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) +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) + +Warning: CachingIterator::offsetExists() expects exactly 1 parameter, 0 given in %siterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects exactly 1 parameter, 0 given in %siterator_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 100644 index 0000000..d76b2d9 --- /dev/null +++ b/ext/spl/tests/iterator_045.phpt @@ -0,0 +1,169 @@ +--TEST-- +SPL: CachingIterator and offsetSet/Unset, getCache using flag FULL_CACHE +--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 100644 index 0000000..f57415a --- /dev/null +++ b/ext/spl/tests/iterator_046.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: CachingIterator and __toString using bypassed string keys +--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 100644 index 0000000..548f486 --- /dev/null +++ b/ext/spl/tests/iterator_047.phpt @@ -0,0 +1,125 @@ +--TEST-- +SPL: RecursiveCachingIterator and exception in has/getChildren +--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() + +Notice: Array to string conversion in %siterator_047.php on line %d +MyRecursiveArrayIterator::hasChildren() +int(0) +int(10) +MyRecursiveArrayIterator::hasChildren() +int(2) +int(2) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() + +Notice: Array to string conversion in %siterator_047.php on line %d +MyRecursiveArrayIterator::hasChildren() +int(0) +int(30) +MyRecursiveArrayIterator::hasChildren() +int(4) +int(4) +===1=== +MyRecursiveArrayIterator::hasChildren() +Exception: State 1: MyRecursiveArrayIterator::hasChildren() in %s on line %d +===2=== +MyRecursiveArrayIterator::hasChildren() +int(0) +int(0) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() +Exception: State 2: MyRecursiveArrayIterator::getChildren() in %s on line %d +===3=== +MyRecursiveArrayIterator::hasChildren() +int(0) +int(0) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() + +Notice: Array to string conversion in %siterator_047.php on line %d +MyRecursiveArrayIterator::hasChildren() +int(0) +int(10) +MyRecursiveArrayIterator::hasChildren() +int(2) +int(2) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() + +Notice: Array to string conversion in %siterator_047.php on line %d +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 100644 index 0000000..bad4e78 --- /dev/null +++ b/ext/spl/tests/iterator_048.phpt @@ -0,0 +1,36 @@ +--TEST-- +SPL: RecursiveRegexIterator and exception in has/getChildren +--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 100644 index 0000000..b9ab2c3 --- /dev/null +++ b/ext/spl/tests/iterator_049.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: ArrayIterator with NULL key +--FILE-- +<?php + +$ar = new ArrayIterator(array(NULL=>NULL)); +@var_dump($ar); +var_dump($ar->getArrayCopy()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(ArrayIterator)#%d (1) { + ["storage":"ArrayIterator":private]=> + array(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 100644 index 0000000..03c7350 --- /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 100644 index 0000000..fed4a3b --- /dev/null +++ b/ext/spl/tests/iterator_050.phpt @@ -0,0 +1,98 @@ +--TEST-- +SPL: RegexIterator::GET_MATCH +--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]=> + %s(3) "1,2" + [1]=> + %s(1) "1" + [2]=> + %s(1) "2" +} +int(2) +array(3) { + [0]=> + %s(3) "1,2" + [1]=> + %s(1) "1" + [2]=> + %s(1) "2" +} + +Notice: Array to string conversion in %siterator_050.php on line %d +int(0) +array(2) { + [0]=> + %s(1) "1" + [1]=> + %s(1) "1" +} +int(1) +array(2) { + [0]=> + %s(1) "1" + [1]=> + %s(1) "1" +} +int(2) +array(2) { + [0]=> + %s(1) "1" + [1]=> + %s(1) "1" +} + +Notice: Array to string conversion in %siterator_050.php on line %d +object(ArrayIterator)#%d (1) { + %s"storage"%s"ArrayIterator":private]=> + array(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 100644 index 0000000..2d198db --- /dev/null +++ b/ext/spl/tests/iterator_051.phpt @@ -0,0 +1,96 @@ +--TEST-- +SPL: RegexIterator::GET_MATCH, USE_KEY +--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 (1) { + ["storage":"ArrayIterator":private]=> + array(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 100644 index 0000000..c68bd52 --- /dev/null +++ b/ext/spl/tests/iterator_052.phpt @@ -0,0 +1,319 @@ +--TEST-- +SPL: RegexIterator::ALL_MATCHES +--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) { + } +} + +Notice: Array to string conversion in %siterator_052.php on line %d +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) { + } +} + +Notice: Array to string conversion in %siterator_052.php on line %d +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 (1) { + ["storage":"ArrayIterator":private]=> + array(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 100644 index 0000000..5d9c740 --- /dev/null +++ b/ext/spl/tests/iterator_053.phpt @@ -0,0 +1,315 @@ +--TEST-- +SPL: RegexIterator::ALL_MATCHES +--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 (1) { + ["storage":"ArrayIterator":private]=> + array(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 100644 index 0000000..1f1cd58 --- /dev/null +++ b/ext/spl/tests/iterator_054.phpt @@ -0,0 +1,87 @@ +--TEST-- +SPL: RegexIterator::SPLIT +--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" +} + +Notice: Array to string conversion in %siterator_054.php on line %d +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 (1) { + ["storage":"ArrayIterator":private]=> + array(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 100644 index 0000000..dec68a4 --- /dev/null +++ b/ext/spl/tests/iterator_055.phpt @@ -0,0 +1,62 @@ +--TEST-- +SPL: RegexIterator::SPLIT, USE_KEY +--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 (1) { + ["storage":"ArrayIterator":private]=> + array(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_056.phpt b/ext/spl/tests/iterator_056.phpt new file mode 100644 index 0000000..4b0e75a --- /dev/null +++ b/ext/spl/tests/iterator_056.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: FilterIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myFilterIterator extends FilterIterator { + function accept() { + + } +} +try { + $it = new myFilterIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_057.phpt b/ext/spl/tests/iterator_057.phpt new file mode 100644 index 0000000..602c125 --- /dev/null +++ b/ext/spl/tests/iterator_057.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: ArrayIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +/** + * From Docs: Construct a new array iterator from anything that has a hash table. + * NULL, NOTHING is not a hash table ;) + */ +class myArrayIterator extends ArrayIterator { +} +try { + $it = new myArrayIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +echo 'no Exception thrown' +?> +--EXPECT-- +no Exception thrown diff --git a/ext/spl/tests/iterator_058.phpt b/ext/spl/tests/iterator_058.phpt new file mode 100644 index 0000000..3f65ecb --- /dev/null +++ b/ext/spl/tests/iterator_058.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: Iterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myIterator implements Iterator { + + function current() {} + function next() {} + function key() {} + function valid() {} + function rewind() {} + +} +try { + $it = new myIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +echo 'no Exception thrown'; +?> +--EXPECT-- +no Exception thrown diff --git a/ext/spl/tests/iterator_059.phpt b/ext/spl/tests/iterator_059.phpt new file mode 100644 index 0000000..8c579ae --- /dev/null +++ b/ext/spl/tests/iterator_059.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: CachingIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myCachingIterator extends CachingIterator { + +} +try { + $it = new myCachingIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_060.phpt b/ext/spl/tests/iterator_060.phpt new file mode 100644 index 0000000..0c3b6c2 --- /dev/null +++ b/ext/spl/tests/iterator_060.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: RecursiveCachingIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myRecursiveCachingIterator extends RecursiveCachingIterator { + +} +try { + $it = new myRecursiveCachingIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_061.phpt b/ext/spl/tests/iterator_061.phpt new file mode 100644 index 0000000..472f8da --- /dev/null +++ b/ext/spl/tests/iterator_061.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: ParentIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myParentIterator extends ParentIterator { + +} +try { + $it = new myParentIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_062.phpt b/ext/spl/tests/iterator_062.phpt new file mode 100644 index 0000000..59a1dfa --- /dev/null +++ b/ext/spl/tests/iterator_062.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: RecursiveIteratorIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myRecursiveIteratorIterator extends RecursiveIteratorIterator { + +} + +try { + $it = new myRecursiveIteratorIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_063.phpt b/ext/spl/tests/iterator_063.phpt new file mode 100644 index 0000000..4d4112b --- /dev/null +++ b/ext/spl/tests/iterator_063.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: LimitIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myLimitIterator extends LimitIterator { + +} +try { + $it = new myLimitIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_064.phpt b/ext/spl/tests/iterator_064.phpt new file mode 100644 index 0000000..6a62e6c --- /dev/null +++ b/ext/spl/tests/iterator_064.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: CachingIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myCachingIterator extends CachingIterator {} +try { + $it = new myCachingIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_065.phpt b/ext/spl/tests/iterator_065.phpt new file mode 100644 index 0000000..9ea2974 --- /dev/null +++ b/ext/spl/tests/iterator_065.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: RecursiveCachingIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myRecursiveCachingIterator extends RecursiveCachingIterator {} +try { + $it = new myRecursiveCachingIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_066.phpt b/ext/spl/tests/iterator_066.phpt new file mode 100644 index 0000000..008c47c --- /dev/null +++ b/ext/spl/tests/iterator_066.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: NoRewindIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myNoRewindIterator extends NoRewindIterator {} +try { + $it = new myNoRewindIterator(); +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +InvalidArgumentException thrown diff --git a/ext/spl/tests/iterator_067.phpt b/ext/spl/tests/iterator_067.phpt new file mode 100644 index 0000000..e05a48d --- /dev/null +++ b/ext/spl/tests/iterator_067.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: AppendIterator::__construct(void) +--CREDITS-- +Sebastian Schürmann +--FILE-- +<?php +class myAppendIterator extends AppendIterator {} +try { + $it = new myAppendIterator(); + echo "no exception"; +} catch (InvalidArgumentException $e) { + echo 'InvalidArgumentException thrown'; +} +?> +--EXPECT-- +no exception diff --git a/ext/spl/tests/iterator_068.phpt b/ext/spl/tests/iterator_068.phpt new file mode 100644 index 0000000..4845708 --- /dev/null +++ b/ext/spl/tests/iterator_068.phpt @@ -0,0 +1,34 @@ +--TEST-- +SPL: Iterator: Overloaded object and destruction +--FILE-- +<?php + +class Test implements Iterator { + function foo() { + echo __METHOD__ . "()\n"; + } + function rewind() {} + function valid() {} + function current() {} + function key() {} + function next() {} +} + +class TestIteratorIterator extends IteratorIterator { + function __destruct() { + echo __METHOD__ . "()\n"; + $this->foo(); + } +} + +$obj = new TestIteratorIterator(new Test); +$obj->foo(); +unset($obj); + +?> +===DONE=== +--EXPECT-- +Test::foo() +TestIteratorIterator::__destruct() +Test::foo() +===DONE=== diff --git a/ext/spl/tests/iterator_069.phpt b/ext/spl/tests/iterator_069.phpt new file mode 100644 index 0000000..e9b3177 --- /dev/null +++ b/ext/spl/tests/iterator_069.phpt @@ -0,0 +1,17 @@ +--TEST--
+SPL: RecursiveIteratorIterator cannot be used with foreach by reference
+--FILE--
+<?php
+
+$arr = array(array(1,2));
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+$recItIt = new RecursiveIteratorIterator($recArrIt);
+
+foreach ($recItIt as &$val) echo "$val\n";
+
+?>
+--EXPECTF--
+Fatal error: An iterator cannot be used with foreach by reference in %s on line %d
diff --git a/ext/spl/tests/iterator_070.phpt b/ext/spl/tests/iterator_070.phpt new file mode 100644 index 0000000..c45f08e --- /dev/null +++ b/ext/spl/tests/iterator_070.phpt @@ -0,0 +1,20 @@ +--TEST--
+SPL: RecursiveIteratorIterator - Ensure that non-overriden methods execute problem free.
+--FILE--
+<?php
+
+$array = array();
+$recArrIt = new RecursiveArrayIterator($array);
+
+$recItIt = new RecursiveIteratorIterator($recArrIt);
+
+var_dump($recItIt->beginIteration());
+var_dump($recItIt->endIteration());
+var_dump($recItIt->nextElement());
+
+?>
+
+--EXPECTF--
+NULL
+NULL
+NULL
\ No newline at end of file diff --git a/ext/spl/tests/iterator_071.phpt b/ext/spl/tests/iterator_071.phpt new file mode 100644 index 0000000..21ec798 --- /dev/null +++ b/ext/spl/tests/iterator_071.phpt @@ -0,0 +1,32 @@ +--TEST--
+SPL: RecursiveIteratorIterator - Test where the case is RS_SELF and mode is CHILD_FIRST
+--FILE--
+<?php
+
+$arr = array(array(1,2),2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function nextelement() {
+ echo __METHOD__."\n";
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::CHILD_FIRST);
+
+foreach ($recItIt as $key => $val) echo "$key\n";
+
+?>
+--EXPECTF--
+MyRecursiveIteratorIterator::nextelement
+0
+MyRecursiveIteratorIterator::nextelement
+1
+MyRecursiveIteratorIterator::nextelement
+0
+MyRecursiveIteratorIterator::nextelement
+1
\ No newline at end of file diff --git a/ext/spl/tests/iterator_count.phpt b/ext/spl/tests/iterator_count.phpt new file mode 100644 index 0000000..9aa4e11 --- /dev/null +++ b/ext/spl/tests/iterator_count.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: iterator_count() exceptions test +--CREDITS-- +Lance Kesson jac_kesson@hotmail.com +#testfest London 2009-05-09 +--FILE-- +<?php +$array=array('a','b'); + +$iterator = new ArrayIterator($array); + +iterator_count(); + + +iterator_count($iterator,'1'); + +iterator_count('1'); + + +?> +--EXPECTF-- +Warning: iterator_count() expects exactly 1 parameter, 0 given in %s + +Warning: iterator_count() expects exactly 1 parameter, 2 given in %s + +Catchable fatal error: Argument 1 passed to iterator_count() must implement interface Traversable, %unicode_string_optional% given %s diff --git a/ext/spl/tests/iterator_to_array.phpt b/ext/spl/tests/iterator_to_array.phpt new file mode 100644 index 0000000..958d370 --- /dev/null +++ b/ext/spl/tests/iterator_to_array.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: iterator_to_array() exceptions test +--CREDITS-- +Lance Kesson jac_kesson@hotmail.com +#testfest London 2009-05-09 +--FILE-- +<?php +$array=array('a','b'); + +$iterator = new ArrayIterator($array); + +iterator_to_array(); + + +iterator_to_array($iterator,'test','test'); + +iterator_to_array('test','test'); + +?> +--EXPECTF-- +Warning: iterator_to_array() expects at least 1 parameter, 0 given in %s + +Warning: iterator_to_array() expects at most 2 parameters, 3 given in %s + +Catchable fatal error: Argument 1 passed to iterator_to_array() must implement interface Traversable, %unicode_string_optional% given %s diff --git a/ext/spl/tests/limititerator_seek.phpt b/ext/spl/tests/limititerator_seek.phpt new file mode 100644 index 0000000..a59a49b --- /dev/null +++ b/ext/spl/tests/limititerator_seek.phpt @@ -0,0 +1,18 @@ +--TEST-- +SPL: LimitIterator seek() arguments +--CREDITS-- +Roshan Abraham (roshanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + +$a = array(1,2,3); +$lt = new LimitIterator(new ArrayIterator($a)); + +$lt->seek(1,1); // Should throw a warning as seek expects only 1 argument + +?> +--EXPECTF-- + +Warning: LimitIterator::seek() expects exactly 1 parameter, 2 given in %s on line %d + diff --git a/ext/spl/tests/multiple_iterator_001.phpt b/ext/spl/tests/multiple_iterator_001.phpt new file mode 100644 index 0000000..edd03f5 --- /dev/null +++ b/ext/spl/tests/multiple_iterator_001.phpt @@ -0,0 +1,345 @@ +--TEST-- +SPL: MultipleIterator +--FILE-- +<?php + +$iter1 = new ArrayIterator(array(1,2,3)); +$iter2 = new ArrayIterator(array(1,2)); +$iter3 = new ArrayIterator(array(new stdClass(),"string",3)); + +$m = new MultipleIterator(); + +echo "-- Default flags, no iterators --\n"; +foreach($m as $value) { + var_dump($value); +} +var_dump($m->current()); + +$m->attachIterator($iter1); +$m->attachIterator($iter2); +$m->attachIterator($iter3); + +echo "-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC --\n"; + +var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC)); + +foreach($m as $value) { + var_dump($m->key(), $value); +} +try { + $m->current(); +} catch(RuntimeException $e) { + echo "RuntimeException thrown: " . $e->getMessage() . "\n"; +} +try { + $m->key(); +} catch(RuntimeException $e) { + echo "RuntimeException thrown: " . $e->getMessage() . "\n"; +} + +echo "-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC --\n"; + +$m->setFlags(MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC); +var_dump($m->getFlags() === (MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC)); + +foreach($m as $value) { + var_dump($m->key(), $value); +} + +echo "-- Default flags, added element --\n"; + +$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC); + +$iter2[] = 3; +foreach($m as $value) { + var_dump($m->key(), $value); +} + +echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL --\n"; + +$m->setFlags(MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_ASSOC); +$m->rewind(); +try { + $m->current(); +} catch(InvalidArgumentException $e) { + echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n"; +} + +echo "-- Flags |= MultipleIterator::MIT_KEYS_ASSOC --\n"; + +$m->attachIterator($iter1, "iter1"); +$m->attachIterator($iter2, b"iter2"); +$m->attachIterator($iter3, 3); + +foreach($m as $value) { + var_dump($m->key(), $value); +} + +echo "-- Associate with invalid value --\n"; + +try { + $m->attachIterator($iter3, new stdClass()); +} catch(InvalidArgumentException $e) { + echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n"; +} + +echo "-- Associate with duplicate value --\n"; + +try { + $m->attachIterator($iter3, "iter1"); +} catch(InvalidArgumentException $e) { + echo "InvalidArgumentException thrown: " . $e->getMessage() . "\n"; +} + +echo "-- Count, contains, detach, count, contains, iterate --\n"; + +var_dump($m->countIterators()); +var_dump($m->containsIterator($iter2)); +var_dump($m->detachIterator($iter2)); +var_dump($m->countIterators()); +var_dump($m->containsIterator($iter2)); +foreach($m as $value) { + var_dump($m->key(), $value); +} + +?> +--EXPECTF-- +-- Default flags, no iterators -- +bool(false) +-- Default flags, MultipleIterator::MIT_NEED_ALL | MultipleIterator::MIT_KEYS_NUMERIC -- +bool(true) +array(3) { + [0]=> + int(0) + [1]=> + int(0) + [2]=> + int(0) +} +array(3) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + object(stdClass)#%d (0) { + } +} +array(3) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(1) +} +array(3) { + [0]=> + int(2) + [1]=> + int(2) + [2]=> + string(6) "string" +} +RuntimeException thrown: Called current() with non valid sub iterator +RuntimeException thrown: Called key() with non valid sub iterator +-- Flags = MultipleIterator::MIT_NEED_ANY | MultipleIterator::MIT_KEYS_NUMERIC -- +bool(true) +array(3) { + [0]=> + int(0) + [1]=> + int(0) + [2]=> + int(0) +} +array(3) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + object(stdClass)#%d (0) { + } +} +array(3) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(1) +} +array(3) { + [0]=> + int(2) + [1]=> + int(2) + [2]=> + string(6) "string" +} +array(3) { + [0]=> + int(2) + [1]=> + NULL + [2]=> + int(2) +} +array(3) { + [0]=> + int(3) + [1]=> + NULL + [2]=> + int(3) +} +-- Default flags, added element -- +array(3) { + [0]=> + int(0) + [1]=> + int(0) + [2]=> + int(0) +} +array(3) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + object(stdClass)#%d (0) { + } +} +array(3) { + [0]=> + int(1) + [1]=> + int(1) + [2]=> + int(1) +} +array(3) { + [0]=> + int(2) + [1]=> + int(2) + [2]=> + string(6) "string" +} +array(3) { + [0]=> + int(2) + [1]=> + int(2) + [2]=> + int(2) +} +array(3) { + [0]=> + int(3) + [1]=> + int(3) + [2]=> + int(3) +} +-- Flags |= MultipleIterator::MIT_KEYS_ASSOC, with iterator associated with NULL -- +InvalidArgumentException thrown: Sub-Iterator is associated with NULL +-- Flags |= MultipleIterator::MIT_KEYS_ASSOC -- +array(3) { + ["iter1"]=> + int(0) + ["iter2"]=> + int(0) + [3]=> + int(0) +} +array(3) { + ["iter1"]=> + int(1) + ["iter2"]=> + int(1) + [3]=> + object(stdClass)#%d (0) { + } +} +array(3) { + ["iter1"]=> + int(1) + ["iter2"]=> + int(1) + [3]=> + int(1) +} +array(3) { + ["iter1"]=> + int(2) + ["iter2"]=> + int(2) + [3]=> + string(6) "string" +} +array(3) { + ["iter1"]=> + int(2) + ["iter2"]=> + int(2) + [3]=> + int(2) +} +array(3) { + ["iter1"]=> + int(3) + ["iter2"]=> + int(3) + [3]=> + int(3) +} +-- Associate with invalid value -- +InvalidArgumentException thrown: Info must be NULL, integer or string +-- Associate with duplicate value -- +InvalidArgumentException thrown: Key duplication error +-- Count, contains, detach, count, contains, iterate -- +int(3) +bool(true) +NULL +int(2) +bool(false) +array(2) { + ["iter1"]=> + int(0) + [3]=> + int(0) +} +array(2) { + ["iter1"]=> + int(1) + [3]=> + object(stdClass)#%d (0) { + } +} +array(2) { + ["iter1"]=> + int(1) + [3]=> + int(1) +} +array(2) { + ["iter1"]=> + int(2) + [3]=> + string(6) "string" +} +array(2) { + ["iter1"]=> + int(2) + [3]=> + int(2) +} +array(2) { + ["iter1"]=> + int(3) + [3]=> + int(3) +} diff --git a/ext/spl/tests/observer_001.phpt b/ext/spl/tests/observer_001.phpt new file mode 100644 index 0000000..e7d72b9 --- /dev/null +++ b/ext/spl/tests/observer_001.phpt @@ -0,0 +1,116 @@ +--TEST-- +SPL: SplObserver and SplSubject (empty notify) +--FILE-- +<?php + +class ObserverImpl implements SplObserver +{ + protected $name = ''; + + function __construct($name = 'obj') + { + $this->name = '$' . $name; + } + + function update(SplSubject $subject) + { + echo $this->name . '->' . __METHOD__ . '(' . $subject->getName() . ");\n"; + } + + function getName() + { + return $this->name; + } +} + +class SubjectImpl implements SplSubject +{ + protected $name = ''; + protected $observers = array(); + + function __construct($name = 'sub') + { + $this->name = '$' . $name; + } + + function attach(SplObserver $observer) + { + echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n"; + if (!in_array($observer, $this->observers)) + { + $this->observers[] = $observer; + } + } + + function detach(SplObserver $observer) + { + echo '$sub->' . __METHOD__ . '(' . $observer->getName() . ");\n"; + $idx = array_search($observer, $this->observers); + if ($idx !== false) + { + unset($this->observers[$idx]); + } + } + + function notify() + { + echo '$sub->' . __METHOD__ . "();\n"; + foreach($this->observers as $observer) + { + $observer->update($this); + } + } + + function getName() + { + return $this->name; + } +} + +$sub = new SubjectImpl; + +$ob1 = new ObserverImpl("ob1"); +$ob2 = new ObserverImpl("ob2"); +$ob3 = new ObserverImpl("ob3"); + +$sub->attach($ob1); +$sub->attach($ob1); +$sub->attach($ob2); +$sub->attach($ob3); + +$sub->notify(); + +$sub->detach($ob3); + +$sub->notify(); + +$sub->detach($ob2); +$sub->detach($ob1); + +$sub->notify(); + +$sub->attach($ob3); + +$sub->notify(); +?> +===DONE=== +--EXPECT-- +$sub->SubjectImpl::attach($ob1); +$sub->SubjectImpl::attach($ob1); +$sub->SubjectImpl::attach($ob2); +$sub->SubjectImpl::attach($ob3); +$sub->SubjectImpl::notify(); +$ob1->ObserverImpl::update($sub); +$ob2->ObserverImpl::update($sub); +$ob3->ObserverImpl::update($sub); +$sub->SubjectImpl::detach($ob3); +$sub->SubjectImpl::notify(); +$ob1->ObserverImpl::update($sub); +$ob2->ObserverImpl::update($sub); +$sub->SubjectImpl::detach($ob2); +$sub->SubjectImpl::detach($ob1); +$sub->SubjectImpl::notify(); +$sub->SubjectImpl::attach($ob3); +$sub->SubjectImpl::notify(); +$ob3->ObserverImpl::update($sub); +===DONE=== diff --git a/ext/spl/tests/observer_002.phpt b/ext/spl/tests/observer_002.phpt new file mode 100644 index 0000000..5d00617 --- /dev/null +++ b/ext/spl/tests/observer_002.phpt @@ -0,0 +1,199 @@ +--TEST-- +SPL: SplObjectStorage +--FILE-- +<?php + +class MyObjectStorage extends SplObjectStorage +{ + function rewind() + { + echo __METHOD__ . "()\n"; + parent::rewind(); + } + + function valid() + { + echo __METHOD__ . "(" . (parent::valid() ? 1 : 0) . ")\n"; + return parent::valid(); + } + + function key() + { + echo __METHOD__ . "(" . parent::key() . ")\n"; + return parent::key(); + } + + function current() + { + echo __METHOD__ . "(" . parent::current()->getName() . ")\n"; + return parent::current(); + } + + function next() + { + echo __METHOD__ . "()\n"; + parent::next(); + } +} + +class ObserverImpl implements SplObserver +{ + protected $name = ''; + + function __construct($name = 'obj') + { + $this->name = '$' . $name; + } + + function update(SplSubject $subject) + { + echo $this->name . '->' . __METHOD__ . '(' . $subject->getName() . ");\n"; + } + + function getName() + { + return $this->name; + } +} + +class SubjectImpl implements SplSubject +{ + protected $name = ''; + protected $observers; + + function __construct($name = 'sub') + { + $this->observers = new MyObjectStorage; + $this->name = '$' . $name; + } + + function attach(SplObserver $observer) + { + echo $this->name . '->' . __METHOD__ . '(' . $observer->getName() . ");\n"; + $this->observers->attach($observer); + } + + function detach(SplObserver $observer) + { + echo $this->name . '->' . __METHOD__ . '(' . $observer->getName() . ");\n"; + $this->observers->detach($observer); + } + + function count() + { + return $this->observers->count(); + } + + function notify() + { + echo $this->name . '->' . __METHOD__ . "();\n"; + foreach($this->observers as $key => $observer) + { + $observer->update($this); + } + } + + function getName() + { + return $this->name; + } + + function contains($obj) + { + return $this->observers->contains($obj); + } +} + +$sub = new SubjectImpl; + +$ob1 = new ObserverImpl("ob1"); +$ob2 = new ObserverImpl("ob2"); +$ob3 = new ObserverImpl("ob3"); + +var_dump($sub->contains($ob1)); +$sub->attach($ob1); +var_dump($sub->contains($ob1)); +$sub->attach($ob1); +$sub->attach($ob2); +$sub->attach($ob3); +var_dump($sub->count()); + +$sub->notify(); + +$sub->detach($ob3); +var_dump($sub->count()); + +$sub->notify(); + +$sub->detach($ob2); +$sub->detach($ob1); +var_dump($sub->count()); + +$sub->notify(); + +$sub->attach($ob3); +var_dump($sub->count()); + +$sub->notify(); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +bool(false) +$sub->SubjectImpl::attach($ob1); +bool(true) +$sub->SubjectImpl::attach($ob1); +$sub->SubjectImpl::attach($ob2); +$sub->SubjectImpl::attach($ob3); +int(3) +$sub->SubjectImpl::notify(); +MyObjectStorage::rewind() +MyObjectStorage::valid(1) +MyObjectStorage::current($ob1) +MyObjectStorage::key(0) +$ob1->ObserverImpl::update($sub); +MyObjectStorage::next() +MyObjectStorage::valid(1) +MyObjectStorage::current($ob2) +MyObjectStorage::key(1) +$ob2->ObserverImpl::update($sub); +MyObjectStorage::next() +MyObjectStorage::valid(1) +MyObjectStorage::current($ob3) +MyObjectStorage::key(2) +$ob3->ObserverImpl::update($sub); +MyObjectStorage::next() +MyObjectStorage::valid(0) +$sub->SubjectImpl::detach($ob3); +int(2) +$sub->SubjectImpl::notify(); +MyObjectStorage::rewind() +MyObjectStorage::valid(1) +MyObjectStorage::current($ob1) +MyObjectStorage::key(0) +$ob1->ObserverImpl::update($sub); +MyObjectStorage::next() +MyObjectStorage::valid(1) +MyObjectStorage::current($ob2) +MyObjectStorage::key(1) +$ob2->ObserverImpl::update($sub); +MyObjectStorage::next() +MyObjectStorage::valid(0) +$sub->SubjectImpl::detach($ob2); +$sub->SubjectImpl::detach($ob1); +int(0) +$sub->SubjectImpl::notify(); +MyObjectStorage::rewind() +MyObjectStorage::valid(0) +$sub->SubjectImpl::attach($ob3); +int(1) +$sub->SubjectImpl::notify(); +MyObjectStorage::rewind() +MyObjectStorage::valid(1) +MyObjectStorage::current($ob3) +MyObjectStorage::key(0) +$ob3->ObserverImpl::update($sub); +MyObjectStorage::next() +MyObjectStorage::valid(0) +===DONE=== diff --git a/ext/spl/tests/observer_003.phpt b/ext/spl/tests/observer_003.phpt new file mode 100644 index 0000000..5e5da22 --- /dev/null +++ b/ext/spl/tests/observer_003.phpt @@ -0,0 +1,58 @@ +--TEST-- +SPL: SplObjectStorage serialization +--FILE-- +<?php + +class TestClass +{ + public $test = 25; + + public function __construct($test = 42) + { + $this->test = $test; + } +} + +$storage = new SplObjectStorage(); + +foreach(array(1,"2","foo",true) as $value) +{ + $storage->attach(new TestClass($value)); +} + +var_dump(count($storage)); + +foreach($storage as $object) +{ + var_dump($object->test); +} + +var_dump(serialize($storage)); +echo "===UNSERIALIZE===\n"; + +$storage2 = unserialize(serialize($storage)); + +var_dump(count($storage2)); + +foreach($storage2 as $object) +{ + var_dump($object->test); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(4) +int(1) +string(1) "2" +string(3) "foo" +bool(true) +string(%d) "%s" +===UNSERIALIZE=== +int(4) +int(1) +string(1) "2" +string(3) "foo" +bool(true) +===DONE=== diff --git a/ext/spl/tests/observer_004.phpt b/ext/spl/tests/observer_004.phpt new file mode 100644 index 0000000..0bc2512 --- /dev/null +++ b/ext/spl/tests/observer_004.phpt @@ -0,0 +1,122 @@ +--TEST-- +SPL: SplObjectStorage serialization & overloading +--FILE-- +<?php + +class TestClass +{ + public $test = 25; + + public function __construct($test = 42) + { + $this->test = $test; + } +} + +class MyStorage extends SplObjectStorage +{ + public $bla = 25; + + public function __construct($bla = 26) + { + $this->bla = $bla; + } +} + +$storage = new MyStorage(); + +foreach(array(1,2) as $value) +{ + $storage->attach(new TestClass($value)); +} + +var_dump(count($storage)); + +foreach($storage as $object) +{ + var_dump($object->test); +} + +var_dump($storage); + +var_dump(serialize($storage)); +echo "===UNSERIALIZE===\n"; + +$storage2 = unserialize(serialize($storage)); + +var_dump(count($storage2)); + +foreach($storage2 as $object) +{ + var_dump($object->test); +} + +var_dump($storage2); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(2) +int(1) +int(2) +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + NULL + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + NULL + } + } +} +string(%d) "%s" +===UNSERIALIZE=== +int(2) +int(1) +int(2) +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + NULL + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + NULL + } + } +} +===DONE=== diff --git a/ext/spl/tests/observer_005.phpt b/ext/spl/tests/observer_005.phpt new file mode 100644 index 0000000..883602f --- /dev/null +++ b/ext/spl/tests/observer_005.phpt @@ -0,0 +1,212 @@ +--TEST-- +SPL: SplObjectStorage serialization & visibility +--FILE-- +<?php + +class TestClass +{ + public $def = 24; + public $pub = 25; + protected $pro = 26; + private $pri = 27; + + public function __construct($pub = 42, $pro = 43, $pri = 44) + { + $this->pub = $pub; + $this->pro = $pro; + $this->pri = $pri; + } +} + +class ExtTestClass +{ +} + +class MyStorage extends SplObjectStorage +{ + public $def = 24; + public $pub = 25; + protected $pro = 26; + private $pri = 27; + + public function __construct($pub = 52, $pro = 53, $pri = 54) + { + $this->pub = $pub; + $this->pro = $pro; + $this->pri = $pri; + } +} + +class ExtStorage extends MyStorage +{ +} + +$storage = new MyStorage(1,2,3); + +foreach(array(array(4,5,6),array(7,8,9)) as $value) +{ + $storage->attach(new TestClass($value[0], $value[1], $value[2])); +} + +var_dump(count($storage)); + +foreach($storage as $object) +{ + var_dump($object); +} + +var_dump($storage); + +var_dump(serialize($storage)); +echo "===UNSERIALIZE===\n"; + +$storage2 = unserialize(serialize($storage)); + +var_dump(count($storage2)); + +foreach($storage2 as $object) +{ + var_dump($object); +} + +var_dump($storage2); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(2) +object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(4) + ["pro":protected]=> + int(5) + ["pri":"TestClass":private]=> + int(6) +} +object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(7) + ["pro":protected]=> + int(8) + ["pri":"TestClass":private]=> + int(9) +} +object(MyStorage)#%d (5) { + ["def"]=> + int(24) + ["pub"]=> + int(1) + ["pro":protected]=> + int(2) + ["pri":"MyStorage":private]=> + int(3) + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(4) + ["pro":protected]=> + int(5) + ["pri":"TestClass":private]=> + int(6) + } + ["inf"]=> + NULL + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(7) + ["pro":protected]=> + int(8) + ["pri":"TestClass":private]=> + int(9) + } + ["inf"]=> + NULL + } + } +} +string(%d) "%s" +===UNSERIALIZE=== +int(2) +object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(4) + ["pro":protected]=> + int(5) + ["pri":"TestClass":private]=> + int(6) +} +object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(7) + ["pro":protected]=> + int(8) + ["pri":"TestClass":private]=> + int(9) +} +object(MyStorage)#%d (5) { + ["def"]=> + int(24) + ["pub"]=> + int(1) + ["pro":protected]=> + int(2) + ["pri":"MyStorage":private]=> + int(3) + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(4) + ["pro":protected]=> + int(5) + ["pri":"TestClass":private]=> + int(6) + } + ["inf"]=> + NULL + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (4) { + ["def"]=> + int(24) + ["pub"]=> + int(7) + ["pro":protected]=> + int(8) + ["pri":"TestClass":private]=> + int(9) + } + ["inf"]=> + NULL + } + } +} +===DONE=== diff --git a/ext/spl/tests/observer_006.phpt b/ext/spl/tests/observer_006.phpt new file mode 100644 index 0000000..3cd84a7 --- /dev/null +++ b/ext/spl/tests/observer_006.phpt @@ -0,0 +1,310 @@ +--TEST-- +SPL: SplObjectStorage with accociatied information +--FILE-- +<?php + +class TestClass +{ + public $test = 25; + + public function __construct($test = 42) + { + $this->test = $test; + } +} + +class MyStorage extends SplObjectStorage +{ + public $bla = 25; + + public function __construct($bla = 26) + { + $this->bla = $bla; + } +} + +$storage = new MyStorage(); + +foreach(array(1=>"foo",2=>42) as $key => $value) +{ + $storage->attach(new TestClass($key), $value); +} + +var_dump(count($storage)); + +foreach($storage as $object) +{ + var_dump($object->test); +} + +var_dump($storage); + +var_dump(serialize($storage)); +echo "===UNSERIALIZE===\n"; + +$storage2 = unserialize(serialize($storage)); + +var_dump(count($storage2)); + +foreach($storage2 as $object) +{ + var_dump($object->test); +} + +var_dump($storage2); +$storage->attach(new TestClass(3), new stdClass); +$storage->attach(new TestClass(4), new TestClass(5)); +echo "===UNSERIALIZE2===\n"; +var_dump(unserialize(serialize($storage))); +$storage->rewind(); +$storage->next(); +var_dump($storage->key()); +var_dump($storage->current()); +var_dump($storage->getInfo()); +$storage->setInfo("bar"); +var_dump($storage->getInfo()); +echo "===UNSERIALIZE3===\n"; +var_dump(unserialize(serialize($storage))); +$storage->rewind(); +$storage->next(); +$storage->next(); +var_dump($storage->key()); +var_dump($storage->current()); +$storage->attach($storage->current(), "replaced"); +echo "===UNSERIALIZE4===\n"; +var_dump(unserialize(serialize($storage))); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(2) +int(1) +int(2) +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + string(3) "foo" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + int(42) + } + } +} +string(%d) "%s" +===UNSERIALIZE=== +int(2) +int(1) +int(2) +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(2) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + string(3) "foo" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + int(42) + } + } +} +===UNSERIALIZE2=== +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(4) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + string(3) "foo" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + int(42) + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(3) + } + ["inf"]=> + object(stdClass)#%d (0) { + } + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(4) + } + ["inf"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(5) + } + } + } +} +int(1) +object(TestClass)#%d (1) { + ["test"]=> + int(2) +} +int(42) +string(3) "bar" +===UNSERIALIZE3=== +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(4) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + string(3) "foo" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + string(3) "bar" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(3) + } + ["inf"]=> + object(stdClass)#%d (0) { + } + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(4) + } + ["inf"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(5) + } + } + } +} +int(2) +object(TestClass)#7 (1) { + ["test"]=> + int(3) +} +===UNSERIALIZE4=== +object(MyStorage)#%d (2) { + ["bla"]=> + int(26) + ["storage":"SplObjectStorage":private]=> + array(4) { + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(1) + } + ["inf"]=> + string(3) "foo" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(2) + } + ["inf"]=> + string(3) "bar" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(3) + } + ["inf"]=> + string(8) "replaced" + } + ["%s"]=> + array(2) { + ["obj"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(4) + } + ["inf"]=> + object(TestClass)#%d (1) { + ["test"]=> + int(5) + } + } + } +} +===DONE=== diff --git a/ext/spl/tests/observer_007.phpt b/ext/spl/tests/observer_007.phpt new file mode 100644 index 0000000..e494f19 --- /dev/null +++ b/ext/spl/tests/observer_007.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplObjectStorage comapred with == +--FILE-- +<?php +$a = new SplObjectStorage; +$b = new SplObjectStorage; +var_dump($a == $b); +$b[$b] = 2; +var_dump($a == $b); +$a[$b] = 2; +var_dump($a == $b); +$a[$b] = 3; +var_dump($a == $b); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +bool(true) +bool(false) +bool(true) +bool(false) +===DONE=== diff --git a/ext/spl/tests/observer_008.phpt b/ext/spl/tests/observer_008.phpt new file mode 100644 index 0000000..56a3c89 --- /dev/null +++ b/ext/spl/tests/observer_008.phpt @@ -0,0 +1,35 @@ +--TEST-- +SPL: SplObjectStorage addAll/removeAll +--FILE-- +<?php +class A extends SplObjectStorage { } + +$o1 = new StdClass; +$o2 = new StdClass; +$o3 = new StdClass; + +$a = new A; +$a->attach($o1); +$a->attach($o2); + +$b = new SplObjectSTorage(); +$b->attach($o2); +$b->attach($o3); + +$a->addAll($b); + +var_dump($a->count()); + +$a->detach($o3); +var_dump($a->count()); + +$a->removeAll($b); +var_dump($a->count()); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +int(3) +int(2) +int(1) +===DONE=== diff --git a/ext/spl/tests/observer_009.phpt b/ext/spl/tests/observer_009.phpt new file mode 100644 index 0000000..6ac676c --- /dev/null +++ b/ext/spl/tests/observer_009.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: SplObjectStorage addAll/removeAll +--FILE-- +<?php +class Foo {} + +$storageA = new \SplObjectStorage(); +$storageA->attach(new \Foo); +$storageA->attach(new \Foo); + +echo ("Count storage A: " . count($storageA)); +foreach ($storageA as $object) { + echo ' x '; +} + +echo "\n"; +$storageB = clone $storageA; + +echo ("Count storage B: " . count($storageB)); +foreach ($storageB as $object) { + echo ' x '; +} +echo "\n"; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Count storage A: 2 x x +Count storage B: 2 x x +===DONE=== diff --git a/ext/spl/tests/pqueue_001.phpt b/ext/spl/tests/pqueue_001.phpt new file mode 100644 index 0000000..de164e5 --- /dev/null +++ b/ext/spl/tests/pqueue_001.phpt @@ -0,0 +1,96 @@ +--TEST-- +SPL: SplPriorityQueue: std operations and extract flags +--FILE-- +<?php +$pq = new SplPriorityQueue(); + +// errors +try { + $pq->extract(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +$pq->insert("a", 1); +$pq->insert("b", 2); +$pq->insert("c", 0); + +foreach ($pq as $k=>$v) { + echo "$k=>".print_r($v, 1)."\n"; +} + +echo "EXTR_BOTH\n"; + +$pq1 = new SplPriorityQueue(); +$pq1->setExtractFlags(SplPriorityQueue::EXTR_BOTH); + +$pq1->insert("a", 1); +$pq1->insert("b", 2); +$pq1->insert("c", 0); + +foreach ($pq1 as $k=>$v) { + echo "$k=>".print_r($v, 1)."\n"; +} + +echo "EXTR_DATA\n"; + +$pq2 = new SplPriorityQueue(); +$pq2->setExtractFlags(SplPriorityQueue::EXTR_DATA); + +$pq2->insert("a", 1); +$pq2->insert("b", 2); +$pq2->insert("c", 0); + +foreach ($pq2 as $k=>$v) { + echo "$k=>".print_r($v, 1)."\n"; +} + +echo "EXTR_PRIORITY\n"; + +$pq3 = new SplPriorityQueue(); +$pq3->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY); + +$pq3->insert("a", 1); +$pq3->insert("b", 2); +$pq3->insert("c", 0); + +foreach ($pq3 as $k=>$v) { + echo "$k=>".print_r($v, 1)."\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Can't extract from an empty heap +2=>b +1=>a +0=>c +EXTR_BOTH +2=>Array +( + [data] => b + [priority] => 2 +) + +1=>Array +( + [data] => a + [priority] => 1 +) + +0=>Array +( + [data] => c + [priority] => 0 +) + +EXTR_DATA +2=>b +1=>a +0=>c +EXTR_PRIORITY +2=>2 +1=>1 +0=>0 +===DONE=== diff --git a/ext/spl/tests/pqueue_002.phpt b/ext/spl/tests/pqueue_002.phpt new file mode 100644 index 0000000..eaab2cf --- /dev/null +++ b/ext/spl/tests/pqueue_002.phpt @@ -0,0 +1,67 @@ +--TEST-- +SPL: SplPriorityQueue: exceptions +--FILE-- +<?php +class myPQueue extends SplPriorityQueue { + public function compare($a, $b) { + throw new exception("foo"); + } +} + +$h = new myPQueue; + +try { + $h->insert(1, 1); + echo "inserted 1\n"; + $h->insert(2, 1); + echo "inserted 2\n"; + $h->insert(3, 1); + echo "inserted 3\n"; +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + $h->insert(4, 1); + echo "inserted 4\n"; +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} + +echo "Recovering..\n"; +$h->recoverFromCorruption(); + +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +try { + var_dump($h->extract()); +} catch(Exception $e) { + echo "Exception: ".$e->getMessage()."\n"; +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +inserted 1 +Exception: foo +Exception: Heap is corrupted, heap properties are no longer ensured. +Exception: Heap is corrupted, heap properties are no longer ensured. +Exception: Heap is corrupted, heap properties are no longer ensured. +Recovering.. +int(1) +int(2) +===DONE=== diff --git a/ext/spl/tests/pqueue_003.phpt b/ext/spl/tests/pqueue_003.phpt new file mode 100644 index 0000000..9c0b5a5 --- /dev/null +++ b/ext/spl/tests/pqueue_003.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: SplPriorityQueue: iteration through methods +--FILE-- +<?php +$h = new SplPriorityQueue(); + +$h->insert(1, 1); +$h->insert(5, 5); +$h->insert(0, 0); +$h->insert(4, 4); + +$h->rewind(); +echo "count(\$h) = ".count($h)."\n"; +echo "\$h->count() = ".$h->count()."\n"; +while ($h->valid()) { + $k = $h->key(); + $v = $h->current(); + echo "$k=>$v\n"; + $h->next(); +} +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +count($h) = 4 +$h->count() = 4 +3=>5 +2=>4 +1=>1 +0=>0 +===DONE=== diff --git a/ext/spl/tests/pqueue_004.phpt b/ext/spl/tests/pqueue_004.phpt new file mode 100644 index 0000000..3a86f9e --- /dev/null +++ b/ext/spl/tests/pqueue_004.phpt @@ -0,0 +1,54 @@ +--TEST-- +SPL: SplPriorityQueue: var_dump +--FILE-- +<?php +$pq = new SplPriorityQueue(); + +$pq->insert("a", 0); +$pq->insert("b", 1); +$pq->insert("c", 5); +$pq->insert("d", -2); + +var_dump($pq); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +object(SplPriorityQueue)#1 (3) { + ["flags":"SplPriorityQueue":private]=> + int(1) + ["isCorrupted":"SplPriorityQueue":private]=> + bool(false) + ["heap":"SplPriorityQueue":private]=> + array(4) { + [0]=> + array(2) { + ["data"]=> + string(1) "c" + ["priority"]=> + int(5) + } + [1]=> + array(2) { + ["data"]=> + string(1) "a" + ["priority"]=> + int(0) + } + [2]=> + array(2) { + ["data"]=> + string(1) "b" + ["priority"]=> + int(1) + } + [3]=> + array(2) { + ["data"]=> + string(1) "d" + ["priority"]=> + int(-2) + } + } +} +===DONE=== diff --git a/ext/spl/tests/pqueue_compare_basic.phpt b/ext/spl/tests/pqueue_compare_basic.phpt new file mode 100644 index 0000000..1544add --- /dev/null +++ b/ext/spl/tests/pqueue_compare_basic.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplPriorityQueue: test compare +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplPriorityQueue(); +var_dump($h->compare(4, 5) < 0); +var_dump($h->compare(5, 5) == 0); +var_dump($h->compare(5, 4) > 0); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) +===DONE=== diff --git a/ext/spl/tests/pqueue_compare_error.phpt b/ext/spl/tests/pqueue_compare_error.phpt new file mode 100644 index 0000000..610be2a --- /dev/null +++ b/ext/spl/tests/pqueue_compare_error.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: Priority queue compare, illegal number of args +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplPriorityQueue(); +$h->compare(); +$h->compare(1); +$h->compare(1, 2, 3); +?> +--EXPECTF-- +Warning: SplPriorityQueue::compare() expects exactly 2 parameters, 0 given in %s + +Warning: SplPriorityQueue::compare() expects exactly 2 parameters, 1 given in %s + +Warning: SplPriorityQueue::compare() expects exactly 2 parameters, 3 given in %s + diff --git a/ext/spl/tests/pqueue_current_error.phpt b/ext/spl/tests/pqueue_current_error.phpt new file mode 100644 index 0000000..7fdf0af --- /dev/null +++ b/ext/spl/tests/pqueue_current_error.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplPriorityQueue current on empty queue should give null +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplPriorityQueue(); +var_dump($h->current()); +?> +--EXPECT-- +NULL diff --git a/ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt b/ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt new file mode 100644 index 0000000..f543072 --- /dev/null +++ b/ext/spl/tests/recursiveIteratorIterator_beginchildren_error.phpt @@ -0,0 +1,36 @@ +--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in beginchildren which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(array(1,2),2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function beginchildren() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+var_dump($recItIt->next());
+
+$recItIt2 = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+var_dump($recItIt2->next());
+
+?>
+--EXPECTF--
+NULL
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->beginchildren()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt b/ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt new file mode 100644 index 0000000..88f03fb --- /dev/null +++ b/ext/spl/tests/recursiveIteratorIterator_callHasChildren_error.phpt @@ -0,0 +1,36 @@ +--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in callHasChildren which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(1,2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function callHasChildren() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+var_dump($recItIt->next());
+
+$recItIt2 = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+var_dump($recItIt2->next());
+
+?>
+--EXPECTF--
+NULL
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->callHasChildren()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt b/ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt new file mode 100644 index 0000000..e25d3ed --- /dev/null +++ b/ext/spl/tests/recursiveIteratorIterator_endchildren_error.phpt @@ -0,0 +1,42 @@ +--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in endchildren which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(array(1,2));
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function endchildren() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+foreach ($recItIt as $val) echo "$val\n";
+
+$recItIt2 = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+echo "===NEXT LOOP===\n";
+
+foreach ($recItIt2 as $val) echo "$val\n";
+
+?>
+--EXPECTF--
+1
+2
+===NEXT LOOP===
+1
+2
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->endchildren()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt b/ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt new file mode 100644 index 0000000..3a91ed5 --- /dev/null +++ b/ext/spl/tests/recursiveIteratorIterator_nextelement_error.phpt @@ -0,0 +1,36 @@ +--TEST--
+SPL: RecursiveIteratorIterator - Exception thrown in nextelement which should be handled in next()
+--FILE--
+<?php
+
+$arr = array(1,2);
+$arrOb = new ArrayObject($arr);
+
+$recArrIt = new RecursiveArrayIterator($arrOb->getIterator());
+
+class MyRecursiveIteratorIterator extends RecursiveIteratorIterator {
+
+ function nextelement() {
+ throw new Exception;
+ }
+}
+
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD);
+
+var_dump($recItIt->next());
+
+$recItIt = new MyRecursiveIteratorIterator($recArrIt, RecursiveIteratorIterator::LEAVES_ONLY);
+
+var_dump($recItIt->next());
+
+?>
+--EXPECTF--
+NULL
+
+Fatal error: Uncaught exception 'Exception' in %s
+Stack trace:
+#0 [internal function]: MyRecursiveIteratorIterator->nextelement()
+#1 %s: RecursiveIteratorIterator->next()
+#2 {main}
+ thrown in %s on line %d
diff --git a/ext/spl/tests/recursive_tree_iterator_001.phpt b/ext/spl/tests/recursive_tree_iterator_001.phpt new file mode 100644 index 0000000..f70186c --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_001.phpt @@ -0,0 +1,102 @@ +--TEST-- +SPL: RecursiveTreeIterator +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php + +$ary = array( + 0 => array( + "a", + 1, + ), + "a" => array( + 2, + "b", + 3 => array( + 4, + "c", + ), + "3" => array( + 4, + "c", + ), + ), +); + +$it = new RecursiveArrayIterator($ary); +echo "-- flags = BYPASS_KEY --\n"; +foreach(new RecursiveTreeIterator($it) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = BYPASS_CURRENT --\n"; +foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = BYPASS_KEY|BYPASS_KEY --\n"; +foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT|RecursiveTreeIterator::BYPASS_KEY) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = 0 --\n"; +foreach(new RecursiveTreeIterator($it, 0) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --\n"; +foreach(new RecursiveTreeIterator($it, 0, CachingIterator::CATCH_GET_CHILD) as $k => $v) { + echo "[$k] => $v\n"; +} + +?> +===DONE=== +--EXPECTF-- +-- flags = BYPASS_KEY -- +[0] => |-Array +[0] => | |-a +[1] => | \-1 +[a] => \-Array +[0] => |-2 +[1] => |-b +[3] => \-Array +[0] => |-4 +[1] => \-c +-- flags = BYPASS_CURRENT -- +[|-0] => Array +[| |-0] => a +[| \-1] => 1 +[\-a] => Array +[ |-0] => 2 +[ |-1] => b +[ \-3] => Array +[ |-0] => 4 +[ \-1] => c +-- flags = BYPASS_KEY|BYPASS_KEY -- +[0] => Array +[0] => a +[1] => 1 +[a] => Array +[0] => 2 +[1] => b +[3] => Array +[0] => 4 +[1] => c +-- flags = 0 -- +[|-0] => |-Array +[| |-0] => | |-a +[| \-1] => | \-1 +[\-a] => \-Array +[ |-0] => |-2 +[ |-1] => |-b +[ \-3] => \-Array +[ |-0] => |-4 +[ \-1] => \-c +-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD -- +[|-0] => |-Array +[| |-0] => | |-a +[| \-1] => | \-1 +[\-a] => \-Array +[ |-0] => |-2 +[ |-1] => |-b +[ \-3] => \-Array +[ |-0] => |-4 +[ \-1] => \-c +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_002.phpt b/ext/spl/tests/recursive_tree_iterator_002.phpt new file mode 100644 index 0000000..1aae288 --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: RecursiveTreeIterator(void) +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php +try { + new RecursiveTreeIterator(); +} catch (InvalidArgumentException $e) { + echo "InvalidArgumentException thrown\n"; +} +?> +===DONE=== +--EXPECTF-- +InvalidArgumentException thrown +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_003.phpt b/ext/spl/tests/recursive_tree_iterator_003.phpt new file mode 100644 index 0000000..83c8553 --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_003.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: RecursiveTreeIterator(non-traversable) +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php +try { + new RecursiveTreeIterator(new ArrayIterator(array())); +} catch (InvalidArgumentException $e) { + echo "InvalidArgumentException thrown\n"; +} +?> +===DONE=== +--EXPECTF-- +InvalidArgumentException thrown +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_004.phpt b/ext/spl/tests/recursive_tree_iterator_004.phpt new file mode 100644 index 0000000..ad3ba6c --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_004.phpt @@ -0,0 +1,43 @@ +--TEST-- +SPL: RecursiveTreeIterator methods +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php + +$ary = array( + 0 => array( + "a", + 1, + ), + "a" => array( + 2, + "b", + 3 => array( + 4, + "c", + ), + "3" => array( + 4, + "c", + ), + ), +); + +$it = new RecursiveTreeIterator(new RecursiveArrayIterator($ary)); +foreach($it as $k => $v) { + echo '[' . $it->key() . '] => ' . $it->getPrefix() . $it->getEntry() . $it->getPostfix() . "\n"; +} +?> +===DONE=== +--EXPECTF-- +[0] => |-Array +[0] => | |-a +[1] => | \-1 +[a] => \-Array +[0] => |-2 +[1] => |-b +[3] => \-Array +[0] => |-4 +[1] => \-c +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_005.phpt b/ext/spl/tests/recursive_tree_iterator_005.phpt new file mode 100644 index 0000000..b14811f --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_005.phpt @@ -0,0 +1,116 @@ +--TEST-- +SPL: RecursiveTreeIterator and binary vs unicode (PHP 6.0+) +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php + +$ary = array( + 0 => array( + (binary) "binary", + "abc2", + 1, + ), + (binary) "binary" => array( + 2, + "b", + 3 => array( + 4, + "c", + ), + "4abc" => array( + 4, + "c", + ), + ), +); + +$it = new RecursiveTreeIterator(new RecursiveArrayIterator($ary), 0); +foreach($it as $k => $v) { + var_dump($v); +} +echo "\n----------------\n\n"; +foreach($it as $k => $v) { + var_dump($k); +} +echo "\n----------------\n\n"; +echo "key, getEntry, current:\n"; +foreach($it as $k => $v) { + var_dump($it->key(), $it->getEntry(), $it->current()); +} +?> +===DONE=== +--EXPECT-- +string(7) "|-Array" +string(10) "| |-binary" +string(8) "| |-abc2" +string(5) "| \-1" +string(7) "\-Array" +string(5) " |-2" +string(5) " |-b" +string(9) " |-Array" +string(7) " | |-4" +string(7) " | \-c" +string(9) " \-Array" +string(7) " |-4" +string(7) " \-c" + +---------------- + +string(3) "|-0" +string(5) "| |-0" +string(5) "| |-1" +string(5) "| \-2" +string(8) "\-binary" +string(5) " |-0" +string(5) " |-1" +string(5) " |-3" +string(7) " | |-0" +string(7) " | \-1" +string(8) " \-4abc" +string(7) " |-0" +string(7) " \-1" + +---------------- + +key, getEntry, current: +string(3) "|-0" +string(5) "Array" +string(7) "|-Array" +string(5) "| |-0" +string(6) "binary" +string(10) "| |-binary" +string(5) "| |-1" +string(4) "abc2" +string(8) "| |-abc2" +string(5) "| \-2" +string(1) "1" +string(5) "| \-1" +string(8) "\-binary" +string(5) "Array" +string(7) "\-Array" +string(5) " |-0" +string(1) "2" +string(5) " |-2" +string(5) " |-1" +string(1) "b" +string(5) " |-b" +string(5) " |-3" +string(5) "Array" +string(9) " |-Array" +string(7) " | |-0" +string(1) "4" +string(7) " | |-4" +string(7) " | \-1" +string(1) "c" +string(7) " | \-c" +string(8) " \-4abc" +string(5) "Array" +string(9) " \-Array" +string(7) " |-0" +string(1) "4" +string(7) " |-4" +string(7) " \-1" +string(1) "c" +string(7) " \-c" +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_006.phpt b/ext/spl/tests/recursive_tree_iterator_006.phpt new file mode 100644 index 0000000..17f51b6 --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_006.phpt @@ -0,0 +1,112 @@ +--TEST-- +SPL: RecursiveTreeIterator and IteratorAggregate +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php + +$ary = array( + 0 => array( + "a", + 1, + ), + "a" => array( + 2, + "b", + 3 => array( + 4, + "c", + ), + "3" => array( + 4, + "c", + ), + ), +); + +class RecursiveArrayIteratorAggregated implements IteratorAggregate { + public $it; + function __construct($it) { + $this->it = new RecursiveArrayIterator($it); + } + function getIterator() { + return $this->it; + } +} + +$it = new RecursiveArrayIteratorAggregated($ary); +echo "-- flags = BYPASS_KEY --\n"; +foreach(new RecursiveTreeIterator($it) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = BYPASS_CURRENT --\n"; +foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = BYPASS_KEY|BYPASS_KEY --\n"; +foreach(new RecursiveTreeIterator($it, RecursiveTreeIterator::BYPASS_CURRENT|RecursiveTreeIterator::BYPASS_KEY) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = 0 --\n"; +foreach(new RecursiveTreeIterator($it, 0) as $k => $v) { + echo "[$k] => $v\n"; +} +echo "-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD --\n"; +foreach(new RecursiveTreeIterator($it, 0, CachingIterator::CATCH_GET_CHILD) as $k => $v) { + echo "[$k] => $v\n"; +} + +?> +===DONE=== +--EXPECTF-- +-- flags = BYPASS_KEY -- +[0] => |-Array +[0] => | |-a +[1] => | \-1 +[a] => \-Array +[0] => |-2 +[1] => |-b +[3] => \-Array +[0] => |-4 +[1] => \-c +-- flags = BYPASS_CURRENT -- +[|-0] => Array +[| |-0] => a +[| \-1] => 1 +[\-a] => Array +[ |-0] => 2 +[ |-1] => b +[ \-3] => Array +[ |-0] => 4 +[ \-1] => c +-- flags = BYPASS_KEY|BYPASS_KEY -- +[0] => Array +[0] => a +[1] => 1 +[a] => Array +[0] => 2 +[1] => b +[3] => Array +[0] => 4 +[1] => c +-- flags = 0 -- +[|-0] => |-Array +[| |-0] => | |-a +[| \-1] => | \-1 +[\-a] => \-Array +[ |-0] => |-2 +[ |-1] => |-b +[ \-3] => \-Array +[ |-0] => |-4 +[ \-1] => \-c +-- flags = 0, caching_it_flags = CachingIterator::CATCH_GET_CHILD -- +[|-0] => |-Array +[| |-0] => | |-a +[| \-1] => | \-1 +[\-a] => \-Array +[ |-0] => |-2 +[ |-1] => |-b +[ \-3] => \-Array +[ |-0] => |-4 +[ \-1] => \-c +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_007.phpt b/ext/spl/tests/recursive_tree_iterator_007.phpt new file mode 100644 index 0000000..6a8ff84 --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_007.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: RecursiveTreeIterator and Exception from getEntry() +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php + +$ary = array(new stdClass); + +class RecursiveArrayIteratorAggregated implements IteratorAggregate { + public $it; + function __construct($it) { + $this->it = new RecursiveArrayIterator($it); + } + function getIterator() { + return $this->it; + } +} + +$it = new RecursiveArrayIteratorAggregated($ary); +try { + foreach(new RecursiveTreeIterator($it) as $k => $v) { + echo "[$k] => $v\n"; + } +} catch (UnexpectedValueException $e) { + echo "UnexpectedValueException thrown\n"; +} + +?> +===DONE=== +--EXPECTF-- +UnexpectedValueException thrown +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_008.phpt b/ext/spl/tests/recursive_tree_iterator_008.phpt new file mode 100644 index 0000000..a034980 --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_008.phpt @@ -0,0 +1,41 @@ +--TEST-- +SPL: RecursiveTreeIterator::setPrefixPart() +--INI-- +error_reporting=E_ALL&~E_NOTICE +--FILE-- +<?php + +$ary = array( + "a" => array("b"), + "c" => array("d"), +); + +$it = new RecursiveArrayIterator($ary); +$it = new RecursiveTreeIterator($it); +for($i = 0; $i < 6; ++$i) { + $it->setPrefixPart($i, $i); +} +foreach($it as $k => $v) { + echo "[$k] => $v\n"; +} +try { + $it->setPrefixPart(-1, ""); + $it->setPrefixPart(6, ""); +} catch (OutOfRangeException $e) { + echo "OutOfRangeException thrown\n"; +} +try { + $it->setPrefixPart(6, ""); +} catch (OutOfRangeException $e) { + echo "OutOfRangeException thrown\n"; +} +?> +===DONE=== +--EXPECTF-- +[a] => 035Array +[0] => 0145b +[c] => 045Array +[0] => 0245d +OutOfRangeException thrown +OutOfRangeException thrown +===DONE=== diff --git a/ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt b/ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt new file mode 100644 index 0000000..81c853f --- /dev/null +++ b/ext/spl/tests/recursive_tree_iterator_setprefixpart.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: RecursiveTreeIterator::setPrefixPart() Test arguments +--CREDITS-- +Roshan Abraham (roshanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + +$arr = array( + "a" => array("b") +); + +$it = new RecursiveArrayIterator($arr); +$it = new RecursiveTreeIterator($it); + +$it->setPrefixPart(1); // Should throw a warning as setPrefixPart expects 2 arguments + +$a = new stdClass(); +$it->setPrefixPart($a, 1); // Should throw a warning as setPrefixPart expects argument 1 to be long integer + +$it->setPrefixPart(1, $a); // Should throw a warning as setPrefixPart expects argument 2 to be a string + + +?> +===DONE=== +--EXPECTF-- +Warning: RecursiveTreeIterator::setPrefixPart() expects exactly 2 parameters, 1 given in %s on line %d + +Warning: RecursiveTreeIterator::setPrefixPart() expects parameter 1 to be long, object given in %s on line %d + +Warning: RecursiveTreeIterator::setPrefixPart() expects parameter 2 to be %binary_string_optional%, object given in %s on line %d +===DONE=== diff --git a/ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt new file mode 100644 index 0000000..c9476e0 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_beginiteration_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: RecursiveIteratorIterator::beginIteration() is called by RecursiveIteratorIterator::rewind() +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1, 2); +$sub_iterator = new RecursiveArrayIterator($sample_array); + +$iterator = new RecursiveIteratorIterator($sub_iterator); +foreach ($iterator as $element) { + var_dump($element); +} + +class SkipsFirstElementRecursiveIteratorIterator extends RecursiveIteratorIterator { + public function beginIteration() { + echo "::beginIteration() was invoked\n"; + $this->next(); + } +} +$iterator = new SkipsFirstElementRecursiveIteratorIterator($sub_iterator); +foreach ($iterator as $element) { + var_dump($element); +} +?> +--EXPECT-- +int(1) +int(2) +::beginIteration() was invoked +int(2) + diff --git a/ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt new file mode 100644 index 0000000..0355401 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_enditeration_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: RecursiveIteratorIterator::endIteration() is called when ::valid() first returns false +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1, 2); +$sub_iterator = new RecursiveArrayIterator($sample_array); + +$iterator = new RecursiveIteratorIterator($sub_iterator); +foreach ($iterator as $element) { + var_dump($element); +} + +class EndIterationRecursiveIteratorIterator extends RecursiveIteratorIterator { + public function endIteration() { + echo "::endIteration() was invoked\n"; + } +} +$iterator = new EndIterationRecursiveIteratorIterator($sub_iterator); +foreach ($iterator as $element) { + var_dump($element); +} +?> +--EXPECT-- +int(1) +int(2) +int(1) +int(2) +::endIteration() was invoked + diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt new file mode 100644 index 0000000..5d1c958 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +SPL: RecursiveIteratorIterator::getSubIterator() returns iterator passed in constructor +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1, 2, array(3, 4)); + +$sub_iterator = new RecursiveArrayIterator($sample_array); +$not_sub_iterator = new RecursiveArrayIterator($sample_array); +$iterator = new RecursiveIteratorIterator($sub_iterator); + +var_dump($iterator->getSubIterator() === $sub_iterator); +var_dump($iterator->getSubIterator() === $not_sub_iterator); +?> +--EXPECT-- +bool(true) +bool(false) + diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt new file mode 100644 index 0000000..760082f --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_error.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: RecursiveIteratorIterator::getSubIterator() expects at most 1 parameter +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator(array())); +$iterator->getSubIterator(); +$iterator->getSubIterator(0); +$iterator->getSubIterator(0, 0); +?> +--EXPECTF-- +Warning: RecursiveIteratorIterator::getSubIterator() expects at most 1 parameter, 2 given in %s on line 5 + diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt new file mode 100644 index 0000000..a7b84c4 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation.phpt @@ -0,0 +1,42 @@ +--TEST-- +SPL: RecursiveIteratorIterator::getSubIterator() returns different iterators depending on the current element +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1, 2, array(3, 4)); + +$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($sample_array)); + +$iterator->next(); +$iterator->next(); +var_dump(get_class($iterator->getSubIterator())); +var_dump($iterator->getSubIterator()->getArrayCopy()); +$iterator->next(); +var_dump(get_class($iterator->getSubIterator())); +var_dump($iterator->getSubIterator()->getArrayCopy()); +?> +--EXPECTF-- +%unicode|string%(22) "RecursiveArrayIterator" +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + array(2) { + [0]=> + int(3) + [1]=> + int(4) + } +} +%unicode|string%(22) "RecursiveArrayIterator" +array(2) { + [0]=> + int(3) + [1]=> + int(4) +} + diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt new file mode 100644 index 0000000..aac4e65 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_002.phpt @@ -0,0 +1,20 @@ +--TEST-- +SPL: RecursiveIteratorIterator::getSubIterator() returns NULL if there's no current element +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1); + +$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($sample_array)); + +$iterator->next(); +var_dump(is_null($iterator->getSubIterator())); +$iterator->next(); +var_dump(is_null($iterator->getSubIterator())); +?> +--EXPECT-- +bool(false) +bool(false) + diff --git a/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt new file mode 100644 index 0000000..ff18840 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_getsubiterator_variation_003.phpt @@ -0,0 +1,42 @@ +--TEST-- +SPL: RecursiveIteratorIterator::getSubIterator() with explicit level parameter +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1, 2, array(3, 4)); + +$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($sample_array)); + +$iterator->next(); +$iterator->next(); +$iterator->next(); +var_dump($iterator->getSubIterator(-1)); +var_dump($iterator->getSubIterator(0)->getArrayCopy()); +var_dump($iterator->getSubIterator(1)->getArrayCopy()); +var_dump($iterator->getSubIterator(2)); +?> +--EXPECT-- +NULL +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + array(2) { + [0]=> + int(3) + [1]=> + int(4) + } +} +array(2) { + [0]=> + int(3) + [1]=> + int(4) +} +NULL + diff --git a/ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt b/ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt new file mode 100644 index 0000000..0bf4f19 --- /dev/null +++ b/ext/spl/tests/recursiveiteratoriterator_nextelement_basic.phpt @@ -0,0 +1,39 @@ +--TEST-- +SPL: RecursiveIteratorIterator::nextElement() is called when the next element is ready +--CREDITS-- +Matt Raines matt@raines.me.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$sample_array = array(1, 2, array(3, 4)); +$sub_iterator = new RecursiveArrayIterator($sample_array); + +$iterator = new RecursiveIteratorIterator($sub_iterator); +foreach ($iterator as $element) { + var_dump($element); +} + +class NextElementRecursiveIteratorIterator extends RecursiveIteratorIterator { + public function nextElement() { + echo "::nextElement() was invoked\n"; + } +} +$iterator = new NextElementRecursiveIteratorIterator($sub_iterator); +foreach ($iterator as $element) { + var_dump($element); +} +?> +--EXPECT-- +int(1) +int(2) +int(3) +int(4) +::nextElement() was invoked +int(1) +::nextElement() was invoked +int(2) +::nextElement() was invoked +int(3) +::nextElement() was invoked +int(4) + diff --git a/ext/spl/tests/regexIterator_flags_basic.phpt b/ext/spl/tests/regexIterator_flags_basic.phpt new file mode 100644 index 0000000..535be00 --- /dev/null +++ b/ext/spl/tests/regexIterator_flags_basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: RegexIterator::getFlags() and setFlags() basic tests +--CREDITS-- +Felix De Vliegher <felix.devliegher@gmail.com> +--FILE-- +<?php + +$array = array('foo', 'bar', 'baz'); +$iterator = new ArrayIterator($array); +$regexIterator = new RegexIterator($iterator, "/f/", null, RegexIterator::USE_KEY); + +var_dump($regexIterator->getFlags() === RegexIterator::USE_KEY); + +// Test a change in flags, there's only one class constant so it has to be another int value +$regexIterator->setFlags(3); +var_dump($regexIterator->getFlags() === RegexIterator::USE_KEY); +$regexIterator->setFlags(RegexIterator::USE_KEY); +var_dump($regexIterator->getFlags() === RegexIterator::USE_KEY); + +?> +--EXPECT-- +bool(true) +bool(false) +bool(true) diff --git a/ext/spl/tests/regexIterator_mode_basic.phpt b/ext/spl/tests/regexIterator_mode_basic.phpt new file mode 100644 index 0000000..a39b969 --- /dev/null +++ b/ext/spl/tests/regexIterator_mode_basic.phpt @@ -0,0 +1,32 @@ +--TEST-- +SPL: RegexIterator::getMode() and setMode() basic tests +--CREDITS-- +Felix De Vliegher <felix.devliegher@gmail.com> +--FILE-- +<?php + +$array = array('foo', 'bar', 'baz'); +$iterator = new ArrayIterator($array); +$regexIterator = new RegexIterator($iterator, "/f/"); + +var_dump($regexIterator->getMode() === RegexIterator::MATCH); + +$regexIterator->setMode(RegexIterator::MATCH); +var_dump($regexIterator->getMode() === RegexIterator::MATCH); + +$regexIterator->setMode(RegexIterator::GET_MATCH); +var_dump($regexIterator->getMode() === RegexIterator::GET_MATCH); + +$regexIterator->setMode(RegexIterator::ALL_MATCHES); +var_dump($regexIterator->getMode() === RegexIterator::ALL_MATCHES); + +$regexIterator->setMode(RegexIterator::SPLIT); +var_dump($regexIterator->getMode() === RegexIterator::SPLIT); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/spl/tests/regexIterator_setMode_error.phpt b/ext/spl/tests/regexIterator_setMode_error.phpt new file mode 100644 index 0000000..52af499 --- /dev/null +++ b/ext/spl/tests/regexIterator_setMode_error.phpt @@ -0,0 +1,28 @@ +--TEST-- +SPL: RegexIterator::setMode() error tests +--CREDITS-- +Felix De Vliegher <felix.devliegher@gmail.com> +--FILE-- +<?php + +$array = array('foo', 'bar', 'baz'); +$regexIterator = new RegexIterator(new ArrayIterator($array), "/f/"); + +var_dump($regexIterator->getMode()); + +try { + $regexIterator->setMode(7); +} catch (InvalidArgumentException $e) { + var_dump($e->getMessage()); + var_dump($e->getCode()); +} + +$regexIterator->setMode('foo'); + +?> +--EXPECTF-- +int(0) +string(14) "Illegal mode 7" +int(0) + +Warning: RegexIterator::setMode() expects parameter 1 to be long, string given in %s on line %d diff --git a/ext/spl/tests/regexiterator_getpregflags.phpt b/ext/spl/tests/regexiterator_getpregflags.phpt new file mode 100644 index 0000000..58a4dc4 --- /dev/null +++ b/ext/spl/tests/regexiterator_getpregflags.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: RegexIterator::getPregFlags() +--CREDITS-- +Lance Kesson jac_kesson@hotmail.com +#testfest London 2009-05-09 +--FILE-- +<?php + +class myIterator implements Iterator { + +function current (){} +function key ( ){} +function next ( ){} +function rewind ( ){} +function valid ( ){} + + +} + +class TestRegexIterator extends RegexIterator{} + +$rege = '/^a/'; + + +$r = new TestRegexIterator(new myIterator, $rege); + +$r->setPregFlags(PREG_OFFSET_CAPTURE); + +echo is_long($r->getPregFlags()); + +?> +--EXPECTF-- +1
\ No newline at end of file diff --git a/ext/spl/tests/regexiterator_getregex.phpt b/ext/spl/tests/regexiterator_getregex.phpt new file mode 100644 index 0000000..d3113a5 --- /dev/null +++ b/ext/spl/tests/regexiterator_getregex.phpt @@ -0,0 +1,29 @@ +--TEST-- +SPL: RegexIterator::getRegex() basic tests +--CREDITS-- +Joshua Thijssen <jthijssen@noxlogic.nl> +--FILE-- +<?php + +$array = array('cat', 'hat', 'sat'); +$iterator = new ArrayIterator($array); + +# Simple regex +$regexIterator = new RegexIterator($iterator, '/.at/'); +var_dump($regexIterator->getRegex()); + +# Empty regular expression +$regexIterator = new RegexIterator($iterator, '//'); +var_dump($regexIterator->getRegex()); + +# "Complex" email regular expression +$regexIterator = new RegexIterator($iterator, '|\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b|'); +var_dump($regexIterator->getRegex()); + + + +?> +--EXPECT-- +string(5) "/.at/" +string(2) "//" +string(43) "|\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b|" diff --git a/ext/spl/tests/regexiterator_setflags_exception.phpt b/ext/spl/tests/regexiterator_setflags_exception.phpt new file mode 100644 index 0000000..fdc8bca --- /dev/null +++ b/ext/spl/tests/regexiterator_setflags_exception.phpt @@ -0,0 +1,35 @@ +--TEST-- +SPL: RegexIterator::setFlags() exceptions test +--CREDITS-- +Lance Kesson jac_kesson@hotmail.com +#testfest London 2009-05-09 +--FILE-- +<?php + +class myIterator implements Iterator { + +function current (){} +function key ( ){} +function next ( ){} +function rewind ( ){} +function valid ( ){} + + +} + +class TestRegexIterator extends RegexIterator{} + +$rege = '/^a/'; + + +$r = new TestRegexIterator(new myIterator, $rege); + +try{ + $r->setFlags(); +}catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECTF-- +Warning: RegexIterator::setFlags() expects exactly 1 parameter, 0 given in %s
\ No newline at end of file diff --git a/ext/spl/tests/regexiterator_setpregflags.phpt b/ext/spl/tests/regexiterator_setpregflags.phpt new file mode 100644 index 0000000..ea1b455 --- /dev/null +++ b/ext/spl/tests/regexiterator_setpregflags.phpt @@ -0,0 +1,34 @@ +--TEST-- +SPL: RegexIterator::setPregFlags() +--CREDITS-- +Lance Kesson jac_kesson@hotmail.com +#testfest London 2009-05-09 +--FILE-- +<?php + +class myIterator implements Iterator { + +function current (){} +function key ( ){} +function next ( ){} +function rewind ( ){} +function valid ( ){} + + +} + +class TestRegexIterator extends RegexIterator{} + +$rege = '/^a/'; + + +$r = new TestRegexIterator(new myIterator, $rege); + +$r->setPregFlags(PREG_OFFSET_CAPTURE); + +echo $r->getPregFlags(); + + +?> +--EXPECTF-- +256
\ No newline at end of file diff --git a/ext/spl/tests/regexiterator_setpregflags_exception.phpt b/ext/spl/tests/regexiterator_setpregflags_exception.phpt new file mode 100644 index 0000000..cc7c17c --- /dev/null +++ b/ext/spl/tests/regexiterator_setpregflags_exception.phpt @@ -0,0 +1,36 @@ +--TEST-- +SPL: RegexIterator::getPregFlags() exception test +--CREDITS-- +Lance Kesson jac_kesson@hotmail.com +#testfest London 2009-05-09 +--FILE-- +<?php + +class myIterator implements Iterator { + +function current (){} +function key ( ){} +function next ( ){} +function rewind ( ){} +function valid ( ){} + + +} + +class TestRegexIterator extends RegexIterator{} + +$rege = '/^a/'; + + +$r = new TestRegexIterator(new myIterator, $rege); + + +try{ + $r->setPregFlags(); +}catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECTF-- +Warning: RegexIterator::setPregFlags() expects exactly 1 parameter, 0 given in %s
\ No newline at end of file diff --git a/ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt b/ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt new file mode 100644 index 0000000..cd4ea5b --- /dev/null +++ b/ext/spl/tests/splDoublyLinkedList_shift_noParams.phpt @@ -0,0 +1,15 @@ +--TEST-- +Checks that the shift() method of DoublyLinkedList does not accept args. +--CREDITS-- +PHPNW Test Fest 2009 - Rick Ogden +--FILE-- +<?php +$ll = new SplDoublyLinkedList(); +$ll->push(1); +$ll->push(2); + +var_dump($ll->shift(1)); +?> +--EXPECTF-- +Warning: SplDoublyLinkedList::shift() expects exactly 0 parameters, 1 given in %s on line %d +NULL diff --git a/ext/spl/tests/spl_001.phpt b/ext/spl/tests/spl_001.phpt new file mode 100644 index 0000000..e101272 --- /dev/null +++ b/ext/spl/tests/spl_001.phpt @@ -0,0 +1,34 @@ +--TEST-- +SPL: iterator_to_array() and iterator_count() +--FILE-- +<?php + +$it = new ArrayObject(array("x"=>1, 1=>2, 3=>3, 4, "1"=>5)); + +$ar = iterator_to_array($it); + +var_dump(iterator_count($it)); + +print_r($ar); + +foreach($ar as $v) +{ + var_dump($v); +} + +?> +===DONE=== +--EXPECT-- +int(4) +Array +( + [x] => 1 + [1] => 5 + [3] => 3 + [4] => 4 +) +int(1) +int(5) +int(3) +int(4) +===DONE=== diff --git a/ext/spl/tests/spl_002.phpt b/ext/spl/tests/spl_002.phpt new file mode 100644 index 0000000..d8b71b2 --- /dev/null +++ b/ext/spl/tests/spl_002.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: Countable +--FILE-- +<?php + +class Test implements Countable +{ + function count() + { + return 4; + } +}; + +$a = new Test; + +var_dump(count($a)); + +?> +===DONE=== +--EXPECT-- +int(4) +===DONE=== diff --git a/ext/spl/tests/spl_003.phpt b/ext/spl/tests/spl_003.phpt new file mode 100644 index 0000000..e92a41a --- /dev/null +++ b/ext/spl/tests/spl_003.phpt @@ -0,0 +1,74 @@ +--TEST-- +SPL: class_parents() and class_implements() +--FILE-- +<?php +class a{} +class b extends a{} +class c extends b{} +class d{} +var_dump(class_parents(new c), + class_parents("c"), + class_parents(new b), + class_parents("b"), + class_parents("d"), + class_parents("foo", 0), + class_parents("foo", 1) +); + +interface iface1{} +interface iface2{} +class f implements iface1, iface2{} +var_dump(class_implements(new a), + class_implements("a"), + class_implements("aaa"), + class_implements("bbb", 0) +); + +function __autoload($cname) { + var_dump($cname); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Warning: class_parents(): Class foo does not exist in %sspl_003.php on line %d +string(3) "foo" + +Warning: class_parents(): Class foo does not exist and could not be loaded in %sspl_003.php on line %d +array(2) { + ["b"]=> + string(1) "b" + ["a"]=> + string(1) "a" +} +array(2) { + ["b"]=> + string(1) "b" + ["a"]=> + string(1) "a" +} +array(1) { + ["a"]=> + string(1) "a" +} +array(1) { + ["a"]=> + string(1) "a" +} +array(0) { +} +bool(false) +bool(false) +string(3) "aaa" + +Warning: class_implements(): Class aaa does not exist and could not be loaded in %sspl_003.php on line %d + +Warning: class_implements(): Class bbb does not exist in %sspl_003.php on line %d +array(0) { +} +array(0) { +} +bool(false) +bool(false) +===DONE=== diff --git a/ext/spl/tests/spl_004.phpt b/ext/spl/tests/spl_004.phpt new file mode 100644 index 0000000..97896f8 --- /dev/null +++ b/ext/spl/tests/spl_004.phpt @@ -0,0 +1,84 @@ +--TEST-- +SPL: iterator_apply() +--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); ?> +--EXPECT-- +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 of the type array, integer given +Error: iterator_apply() expects parameter 3 to be array, integer given +NULL +Error: iterator_apply() expects parameter 2 to be a valid callback, function 'non_existing_functon' not found or invalid function name +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 100644 index 0000000..219c791 --- /dev/null +++ b/ext/spl/tests/spl_005.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: spl_object_hash() +--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=== diff --git a/ext/spl/tests/spl_006.phpt b/ext/spl/tests/spl_006.phpt new file mode 100644 index 0000000..1f5f85f --- /dev/null +++ b/ext/spl/tests/spl_006.phpt @@ -0,0 +1,39 @@ +--TEST-- +SPL: iterator_to_array() without keys +--FILE-- +<?php + +$it = new AppendIterator(); +$it->append(new ArrayIterator(array(1,2))); +$it->append(new ArrayIterator(array(2,3))); + +var_dump(iterator_to_array($it)); +var_dump(iterator_to_array($it, false)); +var_dump(iterator_to_array($it, true)); + +?> +===DONE=== +--EXPECT-- +array(2) { + [0]=> + int(2) + [1]=> + int(3) +} +array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(2) + [3]=> + int(3) +} +array(2) { + [0]=> + int(2) + [1]=> + int(3) +} +===DONE=== diff --git a/ext/spl/tests/spl_007.phpt b/ext/spl/tests/spl_007.phpt new file mode 100644 index 0000000..6d4059d --- /dev/null +++ b/ext/spl/tests/spl_007.phpt @@ -0,0 +1,24 @@ +--TEST-- +SPL: iterator_apply() with callback using __call() +--FILE-- +<?php + +class Foo { + public function __call($name, $params) { + echo "Called $name.\n"; + return true; + } +} + +$it = new ArrayIterator(array(1, 2, 3)); + +iterator_apply($it, array(new Foo, "foobar")); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +Called foobar. +Called foobar. +Called foobar. +===DONE=== diff --git a/ext/spl/tests/spl_autoload_001.phpt b/ext/spl/tests/spl_autoload_001.phpt new file mode 100644 index 0000000..ff9d1e9 --- /dev/null +++ b/ext/spl/tests/spl_autoload_001.phpt @@ -0,0 +1,136 @@ +--TEST-- +SPL: spl_autoload() and friends +--INI-- +include_path=. +--FILE-- +<?php + +echo "===EMPTY===\n"; + +var_dump(spl_autoload_extensions()); + +try +{ + spl_autoload("TestClass"); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +$test_exts = array(NULL, "1", ".inc,,.php.inc", ""); + +foreach($test_exts as $exts) +{ + echo "===($exts)===\n"; + try + { + spl_autoload("TestClass", $exts); + } + catch(Exception $e) + { + echo 'Exception: ' . $e->getMessage() . "\n"; + } +} + +try +{ + spl_autoload_extensions(".inc,.php.inc"); + spl_autoload("TestClass"); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +function TestFunc1($classname) +{ + echo __METHOD__ . "($classname)\n"; +} + +function TestFunc2($classname) +{ + echo __METHOD__ . "($classname)\n"; +} + +echo "===SPL_AUTOLOAD()===\n"; + +spl_autoload_register(); + +try +{ + var_dump(spl_autoload_extensions(".inc")); + var_dump(class_exists("TestClass", true)); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +echo "===REGISTER===\n"; + +spl_autoload_unregister("spl_autoload"); +spl_autoload_register("TestFunc1"); +spl_autoload_register("TestFunc2"); +spl_autoload_register("TestFunc2"); /* 2nd call ignored */ +spl_autoload_extensions(".inc,.class.inc"); /* we do not have spl_autoload_registered yet */ + +try +{ + var_dump(class_exists("TestClass", true)); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +echo "===LOAD===\n"; + +spl_autoload_register("spl_autoload"); +var_dump(class_exists("TestClass", true)); + +echo "===NOFUNCTION===\n"; + +try +{ + spl_autoload_register("unavailable_autoload_function"); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +===EMPTY=== +string(9) ".inc,.php" +%stestclass.inc +Exception: Class TestClass could not be loaded +===()=== +Exception: Class TestClass could not be loaded +===(1)=== +Exception: Class TestClass could not be loaded +===(.inc,,.php.inc)=== +%stestclass +%stestclass.php.inc +Exception: Class TestClass could not be loaded +===()=== +Exception: Class TestClass could not be loaded +Exception: Class TestClass could not be loaded +===SPL_AUTOLOAD()=== +string(4) ".inc" +Exception: Class TestClass could not be loaded +===REGISTER=== +TestFunc1(TestClass) +TestFunc2(TestClass) +bool(false) +===LOAD=== +TestFunc1(TestClass) +TestFunc2(TestClass) +%stestclass.class.inc +bool(true) +===NOFUNCTION=== +Exception: Function 'unavailable_autoload_function' not found (function 'unavailable_autoload_function' not found or invalid function name) +===DONE=== diff --git a/ext/spl/tests/spl_autoload_002.phpt b/ext/spl/tests/spl_autoload_002.phpt new file mode 100644 index 0000000..2373d6d --- /dev/null +++ b/ext/spl/tests/spl_autoload_002.phpt @@ -0,0 +1,70 @@ +--TEST-- +SPL: spl_autoload_functions() +--SKIPIF-- +<?php +if (spl_autoload_functions() !== false) die('skip __autoload() registered by php.ini'); +?> +--FILE-- +<?php + +function SplAutoloadTest1($name) {} +function SplAutoloadTest2($name) {} + +var_dump(spl_autoload_functions()); + +spl_autoload_register(); + +var_dump(spl_autoload_functions()); + +spl_autoload_register('SplAutoloadTest1'); +spl_autoload_register('SplAutoloadTest2'); +spl_autoload_register('SplAutoloadTest1'); + +var_dump(spl_autoload_functions()); + +spl_autoload_unregister('SplAutoloadTest1'); + +var_dump(spl_autoload_functions()); + +spl_autoload_unregister('spl_autoload_call'); + +var_dump(spl_autoload_functions()); + +spl_autoload_register(); + +var_dump(spl_autoload_functions()); + +spl_autoload_unregister('spl_autoload'); + +var_dump(spl_autoload_functions()); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +bool(false) +array(1) { + [0]=> + string(12) "spl_autoload" +} +array(3) { + [0]=> + string(12) "spl_autoload" + [1]=> + string(16) "SplAutoloadTest1" + [2]=> + string(16) "SplAutoloadTest2" +} +array(2) { + [0]=> + string(12) "spl_autoload" + [1]=> + string(16) "SplAutoloadTest2" +} +bool(false) +array(1) { + [0]=> + string(12) "spl_autoload" +} +bool(false) +===DONE=== diff --git a/ext/spl/tests/spl_autoload_003.phpt b/ext/spl/tests/spl_autoload_003.phpt new file mode 100644 index 0000000..7c0bd1a --- /dev/null +++ b/ext/spl/tests/spl_autoload_003.phpt @@ -0,0 +1,45 @@ +--TEST-- +SPL: spl_autoload() and friends +--INI-- +include_path=. +--FILE-- +<?php + +function TestFunc1($classname) +{ + echo __METHOD__ . "($classname)\n"; +} + +function TestFunc2($classname) +{ + echo __METHOD__ . "($classname)\n"; + throw new Exception("Class $classname missing"); +} + +function TestFunc3($classname) +{ + echo __METHOD__ . "($classname)\n"; +} + +spl_autoload_register("TestFunc1"); +spl_autoload_register("TestFunc2"); +spl_autoload_register("TestFunc3"); + +try +{ + var_dump(class_exists("TestClass", true)); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +TestFunc1(TestClass) +TestFunc2(TestClass) +TestFunc3(TestClass) +Exception: Class TestClass missing +===DONE=== diff --git a/ext/spl/tests/spl_autoload_004.phpt b/ext/spl/tests/spl_autoload_004.phpt new file mode 100644 index 0000000..1f26521 --- /dev/null +++ b/ext/spl/tests/spl_autoload_004.phpt @@ -0,0 +1,43 @@ +--TEST-- +SPL: spl_autoload() with static methods +--INI-- +include_path=. +--FILE-- +<?php + +class MyAutoLoader { + + static function autoLoad($className) { + echo __METHOD__ . "($className)\n"; + } +} + +spl_autoload_register(array('MyAutoLoader', 'autoLoad')); + +// and + +$myAutoLoader = new MyAutoLoader(); + +spl_autoload_register(array($myAutoLoader, 'autoLoad')); + +var_dump(spl_autoload_functions()); + +// check +var_dump(class_exists("TestClass", true)); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +array(1) { + [0]=> + array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "autoLoad" + } +} +MyAutoLoader::autoLoad(TestClass) +bool(false) +===DONE=== diff --git a/ext/spl/tests/spl_autoload_005.phpt b/ext/spl/tests/spl_autoload_005.phpt new file mode 100644 index 0000000..f4db521 --- /dev/null +++ b/ext/spl/tests/spl_autoload_005.phpt @@ -0,0 +1,55 @@ +--TEST-- +SPL: spl_autoload() with methods +--INI-- +include_path=. +--FILE-- +<?php + +class MyAutoLoader { + + function autoLoad($className) + { + echo __METHOD__ . "($className)\n"; + } + + function autoThrow($className) + { + echo __METHOD__ . "($className)\n"; + throw new Exception("Unavailable"); + } +} + +try +{ + spl_autoload_register(array('MyAutoLoader', 'autoLoad'), true); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +// and + +$myAutoLoader = new MyAutoLoader(); + +spl_autoload_register(array($myAutoLoader, 'autoLoad')); +spl_autoload_register(array($myAutoLoader, 'autoThrow')); + +try +{ + var_dump(class_exists("TestClass", true)); +} +catch(Exception $e) +{ + echo 'Exception: ' . $e->getMessage() . "\n"; +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +Exception: Passed array specifies a non static method but no object (non-static method MyAutoLoader::autoLoad() should not be called statically) +MyAutoLoader::autoLoad(TestClass) +MyAutoLoader::autoThrow(TestClass) +Exception: Unavailable +===DONE=== diff --git a/ext/spl/tests/spl_autoload_006.phpt b/ext/spl/tests/spl_autoload_006.phpt new file mode 100644 index 0000000..21a6084 --- /dev/null +++ b/ext/spl/tests/spl_autoload_006.phpt @@ -0,0 +1,37 @@ +--TEST-- +SPL: spl_autoload() with static methods +--INI-- +include_path=. +--FILE-- +<?php + +class MyAutoLoader { + + static function autoLoad($className) { + echo __METHOD__ . "($className)\n"; + } +} + +spl_autoload_register('MyAutoLoader::autoLoad'); + +var_dump(spl_autoload_functions()); + +// check +var_dump(class_exists("TestClass", true)); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +array(1) { + [0]=> + array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "autoLoad" + } +} +MyAutoLoader::autoLoad(TestClass) +bool(false) +===DONE=== diff --git a/ext/spl/tests/spl_autoload_007.phpt b/ext/spl/tests/spl_autoload_007.phpt new file mode 100644 index 0000000..1a81f19 --- /dev/null +++ b/ext/spl/tests/spl_autoload_007.phpt @@ -0,0 +1,138 @@ +--TEST-- +SPL: spl_autoload() with inaccessible methods +--INI-- +include_path=. +--FILE-- +<?php + +class MyAutoLoader { + + static protected function noAccess($className) { + echo __METHOD__ . "($className)\n"; + } + + static function autoLoad($className) { + echo __METHOD__ . "($className)\n"; + } + + function dynaLoad($className) { + echo __METHOD__ . "($className)\n"; + } +} + +$obj = new MyAutoLoader; + +$funcs = array( + 'MyAutoLoader::notExist', + 'MyAutoLoader::noAccess', + 'MyAutoLoader::autoLoad', + 'MyAutoLoader::dynaLoad', + array('MyAutoLoader', 'notExist'), + array('MyAutoLoader', 'noAccess'), + array('MyAutoLoader', 'autoLoad'), + array('MyAutoLoader', 'dynaLoad'), + array($obj, 'notExist'), + array($obj, 'noAccess'), + array($obj, 'autoLoad'), + array($obj, 'dynaLoad'), +); + +foreach($funcs as $idx => $func) +{ + if ($idx) echo "\n"; + try + { + var_dump($func); + spl_autoload_register($func); + echo "ok\n"; + } + catch (Exception $e) + { + echo $e->getMessage() . "\n"; + } +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +string(22) "MyAutoLoader::notExist" +Function 'MyAutoLoader::notExist' not found (class 'MyAutoLoader' does not have a method 'notExist') + +string(22) "MyAutoLoader::noAccess" +Function 'MyAutoLoader::noAccess' not callable (cannot access protected method MyAutoLoader::noAccess()) + +string(22) "MyAutoLoader::autoLoad" +ok + +string(22) "MyAutoLoader::dynaLoad" +Function 'MyAutoLoader::dynaLoad' not callable (non-static method MyAutoLoader::dynaLoad() should not be called statically) + +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "notExist" +} +Passed array does not specify an existing static method (class 'MyAutoLoader' does not have a method 'notExist') + +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "noAccess" +} +Passed array does not specify a callable static method (cannot access protected method MyAutoLoader::noAccess()) + +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "autoLoad" +} +ok + +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "dynaLoad" +} +Passed array specifies a non static method but no object (non-static method MyAutoLoader::dynaLoad() should not be called statically) + +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "notExist" +} +Passed array does not specify an existing method (class 'MyAutoLoader' does not have a method 'notExist') + +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "noAccess" +} +Passed array does not specify a callable method (cannot access protected method MyAutoLoader::noAccess()) + +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "autoLoad" +} +ok + +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "dynaLoad" +} +ok +===DONE=== diff --git a/ext/spl/tests/spl_autoload_008.phpt b/ext/spl/tests/spl_autoload_008.phpt new file mode 100644 index 0000000..4b10351 --- /dev/null +++ b/ext/spl/tests/spl_autoload_008.phpt @@ -0,0 +1,129 @@ +--TEST-- +SPL: spl_autoload() with exceptions +--INI-- +include_path=. +--FILE-- +<?php + +function MyAutoLoad($className) +{ + echo __METHOD__ . "($className)\n"; + throw new Exception('Bla'); +} + +class MyAutoLoader +{ + static function autoLoad($className) + { + echo __METHOD__ . "($className)\n"; + throw new Exception('Bla'); + } + + function dynaLoad($className) + { + echo __METHOD__ . "($className)\n"; + throw new Exception('Bla'); + } +} + +$obj = new MyAutoLoader; + +$funcs = array( + 'MyAutoLoad', + 'MyAutoLoader::autoLoad', + 'MyAutoLoader::dynaLoad', + array('MyAutoLoader', 'autoLoad'), + array('MyAutoLoader', 'dynaLoad'), + array($obj, 'autoLoad'), + array($obj, 'dynaLoad'), +); + +foreach($funcs as $idx => $func) +{ + echo "====$idx====\n"; + + try + { + var_dump($func); + spl_autoload_register($func); + if (count(spl_autoload_functions())) + { + echo "registered\n"; + + var_dump(class_exists("NoExistingTestClass", true)); + } + } + catch (Exception $e) + { + echo get_class($e) . ": " . $e->getMessage() . "\n"; + } + + spl_autoload_unregister($func); + var_dump(count(spl_autoload_functions())); +} + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +====0==== +string(10) "MyAutoLoad" +registered +MyAutoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====1==== +string(22) "MyAutoLoader::autoLoad" +registered +MyAutoLoader::autoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====2==== +string(22) "MyAutoLoader::dynaLoad" +LogicException: Function 'MyAutoLoader::dynaLoad' not callable (non-static method MyAutoLoader::dynaLoad() should not be called statically) +int(0) +====3==== +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "autoLoad" +} +registered +MyAutoLoader::autoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====4==== +array(2) { + [0]=> + string(12) "MyAutoLoader" + [1]=> + string(8) "dynaLoad" +} +LogicException: Passed array specifies a non static method but no object (non-static method MyAutoLoader::dynaLoad() should not be called statically) +int(0) +====5==== +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "autoLoad" +} +registered +MyAutoLoader::autoLoad(NoExistingTestClass) +Exception: Bla +int(0) +====6==== +array(2) { + [0]=> + object(MyAutoLoader)#%d (0) { + } + [1]=> + string(8) "dynaLoad" +} +registered +MyAutoLoader::dynaLoad(NoExistingTestClass) +Exception: Bla +int(0) +===DONE=== diff --git a/ext/spl/tests/spl_autoload_009.phpt b/ext/spl/tests/spl_autoload_009.phpt new file mode 100644 index 0000000..d5e5413 --- /dev/null +++ b/ext/spl/tests/spl_autoload_009.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: spl_autoload() and friends +--INI-- +include_path=. +--FILE-- +<?php + +function my_autoload($name) +{ + require $name . '.class.inc'; + var_dump(class_exists($name)); +} + +spl_autoload_register("spl_autoload"); +spl_autoload_register("my_autoload"); + +$obj = new testclass; + +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +%stestclass.inc +%stestclass.class.inc +bool(true) +===DONE=== diff --git a/ext/spl/tests/spl_autoload_010.phpt b/ext/spl/tests/spl_autoload_010.phpt new file mode 100644 index 0000000..cd70bdc --- /dev/null +++ b/ext/spl/tests/spl_autoload_010.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: spl_autoload() and prepend +--INI-- +include_path=. +--FILE-- +<?php +function autoloadA($name) { + echo "A -> $name\n"; +} +function autoloadB($name) { + echo "B -> $name\n"; +} +function autoloadC($name) { + echo "C -> $name\n"; + class C{} +} + +spl_autoload_register('autoloadA'); +spl_autoload_register('autoloadB', true, true); +spl_autoload_register('autoloadC'); + +new C; +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +B -> C +A -> C +C -> C +===DONE=== diff --git a/ext/spl/tests/spl_autoload_011.phpt b/ext/spl/tests/spl_autoload_011.phpt new file mode 100644 index 0000000..5a99255 --- /dev/null +++ b/ext/spl/tests/spl_autoload_011.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: spl_autoload() and object freed +--INI-- +include_path=. +--FILE-- +<?php +class A { + public $var = 1; + public function autoload() { + echo "var:".$this->var."\n"; + } + public function __destruct() { + echo "__destruct__\n"; + } +} + +$a = new A; +$a->var = 2; + +spl_autoload_register(array($a, 'autoload')); +unset($a); + +var_dump(class_exists("C", true)); +?> +===DONE=== +<?php exit(0); ?> +--EXPECTF-- +var:2 +bool(false) +===DONE=== +__destruct__ diff --git a/ext/spl/tests/spl_autoload_012.phpt b/ext/spl/tests/spl_autoload_012.phpt new file mode 100644 index 0000000..e07f0e4 --- /dev/null +++ b/ext/spl/tests/spl_autoload_012.phpt @@ -0,0 +1,65 @@ +--TEST-- +SPL: spl_autoload() capturing multiple Exceptions in __autoload +--FILE-- +<?php + +function autoload_first($name) +{ + echo __METHOD__ . "\n"; + throw new Exception('first'); +} + +function autoload_second($name) +{ + echo __METHOD__ . "\n"; + throw new Exception('second'); +} + +spl_autoload_register('autoload_first'); +spl_autoload_register('autoload_second'); + +try { + class_exists('ThisClassDoesNotExist'); +} catch(Exception $e) { + do { + echo $e->getMessage()."\n"; + } while($e = $e->getPrevious()); +} + +try { + new ThisClassDoesNotExist; +} catch(Exception $e) { + do { + echo $e->getMessage()."\n"; + } while($e = $e->getPrevious()); +} + +class_exists('ThisClassDoesNotExist'); +?> +===DONE=== +--EXPECTF-- +autoload_first +autoload_second +second +first +autoload_first +autoload_second +second +first +autoload_first +autoload_second + +Fatal error: Uncaught exception 'Exception' with message 'first' in %sspl_autoload_012.php:%d +Stack trace: +#0 [internal function]: autoload_first('ThisClassDoesNo...') +#1 [internal function]: spl_autoload_call('ThisClassDoesNo...') +#2 %sspl_autoload_012.php(%d): class_exists('ThisClassDoesNo...') +#3 {main} + +Next exception 'Exception' with message 'second' in %sspl_autoload_012.php:%d +Stack trace: +#0 [internal function]: autoload_second('ThisClassDoesNo...') +#1 [internal function]: spl_autoload_call('ThisClassDoesNo...') +#2 %sspl_autoload_012.php(%d): class_exists('ThisClassDoesNo...') +#3 {main} + thrown in %sspl_autoload_012.php on line %d diff --git a/ext/spl/tests/spl_autoload_013.phpt b/ext/spl/tests/spl_autoload_013.phpt new file mode 100644 index 0000000..44d4d85 --- /dev/null +++ b/ext/spl/tests/spl_autoload_013.phpt @@ -0,0 +1,51 @@ +--TEST-- +SPL: spl_autoload_functions() with closures and invokables +--FILE-- +<?php +$closure = function($class) { + echo "a called\n"; +}; + +class Autoloader { + private $dir; + public function __construct($dir) { + $this->dir = $dir; + } + public function __invoke($class) { + var_dump("{$this->dir}/$class.php"); + } +} + +$al1 = new Autoloader('d1'); +$al2 = new Autoloader('d2'); + +spl_autoload_register($closure); +spl_autoload_register($al1); +spl_autoload_register($al2); + +var_dump(spl_autoload_functions()); + +?> +===DONE=== +--EXPECTF-- +array(3) { + [0]=> + object(Closure)#%d (1) { + ["parameter"]=> + array(1) { + ["$class"]=> + string(10) "<required>" + } + } + [1]=> + object(Autoloader)#%d (1) { + ["dir":"Autoloader":private]=> + string(2) "d1" + } + [2]=> + object(Autoloader)#%d (1) { + ["dir":"Autoloader":private]=> + string(2) "d2" + } +} +===DONE===
\ No newline at end of file diff --git a/ext/spl/tests/spl_autoload_014.phpt b/ext/spl/tests/spl_autoload_014.phpt new file mode 100644 index 0000000..a68fcb7 --- /dev/null +++ b/ext/spl/tests/spl_autoload_014.phpt @@ -0,0 +1,47 @@ +--TEST-- +SPL: spl_autoload_unregister() with closures and invokables +--FILE-- +<?php +$closure = function($class) { + echo "closure called with class $class\n"; +}; + +class Autoloader { + private $dir; + public function __construct($dir) { + $this->dir = $dir; + } + public function __invoke($class) { + echo ("Autoloader('{$this->dir}') called with $class\n"); + } +} + +class WorkingAutoloader { + public function __invoke($class) { + echo ("WorkingAutoloader() called with $class\n"); + eval("class $class { }"); + } +} + +$al1 = new Autoloader('d1'); +$al2 = new WorkingAutoloader('d2'); + +spl_autoload_register($closure); +spl_autoload_register($al1); +spl_autoload_register($al2); + +$x = new TestX; + +spl_autoload_unregister($closure); +spl_autoload_unregister($al1); + +$y = new TestY; + +?> +===DONE=== +--EXPECT-- +closure called with class TestX +Autoloader('d1') called with TestX +WorkingAutoloader() called with TestX +WorkingAutoloader() called with TestY +===DONE===
\ No newline at end of file diff --git a/ext/spl/tests/spl_autoload_bug48541.phpt b/ext/spl/tests/spl_autoload_bug48541.phpt new file mode 100644 index 0000000..9937a7f --- /dev/null +++ b/ext/spl/tests/spl_autoload_bug48541.phpt @@ -0,0 +1,39 @@ +--TEST-- +SPL: spl_autoload_register() Bug #48541: registering multiple closures fails with memleaks +--FILE-- +<?php + +class X { + public function getClosure() { + return function($class) { + echo "a2 called\n"; + }; + } +} + +$a = function ($class) { + echo "a called\n"; +}; +$x = new X; +$a2 = $x->getClosure(); +$b = function ($class) { + eval('class ' . $class . '{function __construct(){echo "foo\n";}}'); + echo "b called\n"; +}; +spl_autoload_register($a); +spl_autoload_register($a2); +spl_autoload_register($b); + +$c = $a; +$c2 = $a2; +spl_autoload_register($c); +spl_autoload_register($c2); +$c = new foo; +?> +===DONE=== +--EXPECT-- +a called +a2 called +b called +foo +===DONE===
\ No newline at end of file diff --git a/ext/spl/tests/spl_autoload_call_basic.phpt b/ext/spl/tests/spl_autoload_call_basic.phpt new file mode 100644 index 0000000..2bd65c2 --- /dev/null +++ b/ext/spl/tests/spl_autoload_call_basic.phpt @@ -0,0 +1,18 @@ +--TEST-- +spl_autoload_call() function - basic test for spl_autoload_call() +--CREDITS-- +Jean-Marc Fontaine <jean-marc.fontaine@alterway.fr> +# Alter Way Contribution Day 2011 +--FILE-- +<?php +function customAutolader($class) { + require_once __DIR__ . '/testclass.class.inc'; +} +spl_autoload_register('customAutolader'); + +spl_autoload_call('TestClass'); +var_dump(class_exists('TestClass', false)); +?> +--EXPECTF-- +%stestclass.class.inc +bool(true) diff --git a/ext/spl/tests/spl_caching_iterator_constructor_flags.phpt b/ext/spl/tests/spl_caching_iterator_constructor_flags.phpt new file mode 100644 index 0000000..499cd67 --- /dev/null +++ b/ext/spl/tests/spl_caching_iterator_constructor_flags.phpt @@ -0,0 +1,25 @@ +--TEST-- +SPL: CachingInterator constructor flag checks +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + //line 681 ... + $array = array(array(7,8,9),1,2,3,array(4,5,6)); +$arrayIterator = new ArrayIterator($array); +try { +$test = new CachingIterator($arrayIterator, 0); +$test = new CachingIterator($arrayIterator, 1); +$test = new CachingIterator($arrayIterator, 2); +$test = new CachingIterator($arrayIterator, 3); // this throws an exception +} catch (InvalidArgumentException $e){ + print $e->getMessage() . "\n"; +} + + +?> +===DONE=== +--EXPECTF-- +Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_CURRENT +===DONE=== diff --git a/ext/spl/tests/spl_cachingiterator___toString_basic.phpt b/ext/spl/tests/spl_cachingiterator___toString_basic.phpt new file mode 100644 index 0000000..0395b37 --- /dev/null +++ b/ext/spl/tests/spl_cachingiterator___toString_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: SplCachingIterator, Test method to convert current element to string +--CREDITS-- +Chris Scott chris.scott@nstein.com +#testfest London 2009-05-09 +--FILE-- +<?php + +$ai = new ArrayIterator(array(new stdClass(), new stdClass())); +$ci = new CachingIterator($ai); +var_dump( +$ci->__toString() // if conversion to string is done by echo, for example, an exeption is thrown. Invoking __toString explicitly covers different code. +); +?> +--EXPECTF-- +NULL diff --git a/ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt b/ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt new file mode 100644 index 0000000..126586b --- /dev/null +++ b/ext/spl/tests/spl_cachingiterator_setFlags_basic.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: SplCachingIterator, Test method to set flags for caching iterator +--CREDITS-- +Chris Scott chris.scott@nstein.com +#testfest London 2009-05-09 +--FILE-- +<?php + +$ai = new ArrayIterator(array('foo', 'bar')); + +$ci = new CachingIterator($ai); +$ci->setFlags(); //expects arg + +?> +--EXPECTF-- +Warning: CachingIterator::setFlags() expects exactly 1 parameter, %s diff --git a/ext/spl/tests/spl_classes.phpt b/ext/spl/tests/spl_classes.phpt new file mode 100644 index 0000000..172c4ab --- /dev/null +++ b/ext/spl/tests/spl_classes.phpt @@ -0,0 +1,13 @@ +--TEST-- +SPL: spl_classes() function +--CREDITS-- +Sebastian Schürmann +sebs@php.net +Testfest 2009 Munich +--FILE-- +<?php +var_dump(is_array(spl_classes())); +?> +--EXPECT-- +bool(true) + diff --git a/ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt b/ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt new file mode 100644 index 0000000..cee557e --- /dev/null +++ b/ext/spl/tests/spl_fileinfo_getlinktarget_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: Spl File Info test getLinkTarget +--CREDITS-- +Nataniel McHugh nat@fishtrap.co.uk +--SKIPIF-- +<?php +if (substr(PHP_OS, 0, 3) == 'WIN') die("skip this test not for Windows platforms"); +?> +--FILE-- +<?php +$link = __DIR__ . '/test_link'; +symlink(__FILE__, $link ); +$fileInfo = new SplFileInfo($link); + +if ($fileInfo->isLink()) { + echo $fileInfo->getLinkTarget() == __FILE__ ? 'same' : 'different',PHP_EOL; +} +var_dump(unlink($link)); +?> +--EXPECT-- +same +bool(true) diff --git a/ext/spl/tests/spl_heap_count_basic.phpt b/ext/spl/tests/spl_heap_count_basic.phpt new file mode 100644 index 0000000..6e6baf6 --- /dev/null +++ b/ext/spl/tests/spl_heap_count_basic.phpt @@ -0,0 +1,35 @@ +--TEST-- +SPL: SplHeap, Test spl_heap_object_count_elements (spl_heap.c:490) for returning count() failure for Heaps +--CREDITS-- +Chris Scott chris.scott@nstein.com +#testfest London 2009-05-09 +--FILE-- +<?php + +class MyHeap extends SplHeap +{ + public function compare($a,$b) + { + return ($a < $b); + } + + public function count() // override count to force failure + { + throw new Exception('Cause count to fail'); + return parent::count(); + } +} + + +$heap = new MyHeap(); +$heap->insert(1); +count($heap);// refers to MyHeap->count() method + +?> +--EXPECTF-- +Fatal error: Uncaught exception 'Exception' with message 'Cause count to fail' in %s +Stack trace: +#0 [internal function]: MyHeap->count() +#1 %s count(Object(MyHeap)) +#2 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/spl_heap_count_error.phpt b/ext/spl/tests/spl_heap_count_error.phpt new file mode 100644 index 0000000..6bed4cf --- /dev/null +++ b/ext/spl/tests/spl_heap_count_error.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: Priority queue count, illegal number of args +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +$h = new SplPriorityQueue(); +$h->count(1); +?> +--EXPECTF-- +Warning: SplPriorityQueue::count() expects exactly 0 parameters, 1 given in %s diff --git a/ext/spl/tests/spl_heap_extract_parameter_error.phpt b/ext/spl/tests/spl_heap_extract_parameter_error.phpt new file mode 100644 index 0000000..aecd03d --- /dev/null +++ b/ext/spl/tests/spl_heap_extract_parameter_error.phpt @@ -0,0 +1,27 @@ +--TEST-- +SPL: Heap and extract with parameter +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + +class TestHeap extends SplHeap { + + function compare() { + print "This shouldn't be printed"; + } +} + +$testHeap = new TestHeap(); + + + +var_dump($testHeap->extract('test')); + +?> +===DONE=== +--EXPECTF-- +Warning: SplHeap::extract() expects exactly 0 parameters, 1 given in %s on line 14 +NULL +===DONE=== diff --git a/ext/spl/tests/spl_heap_insert_basic.phpt b/ext/spl/tests/spl_heap_insert_basic.phpt new file mode 100644 index 0000000..76a34b2 --- /dev/null +++ b/ext/spl/tests/spl_heap_insert_basic.phpt @@ -0,0 +1,20 @@ +--TEST-- +SPL: SplHeap, Test method to insert into heap +--CREDITS-- +Chris Scott chris.scott@nstein.com +#testfest London 2009-05-09 +--FILE-- +<?php +class MyHeap extends SplHeap +{ + public function compare($a, $b) + { + return $a < $b; + } +} + +$heap = new MyHeap(); +$heap->insert(1,2); +?> +--EXPECTF-- +Warning: SplHeap::insert() expects exactly 1 parameter, %s diff --git a/ext/spl/tests/spl_heap_is_empty_basic.phpt b/ext/spl/tests/spl_heap_is_empty_basic.phpt new file mode 100644 index 0000000..47d7ccc --- /dev/null +++ b/ext/spl/tests/spl_heap_is_empty_basic.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: SplHeap, test trivial method to find if a heap is empty +--CREDITS-- +Nathaniel McHugh nat@fishtrap.co.uk +#testfest London 2009-05-09 +--FILE-- +<?php + +class MyHeap extends SplHeap{ + +public function compare($a, $b){ +return $a < $b; +} + +} + + +$heap = new MyHeap(); +var_dump($heap->isEmpty()); +$heap->insert(1); +var_dump($heap->isEmpty()); +$heap->extract(); +var_dump($heap->isEmpty()); +$heap->isEmpty('var'); +?> +--EXPECTF-- +bool(true) +bool(false) +bool(true) + +Warning: SplHeap::isEmpty() expects exactly 0 parameters, 1 given in %s diff --git a/ext/spl/tests/spl_heap_isempty.phpt b/ext/spl/tests/spl_heap_isempty.phpt new file mode 100644 index 0000000..2729c7f --- /dev/null +++ b/ext/spl/tests/spl_heap_isempty.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: Test of isEmpty for SPL Max Heap +--CREDITS-- +Rohan Abraham (rohanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + $h = new SplMaxHeap(); + echo "Checking a new heap is empty: "; + var_dump($h->isEmpty())."\n"; + $h->insert(2); + echo "Checking after insert: "; + var_dump($h->isEmpty())."\n"; + $h->extract(); + echo "Checking after extract: "; + var_dump($h->isEmpty())."\n"; +?> +--EXPECT-- +Checking a new heap is empty: bool(true) +Checking after insert: bool(false) +Checking after extract: bool(true)
\ No newline at end of file diff --git a/ext/spl/tests/spl_heap_iteration_error.phpt b/ext/spl/tests/spl_heap_iteration_error.phpt new file mode 100644 index 0000000..62e462f --- /dev/null +++ b/ext/spl/tests/spl_heap_iteration_error.phpt @@ -0,0 +1,53 @@ +--TEST-- +SPL: Attempt to corrupt the heap while iterating +--CREDITS-- +Lukasz Andrzejak meltir@meltir.com +#testfest London 2009-05-09 +--FILE-- +<?php +class ext_heap extends SplMaxHeap { + public $fail = false; + public function compare($val1,$val2) { + if ($this->fail) + throw new Exception('Corrupting heap',99); + return 0; + } +} + +$h = new ext_heap(); +$h->insert(array('foobar')); +$h->insert(array('foobar1')); +$h->insert(array('foobar2')); + +try { + $h->fail=true; + foreach ($h as $value) {}; + echo "I should have raised an exception here"; +} catch (Exception $e) { + if ($e->getCode()!=99) echo "Unexpected exception"; +} + +var_dump($h); +?> +--EXPECTF-- +object(ext_heap)#%d (4) { + [%u|b%"fail"]=> + bool(true) + [%u|b%"flags":%u|b%"SplHeap":private]=> + int(0) + [%u|b%"isCorrupted":%u|b%"SplHeap":private]=> + bool(true) + [%u|b%"heap":%u|b%"SplHeap":private]=> + array(2) { + [0]=> + array(1) { + [0]=> + %unicode|string%(7) "foobar2" + } + [1]=> + array(1) { + [0]=> + %unicode|string%(7) "foobar1" + } + } +} diff --git a/ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt b/ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt new file mode 100644 index 0000000..8726f4b --- /dev/null +++ b/ext/spl/tests/spl_heap_recoverfromcorruption_arguments.phpt @@ -0,0 +1,15 @@ +--TEST-- +SPL: SplHeap check no arguments to be accepted on recoverFromCorruption +--CREDITS-- +Rohan Abraham (rohanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + $h = new SplMaxHeap(); + //Line below should throw a warning as no args are expected + $h->recoverFromCorruption("no args"); +?> +--EXPECTF-- + +Warning: SplHeap::recoverFromCorruption() expects exactly 0 parameters, 1 given in %s on line %d + diff --git a/ext/spl/tests/spl_iterator_apply_error.phpt b/ext/spl/tests/spl_iterator_apply_error.phpt new file mode 100644 index 0000000..8e7cba4 --- /dev/null +++ b/ext/spl/tests/spl_iterator_apply_error.phpt @@ -0,0 +1,26 @@ +--TEST-- +SPL: Error: iterator_apply when an iterator method (eg rewind) throws exception +--FILE-- +<?php + +class MyArrayIterator extends ArrayIterator { + public function rewind() { + throw new Exception('Make the iterator break'); + } +} + +function test() {} + +$it = new MyArrayIterator(array(1, 21, 22)); + +try { + $res = iterator_apply($it, 'test'); +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> + +<?php exit(0); ?> +--EXPECT-- +Make the iterator break diff --git a/ext/spl/tests/spl_iterator_apply_error_001.phpt b/ext/spl/tests/spl_iterator_apply_error_001.phpt new file mode 100644 index 0000000..54663c0 --- /dev/null +++ b/ext/spl/tests/spl_iterator_apply_error_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +SPL: Error: iterator_apply when the callback throws an exception +--FILE-- +<?php + +function test() { + throw new Exception('Broken callback'); +} + +$it = new RecursiveArrayIterator(array(1, 21, 22)); + +try { + iterator_apply($it, 'test'); +} catch (Exception $e) { + echo $e->getMessage(); +} + +?> +--EXPECT-- +Broken callback diff --git a/ext/spl/tests/spl_iterator_caching_count_basic.phpt b/ext/spl/tests/spl_iterator_caching_count_basic.phpt new file mode 100644 index 0000000..b11eb7b --- /dev/null +++ b/ext/spl/tests/spl_iterator_caching_count_basic.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: Caching iterator count() cache contents +--CREDITS-- +Lukasz Andrzejak meltir@meltir.com +#testfest London 2009-05-09 +--FILE-- +<?php +$i = new ArrayIterator(array(1,1,1,1,1)); +$i = new CachingIterator($i,CachingIterator::FULL_CACHE); +foreach ($i as $value) { + echo $i->count()."\n"; +} +?> +===DONE=== +--EXPECT-- +1 +2 +3 +4 +5 +===DONE===
\ No newline at end of file diff --git a/ext/spl/tests/spl_iterator_caching_count_error.phpt b/ext/spl/tests/spl_iterator_caching_count_error.phpt new file mode 100644 index 0000000..70aa2be --- /dev/null +++ b/ext/spl/tests/spl_iterator_caching_count_error.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: Caching iterator count() cache failure +--CREDITS-- +Lukasz Andrzejak meltir@meltir.com +#testfest London 2009-05-09 +--FILE-- +<?php +$i = new ArrayIterator(array(1,1,1,1,1)); +$i = new CachingIterator($i); +try { + $i->count(); + echo "Should have caused an exception"; +} catch (BadMethodCallException $e) { + echo "Exception raised\n"; +} + +?> +===DONE=== +--EXPECT-- +Exception raised +===DONE===
\ No newline at end of file diff --git a/ext/spl/tests/spl_iterator_caching_getcache_error.phpt b/ext/spl/tests/spl_iterator_caching_getcache_error.phpt new file mode 100644 index 0000000..2ea4bd8 --- /dev/null +++ b/ext/spl/tests/spl_iterator_caching_getcache_error.phpt @@ -0,0 +1,21 @@ +--TEST-- +SPL: Caching iterator getCache failure +--CREDITS-- +Lukasz Andrzejak meltir@meltir.com +#testfest London 2009-05-09 +--FILE-- +<?php +$i = new ArrayIterator(array(1,1,1,1,1)); +$i = new CachingIterator($i); +try { + $i->getCache(); + echo "Should have caused an exception"; +} catch (BadMethodCallException $e) { + echo "Exception raised\n"; +} + +?> +===DONE=== +--EXPECT-- +Exception raised +===DONE===
\ No newline at end of file diff --git a/ext/spl/tests/spl_iterator_getcallchildren.phpt b/ext/spl/tests/spl_iterator_getcallchildren.phpt new file mode 100644 index 0000000..77b03b6 --- /dev/null +++ b/ext/spl/tests/spl_iterator_getcallchildren.phpt @@ -0,0 +1,39 @@ +--TEST-- +SPL: RecursiveIteratorIterator, getCallChildren +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + //line 681 ... + $array = array(array(7,8,9),1,2,3,array(4,5,6)); +$recursiveArrayIterator = new RecursiveArrayIterator($array); +$test = new RecursiveIteratorIterator($recursiveArrayIterator); + +var_dump($test->current()); +$test->next(); +var_dump($test->current()); +try { + $output = $test->callGetChildren(); +} catch (InvalidArgumentException $ilae){ + $output = null; + print "invalid argument exception\n"; +} +var_dump($output); + + +?> +===DONE=== +--EXPECTF-- + array(3) { + [0]=> + int(7) + [1]=> + int(8) + [2]=> + int(9) +} +int(7) +invalid argument exception +NULL +===DONE=== diff --git a/ext/spl/tests/spl_iterator_iterator_constructor.phpt b/ext/spl/tests/spl_iterator_iterator_constructor.phpt new file mode 100644 index 0000000..d4fdb14 --- /dev/null +++ b/ext/spl/tests/spl_iterator_iterator_constructor.phpt @@ -0,0 +1,30 @@ +--TEST-- +SPL: IteratorInterator constructor checks +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + + //I think this is testing line 1297 of spl_iterators.c + + $array = array(array(7,8,9),1,2,3,array(4,5,6)); +$arrayIterator = new ArrayIterator($array); +try { +$test = new IteratorIterator($arrayIterator); + +$test = new IteratorIterator($arrayIterator, 1); +$test = new IteratorIterator($arrayIterator, 1, 1); +$test = new IteratorIterator($arrayIterator, 1, 1, 1); +$test = new IteratorIterator($arrayIterator, 1, 1, 1, 1); + +} catch (InvalidArgumentException $e){ + print $e->getMessage() . "\n"; +} + + +?> +===DONE=== +--EXPECTF-- +IteratorIterator::__construct() expects at most 2 parameters, 3 given +===DONE=== diff --git a/ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt b/ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt new file mode 100644 index 0000000..0d45c31 --- /dev/null +++ b/ext/spl/tests/spl_iterator_recursive_getiterator_error.phpt @@ -0,0 +1,16 @@ +--TEST-- +SPL: IteratorIterator foreach by reference failure +--CREDITS-- +Lukasz Andrzejak meltir@meltir.com +#testfest London 2009-05-09 +--FILE-- +<?php +$i = new ArrayIterator(array(1,1,1,1,1)); +$iii = new IteratorIterator($i); +p($iii); +function p ($i) { + foreach ($i as &$value) {} +} +?> +--EXPECTF-- +Fatal error: An iterator cannot be used with foreach by reference in %s
\ No newline at end of file diff --git a/ext/spl/tests/spl_iterator_to_array_basic.phpt b/ext/spl/tests/spl_iterator_to_array_basic.phpt new file mode 100644 index 0000000..68cb879 --- /dev/null +++ b/ext/spl/tests/spl_iterator_to_array_basic.phpt @@ -0,0 +1,13 @@ +--TEST-- +SPL: iterator_to_array, Test function to convert iterator to array +--CREDITS-- +Chris Scott chris.scott@nstein.com +#testfest London 2009-05-09 +--FILE-- +<?php + +iterator_to_array();//requires iterator as arg + +?> +--EXPECTF-- +Warning: iterator_to_array() expects at least 1 parameter, %s diff --git a/ext/spl/tests/spl_iterator_to_array_error.phpt b/ext/spl/tests/spl_iterator_to_array_error.phpt new file mode 100644 index 0000000..755ef7b --- /dev/null +++ b/ext/spl/tests/spl_iterator_to_array_error.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: Error: iterator_to_array when the current operation throws an exception +--FILE-- +<?php + +class MyArrayIterator extends ArrayIterator { + public function current() { + throw new Exception('Make the iterator break'); + } +} + +$it = new MyArrayIterator(array(4, 6, 2)); + +try { + // get keys + $ar = iterator_to_array($it); +} catch (Exception $e) { + echo $e->getMessage() . PHP_EOL; +} + +try { + // get values + $ar = iterator_to_array($it, false); +} catch (Exception $e) { + echo $e->getMessage() . PHP_EOL; +} + +?> + +<?php exit(0); ?> +--EXPECT-- +Make the iterator break +Make the iterator break diff --git a/ext/spl/tests/spl_limit_iterator_check_limits.phpt b/ext/spl/tests/spl_limit_iterator_check_limits.phpt new file mode 100644 index 0000000..ae1bc85 --- /dev/null +++ b/ext/spl/tests/spl_limit_iterator_check_limits.phpt @@ -0,0 +1,37 @@ +--TEST-- +SPL: LimitIterator check limits are valid +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + $array = array(array(7,8,9),1,2,3,array(4,5,6)); +$arrayIterator = new ArrayIterator($array); + +try { + $limitIterator = new LimitIterator($arrayIterator, -1); +} catch (OutOfRangeException $e){ + print $e->getMessage(). "\n"; +} + + +try { + $limitIterator = new LimitIterator($arrayIterator, 0, -2); +} catch (OutOfRangeException $e){ + print $e->getMessage() . "\n"; +} + +try { + $limitIterator = new LimitIterator($arrayIterator, 0, -1); +} catch (OutOfRangeException $e){ + print $e->getMessage() . "\n"; +} + + + +?> +===DONE=== +--EXPECTF-- +Parameter offset must be >= 0 +Parameter count must either be -1 or a value greater than or equal 0 +===DONE=== diff --git a/ext/spl/tests/spl_maxheap_compare_basic.phpt b/ext/spl/tests/spl_maxheap_compare_basic.phpt new file mode 100644 index 0000000..3705b3f --- /dev/null +++ b/ext/spl/tests/spl_maxheap_compare_basic.phpt @@ -0,0 +1,22 @@ +--TEST-- +SPL: SplMaxHeap, Test method to comare elements +--CREDITS-- +Chris Scott chris.scott@nstein.com +#testfest London 2009-05-09 +--FILE-- +<?php + +class MyHeap extends SplMaxHeap +{ + public function testCompare() + { + return parent::compare(1); + } +} + +$heap = new MyHeap(); +$heap->testCompare(); + +?> +--EXPECTF-- +Warning: SplMaxHeap::compare() expects exactly 2 parameters, %s diff --git a/ext/spl/tests/spl_minheap_compare_error.phpt b/ext/spl/tests/spl_minheap_compare_error.phpt new file mode 100644 index 0000000..7120a6c --- /dev/null +++ b/ext/spl/tests/spl_minheap_compare_error.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: SplMinHeap compare, illegal number of args +--CREDITS-- +Mark Schaschke (mark@fractalturtle.com) +TestFest London May 2009 +--FILE-- +<?php +class SplMinHeap2 extends SplMinHeap { + public function testCompare1() { + return parent::compare(); + } + public function testCompare2() { + return parent::compare(1); + } + public function testCompare3() { + return parent::compare(1, 2, 3); + } +} + +$h = new SplMinHeap2(); +$h->testCompare1(); +$h->testCompare2(); +$h->testCompare3(); +?> +--EXPECTF-- +Warning: SplMinHeap::compare() expects exactly 2 parameters, 0 given in %s + +Warning: SplMinHeap::compare() expects exactly 2 parameters, 1 given in %s + +Warning: SplMinHeap::compare() expects exactly 2 parameters, 3 given in %s + diff --git a/ext/spl/tests/spl_pq_top_basic.phpt b/ext/spl/tests/spl_pq_top_basic.phpt new file mode 100644 index 0000000..dcc1cbe --- /dev/null +++ b/ext/spl/tests/spl_pq_top_basic.phpt @@ -0,0 +1,42 @@ +--TEST-- +SPL: SplPriorityQueue: top and extract flags +--CREDITS-- +Nathaniel McHugh nat@fishtrap.co.uk +#testfest London 2009-05-09 +--FILE-- +<?php + +$priorityQueue = new SplPriorityQueue(); + +$priorityQueue->insert("a", 1); +$priorityQueue->insert("b", 2); +$priorityQueue->insert("c", 0); + +echo "EXTR DEFAULT",PHP_EOL; +echo "value: ",$priorityQueue->top(),PHP_EOL; + +$priorityQueue->setExtractFlags(SplPriorityQueue::EXTR_PRIORITY); +echo "EXTR_PRIORITY",PHP_EOL; +echo "priority: ",$priorityQueue->top(),PHP_EOL; + +$priorityQueue->setExtractFlags(SplPriorityQueue::EXTR_BOTH); +echo "EXTR_BOTH",PHP_EOL; +print_r($priorityQueue->top()); + +echo "EXTR_DATA",PHP_EOL; +$priorityQueue->setExtractFlags(SplPriorityQueue::EXTR_DATA); +echo "value: ",$priorityQueue->top(),PHP_EOL; +?> +--EXPECT-- +EXTR DEFAULT +value: b +EXTR_PRIORITY +priority: 2 +EXTR_BOTH +Array +( + [data] => b + [priority] => 2 +) +EXTR_DATA +value: b
\ No newline at end of file diff --git a/ext/spl/tests/spl_pq_top_error_args.phpt b/ext/spl/tests/spl_pq_top_error_args.phpt new file mode 100644 index 0000000..a0e5969 --- /dev/null +++ b/ext/spl/tests/spl_pq_top_error_args.phpt @@ -0,0 +1,12 @@ +--TEST-- +SPL: SplPriorityQueue: top too many arguments exception +--CREDITS-- +Nathaniel McHugh nat@fishtrap.co.uk +#testfest London 2009-05-09 +--FILE-- +<?php +$priorityQueue = new SplPriorityQueue(); +$priorityQueue->top('var'); +?> +--EXPECTF-- +Warning: SplPriorityQueue::top() expects exactly 0 parameters, 1 given in %s
\ No newline at end of file diff --git a/ext/spl/tests/spl_pq_top_error_corrupt.phpt b/ext/spl/tests/spl_pq_top_error_corrupt.phpt new file mode 100644 index 0000000..30b6fde --- /dev/null +++ b/ext/spl/tests/spl_pq_top_error_corrupt.phpt @@ -0,0 +1,38 @@ +--TEST-- +SPL: SplPriorityQueue: top and extract flags +--CREDITS-- +Nathaniel McHugh nat@fishtrap.co.uk +#testfest 2009-05-09 +--FILE-- +<?php + +class myPriorityQueue extends SplPriorityQueue{ + + public function compare($a, $b){ + if ($b == 2) { + throw new Exception('ignore me'); + } else { + return parent::compare($a, $b); + } + } +} + +$priorityQueue = new myPriorityQueue(); +$priorityQueue->insert("a", 1); + +try { + //corrupt heap + $priorityQueue->insert("b", 2); + // ignore exception tested elsewhere +} catch (Exception $e) { +} + +try { + $priorityQueue->top(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage().PHP_EOL; +} + +?> +--EXPECT-- +Exception: Heap is corrupted, heap properties are no longer ensured. diff --git a/ext/spl/tests/spl_pq_top_error_empty.phpt b/ext/spl/tests/spl_pq_top_error_empty.phpt new file mode 100644 index 0000000..9e2a31b --- /dev/null +++ b/ext/spl/tests/spl_pq_top_error_empty.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: SplPriorityQueue: top exception on empty heap +--CREDITS-- +Nathaniel McHugh nat@fishtrap.co.uk +#testfest 2009-05-09 +--FILE-- +<?php + +$priorityQueue = new SplPriorityQueue(); + +try { + $priorityQueue->top(); +} catch (RuntimeException $e) { + echo "Exception: ".$e->getMessage().PHP_EOL; +} + +?> +--EXPECT-- +Exception: Can't peek at an empty heap diff --git a/ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt b/ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt new file mode 100644 index 0000000..659ffb4 --- /dev/null +++ b/ext/spl/tests/spl_priorityqeue_insert_two_params_error.phpt @@ -0,0 +1,31 @@ +--TEST-- +SPL: priorityQueue paramter test on insert method +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + + +$testHeap = new SplPriorityQueue(); + + +var_dump($testHeap->insert()); +var_dump($testHeap->insert('test')); +var_dump($testHeap->insert('test', 'test')); +var_dump($testHeap->insert('test', 'test', 'test')); + + +?> +===DONE=== +--EXPECTF-- +Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 0 given in %s on line 7 +NULL + +Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 1 given in %s on line 8 +NULL +bool(true) + +Warning: SplPriorityQueue::insert() expects exactly 2 parameters, 3 given in %s on line 10 +NULL +===DONE=== diff --git a/ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt b/ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt new file mode 100644 index 0000000..d52a320 --- /dev/null +++ b/ext/spl/tests/spl_recursiveIteratorIterator_setMaxDepth_parameter_count.phpt @@ -0,0 +1,28 @@ +--TEST-- +SPL: RecursiveIteratorIterator, setMaxDepth check parameter count +--CREDITS-- +Sean Burlington www.practicalweb.co.uk +TestFest London May 2009 +--FILE-- +<?php + //line 681 ... + $array = array(array(7,8,9),1,2,3,array(4,5,6)); +$recursiveArrayIterator = new RecursiveArrayIterator($array); +$test = new RecursiveIteratorIterator($recursiveArrayIterator); + +//var_dump($test->current()); +$test->setMaxDepth(); +$test->setMaxDepth(1); +$test->setMaxDepth(1,2); +$test->setMaxDepth(1,2,3); + +//var_dump($test->current()); + + +?> +===DONE=== +--EXPECTF-- +Warning: RecursiveIteratorIterator::setMaxDepth() expects at most 1 parameter, 2 given in %s on line 10 + +Warning: RecursiveIteratorIterator::setMaxDepth() expects at most 1 parameter, 3 given in %s on line 11 +===DONE=== diff --git a/ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt b/ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt new file mode 100644 index 0000000..1262ec0 --- /dev/null +++ b/ext/spl/tests/spl_recursive_iterator_iterator_key_case.phpt @@ -0,0 +1,33 @@ +--TEST-- +SPL: Test on RecursiveIteratorIterator key function checking switch statements +--CREDITS-- +Rohan Abraham (rohanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + $ar = array("one"=>1, "two"=>2, "three"=>array("four"=>4, "five"=>5, "six"=>array("seven"=>7)), "eight"=>8, -100 => 10, NULL => "null"); + $it = new RecursiveArrayIterator($ar); + $it = new RecursiveIteratorIterator($it); + foreach($it as $k=>$v) + { + echo "$k=>$v\n"; + var_dump($k); + } +?> +--EXPECTF-- +one=>1 +%unicode|string%(3) "one" +two=>2 +%unicode|string%(3) "two" +four=>4 +%unicode|string%(4) "four" +five=>5 +%unicode|string%(4) "five" +seven=>7 +%unicode|string%(5) "seven" +eight=>8 +%unicode|string%(5) "eight" +-100=>10 +int(-100) +=>null +%unicode|string%(0) "" diff --git a/ext/spl/tests/splfixedarray_offsetExists_larger.phpt b/ext/spl/tests/splfixedarray_offsetExists_larger.phpt new file mode 100644 index 0000000..9449d64 --- /dev/null +++ b/ext/spl/tests/splfixedarray_offsetExists_larger.phpt @@ -0,0 +1,15 @@ +--TEST-- +Checks that offsetExists() does not accept a value larger than the array. +--CREDITS-- + PHPNW Test Fest 2009 - Rick Ogden +--FILE-- +<?php +$ar = new SplFixedArray(3); +$ar[0] = 1; +$ar[1] = 2; +$ar[2] = 3; + +var_dump($ar->offsetExists(4)); +?> +--EXPECT-- +bool(false) diff --git a/ext/spl/tests/splpriorityqueue_extract.phpt b/ext/spl/tests/splpriorityqueue_extract.phpt new file mode 100644 index 0000000..eee7bb2 --- /dev/null +++ b/ext/spl/tests/splpriorityqueue_extract.phpt @@ -0,0 +1,19 @@ +--TEST-- +SPL: splpriorityqueue extract() Test arguments +--CREDITS-- +Roshan Abraham (roshanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + +$sp = new SplPriorityQueue(); + +$sp->insert("1",1); + +$sp->extract(1); // Should throw a warning as extract expects NO arguments + +?> +--EXPECTF-- + +Warning: SplPriorityQueue::extract() expects exactly 0 parameters, 1 given in %s on line %d + diff --git a/ext/spl/tests/splpriorityqueue_setextractflags.phpt b/ext/spl/tests/splpriorityqueue_setextractflags.phpt new file mode 100644 index 0000000..97d86f3 --- /dev/null +++ b/ext/spl/tests/splpriorityqueue_setextractflags.phpt @@ -0,0 +1,17 @@ +--TEST-- +SPL: splpriorityqueue setExtractFlags() Test arguments +--CREDITS-- +Roshan Abraham (roshanabrahams@gmail.com) +TestFest London May 2009 +--FILE-- +<?php + +$sp = new SplPriorityQueue(); + +$sp->setExtractFlags(1,1); // Should throw a warning as setExtractFlags expects only 1 argument + +?> +--EXPECTF-- + +Warning: SplPriorityQueue::setExtractFlags() expects exactly 1 parameter, 2 given in %s on line %d + diff --git a/ext/spl/tests/testclass b/ext/spl/tests/testclass new file mode 100755 index 0000000..ceb24c8 --- /dev/null +++ b/ext/spl/tests/testclass @@ -0,0 +1,5 @@ +<?php + +echo __FILE__ . "\n"; + +?>
\ No newline at end of file diff --git a/ext/spl/tests/testclass.class.inc b/ext/spl/tests/testclass.class.inc new file mode 100644 index 0000000..f5fe741 --- /dev/null +++ b/ext/spl/tests/testclass.class.inc @@ -0,0 +1,9 @@ +<?php + +echo __FILE__ . "\n"; + +class TestClass +{ +} + +?>
\ No newline at end of file diff --git a/ext/spl/tests/testclass.inc b/ext/spl/tests/testclass.inc new file mode 100644 index 0000000..ceb24c8 --- /dev/null +++ b/ext/spl/tests/testclass.inc @@ -0,0 +1,5 @@ +<?php + +echo __FILE__ . "\n"; + +?>
\ No newline at end of file diff --git a/ext/spl/tests/testclass.php.inc b/ext/spl/tests/testclass.php.inc new file mode 100644 index 0000000..ceb24c8 --- /dev/null +++ b/ext/spl/tests/testclass.php.inc @@ -0,0 +1,5 @@ +<?php + +echo __FILE__ . "\n"; + +?>
\ No newline at end of file |