php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #69106
Patch sortable_interface revision 2015-02-22 21:36 UTC by thomas at gielfeldt dot dk

Patch sortable_interface for SPL related Bug #69106

Patch version 2015-02-22 21:36 UTC

Return to Bug #69106 | Download this patch
Patch Revisions:

Developer: thomas@gielfeldt.dk

diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index 44611e6..e611ef1 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -223,6 +223,7 @@ PHP_FUNCTION(class_uses)
 	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(Sortable, 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); \
diff --git a/ext/spl/spl.php b/ext/spl/spl.php
index c276f1f..5547cf4 100755
--- a/ext/spl/spl.php
+++ b/ext/spl/spl.php
@@ -577,6 +577,58 @@ interface Countable
 	function count();
 }
 
+/** @ingroup SPL
+ * @brief This Interface allows to hook into the global sort() functions.
+ * @since PHP 5.6
+ */
+interface Sortable
+{
+	/** Sort the entries by values.
+	 */
+	function sort($sort_flags = SORT_REGULAR);
+
+	/** Sort the entries by values in reverse
+	 */
+	function rsort($sort_flags = SORT_REGULAR);
+
+	/** Sort the entries by values and maintain indexes.
+	 */
+	function asort($sort_flags = SORT_REGULAR);
+
+	/** Sort the entries by values in reverse and maintain indexes.
+	 */
+	function arsort($sort_flags = SORT_REGULAR);
+
+	/** Sort the entries by key.
+	 */
+	function ksort($sort_flags = SORT_REGULAR);
+
+	/** Sort the entries by key in reverse.
+	 */
+	function krsort($sort_flags = SORT_REGULAR);
+
+	/** Sort the entries by values using user defined function.
+	 */
+	function usort(mixed cmp_function);
+
+	/** Sort the entries by values using user defined function and maintain index.
+	 */
+	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();
+
+}
+
 /** @ingroup ZendEngine
  * @brief Interface for customized serializing
  * @since 5.1
@@ -646,14 +698,34 @@ class ArrayObject implements IteratorAggregate, ArrayAccess, Countable
 
 	/** Sort the entries by values.
 	 */
-	function asort() {/**/}
+	function sort($sort_flags = SORT_REGULAR) {/**/}
+
+	/** Sort the entries by values in reverse
+	 */
+	function rsort($sort_flags = SORT_REGULAR) {/**/}
+
+	/** Sort the entries by values and maintain indexes.
+	 */
+	function asort($sort_flags = SORT_REGULAR) {/**/}
+
+	/** Sort the entries by values in reverse and maintain indexes.
+	 */
+	function arsort($sort_flags = SORT_REGULAR) {/**/}
 
 	/** Sort the entries by key.
 	 */
-	function ksort() {/**/}
+	function ksort($sort_flags = SORT_REGULAR) {/**/}
+
+	/** Sort the entries by key in reverse.
+	 */
+	function krsort($sort_flags = SORT_REGULAR) {/**/}
 
 	/** Sort the entries by values using user defined function.
 	 */
+	function usort(mixed cmp_function) {/**/}
+
+	/** Sort the entries by values using user defined function and maintain index.
+	 */
 	function uasort(mixed cmp_function) {/**/}
 
 	/** Sort the entries by key using user defined function.
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index 9c49d91..36b8a31 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -1495,16 +1495,41 @@ SPL_METHOD(cname, fname) \
 	spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
 }
 
+/* {{{ proto int ArrayObject::sort([int $sort_flags = SORT_REGULAR ])
+       proto int ArrayIterator::sort([int $sort_flags = SORT_REGULAR ])
+   Sort the entries by values. */
+SPL_ARRAY_METHOD(Array, sort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::rsort([int $sort_flags = SORT_REGULAR ])
+       proto int ArrayIterator::rsort([int $sort_flags = SORT_REGULAR ])
+   Sort the entries by values reverse. */
+SPL_ARRAY_METHOD(Array, rsort, SPL_ARRAY_METHOD_MAY_USER_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::arsort([int $sort_flags = SORT_REGULAR ])
+       proto int ArrayIterator::arsort([int $sort_flags = SORT_REGULAR ])
+   Sort the entries by values reverse. */
+SPL_ARRAY_METHOD(Array, arsort, 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::krsort([int $sort_flags = SORT_REGULAR ])
+       proto int ArrayIterator::krsort([int $sort_flags = SORT_REGULAR ])
+   Sort the entries by key. */
+SPL_ARRAY_METHOD(Array, krsort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
+
+/* {{{ proto int ArrayObject::usort(callback cmp_function)
+       proto int ArrayIterator::usort(callback cmp_function)
+   Sort the entries by key using user defined function. */
+SPL_ARRAY_METHOD(Array, usort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
+
 /* {{{ proto int ArrayObject::uasort(callback cmp_function)
        proto int ArrayIterator::uasort(callback cmp_function)
    Sort the entries by values user defined function. */
@@ -1891,8 +1916,13 @@ static const zend_function_entry spl_funcs_ArrayObject[] = {
 	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, sort,             arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, rsort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
 	SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, arsort,           arginfo_array_void,             ZEND_ACC_PUBLIC)
 	SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, krsort,           arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, usort,            arginfo_array_uXsort,           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)
@@ -1918,8 +1948,13 @@ static const zend_function_entry spl_funcs_ArrayIterator[] = {
 	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, sort,             arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, rsort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
 	SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, arsort,           arginfo_array_void,             ZEND_ACC_PUBLIC)
 	SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, krsort,           arginfo_array_void,             ZEND_ACC_PUBLIC)
+	SPL_ME(Array, usort,            arginfo_array_uXsort,           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)
@@ -1951,6 +1986,7 @@ PHP_MINIT_FUNCTION(spl_array)
 	REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
 	REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
 	REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
+	REGISTER_SPL_IMPLEMENTS(ArrayObject, Sortable);
 	memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
 
 	spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
@@ -1976,6 +2012,7 @@ PHP_MINIT_FUNCTION(spl_array)
 	REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
 	REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
 	REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
+	REGISTER_SPL_IMPLEMENTS(ArrayIterator, Sortable);
 	memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
 	spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
 
diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c
index 3a37241..9c1d665 100644
--- a/ext/spl/spl_iterators.c
+++ b/ext/spl/spl_iterators.c
@@ -62,6 +62,7 @@ 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;
+PHPAPI zend_class_entry *spl_ce_Sortable;
 
 ZEND_BEGIN_ARG_INFO(arginfo_recursive_it_void, 0)
 ZEND_END_ARG_INFO()
@@ -3729,6 +3730,25 @@ static const zend_function_entry spl_funcs_Countable[] = {
 	PHP_FE_END
 };
 
+ZEND_BEGIN_ARG_INFO(arginfo_array_it_uXsort, 0)
+	ZEND_ARG_INFO(0, cmp_function)
+ZEND_END_ARG_INFO();
+
+static const zend_function_entry spl_funcs_Sortable[] = {
+	SPL_ABSTRACT_ME(Sortable, sort,         arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, rsort,        arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, asort,        arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, arsort,       arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, ksort,        arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, krsort,       arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, usort,        arginfo_array_it_uXsort)
+	SPL_ABSTRACT_ME(Sortable, uasort,       arginfo_array_it_uXsort)
+	SPL_ABSTRACT_ME(Sortable, uksort,       arginfo_array_it_uXsort)
+	SPL_ABSTRACT_ME(Sortable, natcasesort,  arginfo_recursive_it_void)
+	SPL_ABSTRACT_ME(Sortable, natsort,      arginfo_recursive_it_void)
+	PHP_FE_END
+};
+
 /* {{{ PHP_MINIT_FUNCTION(spl_iterators)
  */
 PHP_MINIT_FUNCTION(spl_iterators)
@@ -3778,6 +3798,7 @@ PHP_MINIT_FUNCTION(spl_iterators)
 	REGISTER_SPL_SUB_CLASS_EX(ParentIterator, RecursiveFilterIterator, spl_dual_it_new, spl_funcs_ParentIterator);
 
 	REGISTER_SPL_INTERFACE(Countable);
+	REGISTER_SPL_INTERFACE(Sortable);
 	REGISTER_SPL_INTERFACE(SeekableIterator);
 	REGISTER_SPL_ITERATOR(SeekableIterator);
 
diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h
index 3991dda..02706bb 100644
--- a/ext/spl/spl_iterators.h
+++ b/ext/spl/spl_iterators.h
@@ -54,6 +54,7 @@ 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;
+extern PHPAPI zend_class_entry *spl_ce_Sortable;
 
 PHP_MINIT_FUNCTION(spl_iterators);
 
diff --git a/ext/spl/tests/arrayObject_arsort_basic1.phpt b/ext/spl/tests/arrayObject_arsort_basic1.phpt
new file mode 100644
index 0000000..d8cb411
--- /dev/null
+++ b/ext/spl/tests/arrayObject_arsort_basic1.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::arsort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::arsort()
+ * Description: proto int ArrayIterator::arsort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::arsort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump($ao1->arsort());
+var_dump($ao1);
+var_dump($ao2->arsort('blah'));
+var_dump($ao2);
+var_dump($ao2->arsort(SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::arsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(4)
+    [2]=>
+    int(3)
+    [1]=>
+    int(2)
+  }
+}
+
+Warning: arsort() expects parameter 2 to be long, string given in %sarrayObject_arsort_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) {
+    ["a"]=>
+    int(4)
+    ["c"]=>
+    int(3)
+    ["b"]=>
+    int(2)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_arsort_basic2.phpt b/ext/spl/tests/arrayObject_arsort_basic2.phpt
new file mode 100644
index 0000000..d6c3ba5
--- /dev/null
+++ b/ext/spl/tests/arrayObject_arsort_basic2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: Test ArrayObject::arsort() function : basic functionality with object based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::arsort()
+ * Description: proto int ArrayIterator::arsort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::arsort() : 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->arsort());
+var_dump($ao1, $c);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::arsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#2 (1) {
+  ["storage":"ArrayObject":private]=>
+  object(C)#1 (4) {
+    ["prop2"]=>
+    string(1) "z"
+    ["prop1"]=>
+    string(1) "x"
+    ["prop4"]=>
+    string(1) "x"
+    ["prop3":"C":private]=>
+    string(1) "a"
+  }
+}
+object(C)#1 (4) {
+  ["prop2"]=>
+  string(1) "z"
+  ["prop1"]=>
+  string(1) "x"
+  ["prop4"]=>
+  string(1) "x"
+  ["prop3":"C":private]=>
+  string(1) "a"
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_arsort_basic3.phpt b/ext/spl/tests/arrayObject_arsort_basic3.phpt
new file mode 100644
index 0000000..055348e
--- /dev/null
+++ b/ext/spl/tests/arrayObject_arsort_basic3.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::arsort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::arsort()
+ * Description: proto int ArrayIterator::arsort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::arsort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump(arsort($ao1));
+var_dump($ao1);
+var_dump(arsort($ao2, 'blah'));
+var_dump($ao2);
+var_dump(arsort($ao2, SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::arsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(4)
+    [2]=>
+    int(3)
+    [1]=>
+    int(2)
+  }
+}
+
+Warning: arsort() expects parameter 2 to be long, string given in %sarrayObject_arsort_basic3.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) {
+    ["a"]=>
+    int(4)
+    ["c"]=>
+    int(3)
+    ["b"]=>
+    int(2)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_asort_basic3.phpt b/ext/spl/tests/arrayObject_asort_basic3.phpt
new file mode 100644
index 0000000..7194935
--- /dev/null
+++ b/ext/spl/tests/arrayObject_asort_basic3.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(asort($ao1));
+var_dump($ao1);
+var_dump(asort($ao2, 'blah'));
+var_dump($ao2);
+var_dump(asort($ao2, 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_basic3.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_krsort_basic1.phpt b/ext/spl/tests/arrayObject_krsort_basic1.phpt
new file mode 100644
index 0000000..d33b952
--- /dev/null
+++ b/ext/spl/tests/arrayObject_krsort_basic1.phpt
@@ -0,0 +1,67 @@
+--TEST--
+SPL: Test ArrayObject::krsort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::krsort()
+ * Description: proto int ArrayIterator::krsort()
+ * Sort the entries by key.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::krsort() : 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->krsort());
+var_dump($ao1);
+var_dump($ao2->krsort('blah'));
+var_dump($ao2);
+var_dump($ao2->krsort(SORT_STRING));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::krsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [2]=>
+    int(3)
+    [1]=>
+    int(2)
+    [0]=>
+    int(4)
+  }
+}
+
+Warning: krsort() expects parameter 2 to be long, string given in %sarrayObject_krsort_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) {
+    ["q"]=>
+    int(3)
+    ["b"]=>
+    int(4)
+    ["a"]=>
+    int(2)
+    [99]=>
+    string(1) "x"
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_krsort_basic2.phpt b/ext/spl/tests/arrayObject_krsort_basic2.phpt
new file mode 100644
index 0000000..b6d3430
--- /dev/null
+++ b/ext/spl/tests/arrayObject_krsort_basic2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: Test ArrayObject::krsort() function : basic functionality with object base store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::krsort()
+ * Description: proto int ArrayIterator::krsort()
+ * Sort the entries by key.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::krsort() : 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->krsort());
+var_dump($ao1, $c);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::krsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#2 (1) {
+  ["storage":"ArrayObject":private]=>
+  object(C)#1 (4) {
+    ["z"]=>
+    string(5) "prop2"
+    ["x"]=>
+    string(5) "prop1"
+    ["a"]=>
+    string(5) "prop3"
+    ["b":"C":private]=>
+    string(5) "prop4"
+  }
+}
+object(C)#1 (4) {
+  ["z"]=>
+  string(5) "prop2"
+  ["x"]=>
+  string(5) "prop1"
+  ["a"]=>
+  string(5) "prop3"
+  ["b":"C":private]=>
+  string(5) "prop4"
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_krsort_basic3.phpt b/ext/spl/tests/arrayObject_krsort_basic3.phpt
new file mode 100644
index 0000000..4599ad3
--- /dev/null
+++ b/ext/spl/tests/arrayObject_krsort_basic3.phpt
@@ -0,0 +1,67 @@
+--TEST--
+SPL: Test ArrayObject::krsort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::krsort()
+ * Description: proto int ArrayIterator::krsort()
+ * Sort the entries by key.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::krsort() : basic functionality ***\n";
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('b'=>4,'a'=>2,'q'=>3, 99=>'x'));
+var_dump(krsort($ao1));
+var_dump($ao1);
+var_dump(krsort($ao2, 'blah'));
+var_dump($ao2);
+var_dump(krsort($ao2, SORT_STRING));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::krsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [2]=>
+    int(3)
+    [1]=>
+    int(2)
+    [0]=>
+    int(4)
+  }
+}
+
+Warning: krsort() expects parameter 2 to be long, string given in %sarrayObject_krsort_basic3.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) {
+    ["q"]=>
+    int(3)
+    ["b"]=>
+    int(4)
+    ["a"]=>
+    int(2)
+    [99]=>
+    string(1) "x"
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_ksort_basic3.phpt b/ext/spl/tests/arrayObject_ksort_basic3.phpt
new file mode 100644
index 0000000..50ee086
--- /dev/null
+++ b/ext/spl/tests/arrayObject_ksort_basic3.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(ksort($ao1));
+var_dump($ao1);
+var_dump(ksort($ao2, 'blah'));
+var_dump($ao2);
+var_dump(ksort($ao2, 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_basic3.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_natcasesort_basic2.phpt b/ext/spl/tests/arrayObject_natcasesort_basic2.phpt
new file mode 100644
index 0000000..5be5b9c
--- /dev/null
+++ b/ext/spl/tests/arrayObject_natcasesort_basic2.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(natcasesort($ao1));
+var_dump($ao1);
+var_dump(natcasesort($ao2));
+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_basic2.phpt b/ext/spl/tests/arrayObject_natsort_basic2.phpt
new file mode 100644
index 0000000..7c25345
--- /dev/null
+++ b/ext/spl/tests/arrayObject_natsort_basic2.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(natsort($ao1));
+var_dump($ao1);
+var_dump(natsort($ao2));
+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_rsort_basic1.phpt b/ext/spl/tests/arrayObject_rsort_basic1.phpt
new file mode 100644
index 0000000..5ad0425
--- /dev/null
+++ b/ext/spl/tests/arrayObject_rsort_basic1.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::rsort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::rsort()
+ * Description: proto int ArrayIterator::rsort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::rsort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump($ao1->rsort());
+var_dump($ao1);
+var_dump($ao2->rsort('blah'));
+var_dump($ao2);
+var_dump($ao2->rsort(SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::rsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(4)
+    [1]=>
+    int(3)
+    [2]=>
+    int(2)
+  }
+}
+
+Warning: rsort() expects parameter 2 to be long, string given in %sarrayObject_rsort_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) {
+    [0]=>
+    int(4)
+    [1]=>
+    int(3)
+    [2]=>
+    int(2)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_rsort_basic2.phpt b/ext/spl/tests/arrayObject_rsort_basic2.phpt
new file mode 100644
index 0000000..bf18dd4
--- /dev/null
+++ b/ext/spl/tests/arrayObject_rsort_basic2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: Test ArrayObject::rsort() function : basic functionality with object based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::rsort()
+ * Description: proto int ArrayIterator::rsort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::rsort() : 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->rsort());
+var_dump($ao1, $c);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::rsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#2 (1) {
+  ["storage":"ArrayObject":private]=>
+  object(C)#1 (4) {
+    [0]=>
+    string(1) "z"
+    [1]=>
+    string(1) "x"
+    [2]=>
+    string(1) "x"
+    [3]=>
+    string(1) "a"
+  }
+}
+object(C)#1 (4) {
+  [0]=>
+  string(1) "z"
+  [1]=>
+  string(1) "x"
+  [2]=>
+  string(1) "x"
+  [3]=>
+  string(1) "a"
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_rsort_basic3.phpt b/ext/spl/tests/arrayObject_rsort_basic3.phpt
new file mode 100644
index 0000000..54cb994
--- /dev/null
+++ b/ext/spl/tests/arrayObject_rsort_basic3.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::rsort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::rsort()
+ * Description: proto int ArrayIterator::rsort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::rsort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump(rsort($ao1));
+var_dump($ao1);
+var_dump(rsort($ao2, 'blah'));
+var_dump($ao2);
+var_dump(rsort($ao2, SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::rsort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(4)
+    [1]=>
+    int(3)
+    [2]=>
+    int(2)
+  }
+}
+
+Warning: rsort() expects parameter 2 to be long, string given in %sarrayObject_rsort_basic3.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) {
+    [0]=>
+    int(4)
+    [1]=>
+    int(3)
+    [2]=>
+    int(2)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_sort_basic1.phpt b/ext/spl/tests/arrayObject_sort_basic1.phpt
new file mode 100644
index 0000000..6b55c98
--- /dev/null
+++ b/ext/spl/tests/arrayObject_sort_basic1.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::sort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::sort()
+ * Description: proto int ArrayIterator::sort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::sort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump($ao1->sort());
+var_dump($ao1);
+var_dump($ao2->sort('blah'));
+var_dump($ao2);
+var_dump($ao2->sort(SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::sort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(2)
+    [1]=>
+    int(3)
+    [2]=>
+    int(4)
+  }
+}
+
+Warning: sort() expects parameter 2 to be long, string given in %sarrayObject_sort_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) {
+    [0]=>
+    int(2)
+    [1]=>
+    int(3)
+    [2]=>
+    int(4)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_sort_basic2.phpt b/ext/spl/tests/arrayObject_sort_basic2.phpt
new file mode 100644
index 0000000..3c7af6c
--- /dev/null
+++ b/ext/spl/tests/arrayObject_sort_basic2.phpt
@@ -0,0 +1,52 @@
+--TEST--
+SPL: Test ArrayObject::sort() function : basic functionality with object based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::sort()
+ * Description: proto int ArrayIterator::sort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::sort() : 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->sort());
+var_dump($ao1, $c);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::sort() : basic functionality ***
+bool(true)
+object(ArrayObject)#2 (1) {
+  ["storage":"ArrayObject":private]=>
+  object(C)#1 (4) {
+    [0]=>
+    string(1) "a"
+    [1]=>
+    string(1) "x"
+    [2]=>
+    string(1) "x"
+    [3]=>
+    string(1) "z"
+  }
+}
+object(C)#1 (4) {
+  [0]=>
+  string(1) "a"
+  [1]=>
+  string(1) "x"
+  [2]=>
+  string(1) "x"
+  [3]=>
+  string(1) "z"
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_sort_basic3.phpt b/ext/spl/tests/arrayObject_sort_basic3.phpt
new file mode 100644
index 0000000..6902af1
--- /dev/null
+++ b/ext/spl/tests/arrayObject_sort_basic3.phpt
@@ -0,0 +1,64 @@
+--TEST--
+SPL: Test ArrayObject::sort() function : basic functionality with array based store
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::sort()
+ * Description: proto int ArrayIterator::sort()
+ * Sort the entries by values.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::sort() : basic functionality ***\n";
+
+$ao1 = new ArrayObject(array(4,2,3));
+$ao2 = new ArrayObject(array('a'=>4,'b'=>2,'c'=>3));
+var_dump(sort($ao1));
+var_dump($ao1);
+var_dump(sort($ao2, 'blah'));
+var_dump($ao2);
+var_dump(sort($ao2, SORT_NUMERIC));
+var_dump($ao2);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::sort() : basic functionality ***
+bool(true)
+object(ArrayObject)#%d (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(2)
+    [1]=>
+    int(3)
+    [2]=>
+    int(4)
+  }
+}
+
+Warning: sort() expects parameter 2 to be long, string given in %sarrayObject_sort_basic3.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) {
+    [0]=>
+    int(2)
+    [1]=>
+    int(3)
+    [2]=>
+    int(4)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_uasort_basic2.phpt b/ext/spl/tests/arrayObject_uasort_basic2.phpt
new file mode 100644
index 0000000..65ea754
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uasort_basic2.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));
+
+uasort($ao, '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_error2.phpt b/ext/spl/tests/arrayObject_uasort_error2.phpt
new file mode 100644
index 0000000..6a6a02a
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uasort_error2.phpt
@@ -0,0 +1,31 @@
+--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 {
+	uasort($ao);
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+
+try {
+	uasort($ao, 1,2);
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Warning: uasort() expects exactly 2 parameters, 1 given in %sarrayObject_uasort_error2.php on line %d
+
+Warning: uasort() expects exactly 2 parameters, 3 given in %sarrayObject_uasort_error2.php on line %d
+===DONE===
diff --git a/ext/spl/tests/arrayObject_uksort_basic2.phpt b/ext/spl/tests/arrayObject_uksort_basic2.phpt
new file mode 100644
index 0000000..76eba20
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uksort_basic2.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));
+
+uksort($ao, '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_error2.phpt b/ext/spl/tests/arrayObject_uksort_error2.phpt
new file mode 100644
index 0000000..3e2ffcb
--- /dev/null
+++ b/ext/spl/tests/arrayObject_uksort_error2.phpt
@@ -0,0 +1,31 @@
+--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 {
+	uksort($ao);
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+
+try {
+	uksort($ao, 1,2);
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Warning: uksort() expects exactly 2 parameters, 1 given in %sarrayObject_uksort_error2.php on line %d
+
+Warning: uksort() expects exactly 2 parameters, 3 given in %sarrayObject_uksort_error2.php on line %d
+===DONE===
diff --git a/ext/spl/tests/arrayObject_usort_basic1.phpt b/ext/spl/tests/arrayObject_usort_basic1.phpt
new file mode 100644
index 0000000..779161f
--- /dev/null
+++ b/ext/spl/tests/arrayObject_usort_basic1.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: Test ArrayObject::usort() function : basic functionality
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::usort(callback cmp_function)
+ * Description: proto int ArrayIterator::usort(callback cmp_function)
+ Sort the entries by values user defined function.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::usort() : 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->usort('cmp');
+var_dump($ao);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::usort() : basic functionality ***
+object(ArrayObject)#1 (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(3)
+    [1]=>
+    int(2)
+    [2]=>
+    int(1)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_usort_basic2.phpt b/ext/spl/tests/arrayObject_usort_basic2.phpt
new file mode 100644
index 0000000..99f112c
--- /dev/null
+++ b/ext/spl/tests/arrayObject_usort_basic2.phpt
@@ -0,0 +1,44 @@
+--TEST--
+SPL: Test ArrayObject::usort() function : basic functionality
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::usort(callback cmp_function)
+ * Description: proto int ArrayIterator::usort(callback cmp_function)
+ Sort the entries by values user defined function.
+ * Source code: ext/spl/spl_array.c
+ * Alias to functions:
+ */
+
+echo "*** Testing ArrayObject::usort() : 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));
+
+usort($ao, 'cmp');
+var_dump($ao);
+?>
+===DONE===
+--EXPECTF--
+*** Testing ArrayObject::usort() : basic functionality ***
+object(ArrayObject)#1 (1) {
+  ["storage":"ArrayObject":private]=>
+  array(3) {
+    [0]=>
+    int(3)
+    [1]=>
+    int(2)
+    [2]=>
+    int(1)
+  }
+}
+===DONE===
diff --git a/ext/spl/tests/arrayObject_usort_error1.phpt b/ext/spl/tests/arrayObject_usort_error1.phpt
new file mode 100644
index 0000000..0fe6126
--- /dev/null
+++ b/ext/spl/tests/arrayObject_usort_error1.phpt
@@ -0,0 +1,30 @@
+--TEST--
+Test ArrayObject::usort() function : wrong arg count
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::usort(callback cmp_function)
+ * Description: proto int ArrayIterator::usort(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->usort();
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+
+try {
+	$ao->usort(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_usort_error2.phpt b/ext/spl/tests/arrayObject_usort_error2.phpt
new file mode 100644
index 0000000..b330d4a
--- /dev/null
+++ b/ext/spl/tests/arrayObject_usort_error2.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Test ArrayObject::usort() function : wrong arg count
+--FILE--
+<?php
+/* Prototype  : int ArrayObject::usort(callback cmp_function)
+ * Description: proto int ArrayIterator::usort(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 {
+	usort($ao);
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+
+try {
+	usort($ao,1,2);
+} catch (BadMethodCallException $e) {
+	echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECTF--
+Warning: usort() expects exactly 2 parameters, 1 given in %sarrayObject_usort_error2.php on line %d
+
+Warning: usort() expects exactly 2 parameters, 3 given in %sarrayObject_usort_error2.php on line %d
+===DONE===
diff --git a/ext/standard/array.c b/ext/standard/array.c
index f480659..11d6472 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -238,16 +238,38 @@ PHP_FUNCTION(krsort)
 	zval *array;
 	long sort_type = PHP_SORT_REGULAR;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &sort_type) == FAILURE) {
 		RETURN_FALSE;
 	}
 
 	php_set_compare_func(sort_type TSRMLS_CC);
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) {
-		RETURN_FALSE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its krsort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zval *arg;
+				MAKE_STD_ZVAL(arg);
+				ZVAL_LONG(arg, sort_type);
+				zend_call_method_with_1_params(&array, NULL, NULL, "krsort", &retval, arg);
+				zval_ptr_dtor(&arg);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+				RETURN_FALSE;
+			}
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) {
+				RETURN_FALSE;
+			}
+			RETURN_TRUE;
+		}
 	}
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -258,16 +280,38 @@ PHP_FUNCTION(ksort)
 	zval *array;
 	long sort_type = PHP_SORT_REGULAR;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &sort_type) == FAILURE) {
 		RETURN_FALSE;
 	}
 
 	php_set_compare_func(sort_type TSRMLS_CC);
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_key_compare, 0 TSRMLS_CC) == FAILURE) {
-		RETURN_FALSE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its ksort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zval *arg;
+				MAKE_STD_ZVAL(arg);
+				ZVAL_LONG(arg, sort_type);
+				zend_call_method_with_1_params(&array, NULL, NULL, "ksort", &retval, arg);
+				zval_ptr_dtor(&arg);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+				RETURN_FALSE;
+			}
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_key_compare, 0 TSRMLS_CC) == FAILURE) {
+				RETURN_FALSE;
+			}
+			RETURN_TRUE;
+		}
 	}
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -457,21 +501,43 @@ static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
 {
 	zval *array;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &array) == FAILURE) {
 		return;
 	}
 
-	if (fold_case) {
-		if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) {
-			return;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its natXsort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				if (fold_case) {
+					zend_call_method_with_0_params(&array, NULL, NULL, "natcasesort", &retval);
+				}
+				else {
+					zend_call_method_with_0_params(&array, NULL, NULL, "natsort", &retval);
+				}
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
 		}
-	} else {
-		if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_compare, 0 TSRMLS_CC) == FAILURE) {
-			return;
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
+				return;
+			}
+
+			if (fold_case) {
+				if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) {
+					return;
+				}
+			} else {
+				if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_compare, 0 TSRMLS_CC) == FAILURE) {
+					return;
+				}
+			}
+			RETURN_TRUE;
 		}
 	}
-
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -498,16 +564,38 @@ PHP_FUNCTION(asort)
 	zval *array;
 	long sort_type = PHP_SORT_REGULAR;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &sort_type) == FAILURE) {
 		RETURN_FALSE;
 	}
 
 	php_set_compare_func(sort_type TSRMLS_CC);
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 0 TSRMLS_CC) == FAILURE) {
-		RETURN_FALSE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its asort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zval *arg;
+				MAKE_STD_ZVAL(arg);
+				ZVAL_LONG(arg, sort_type);
+				zend_call_method_with_1_params(&array, NULL, NULL, "asort", &retval, arg);
+				zval_ptr_dtor(&arg);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+				RETURN_FALSE;
+			}
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 0 TSRMLS_CC) == FAILURE) {
+				RETURN_FALSE;
+			}
+			RETURN_TRUE;
+		}
 	}
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -518,16 +606,38 @@ PHP_FUNCTION(arsort)
 	zval *array;
 	long sort_type = PHP_SORT_REGULAR;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &sort_type) == FAILURE) {
 		RETURN_FALSE;
 	}
 
 	php_set_compare_func(sort_type TSRMLS_CC);
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) {
-		RETURN_FALSE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its arsort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zval *arg;
+				MAKE_STD_ZVAL(arg);
+				ZVAL_LONG(arg, sort_type);
+				zend_call_method_with_1_params(&array, NULL, NULL, "arsort", &retval, arg);
+				zval_ptr_dtor(&arg);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+				RETURN_FALSE;
+			}
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) {
+				RETURN_FALSE;
+			}
+			RETURN_TRUE;
+		}
 	}
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -538,16 +648,38 @@ PHP_FUNCTION(sort)
 	zval *array;
 	long sort_type = PHP_SORT_REGULAR;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &sort_type) == FAILURE) {
 		RETURN_FALSE;
 	}
 
 	php_set_compare_func(sort_type TSRMLS_CC);
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 1 TSRMLS_CC) == FAILURE) {
-		RETURN_FALSE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its sort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zval *arg;
+				MAKE_STD_ZVAL(arg);
+				ZVAL_LONG(arg, sort_type);
+				zend_call_method_with_1_params(&array, NULL, NULL, "sort", &retval, arg);
+				zval_ptr_dtor(&arg);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+				RETURN_FALSE;
+			}
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 1 TSRMLS_CC) == FAILURE) {
+				RETURN_FALSE;
+			}
+			RETURN_TRUE;
+		}
 	}
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -558,16 +690,38 @@ PHP_FUNCTION(rsort)
 	zval *array;
 	long sort_type = PHP_SORT_REGULAR;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &sort_type) == FAILURE) {
 		RETURN_FALSE;
 	}
 
 	php_set_compare_func(sort_type TSRMLS_CC);
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 1 TSRMLS_CC) == FAILURE) {
-		RETURN_FALSE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its rsort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zval *arg;
+				MAKE_STD_ZVAL(arg);
+				ZVAL_LONG(arg, sort_type);
+				zend_call_method_with_1_params(&array, NULL, NULL, "rsort", &retval, arg);
+				zval_ptr_dtor(&arg);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
+				RETURN_FALSE;
+			}
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 1 TSRMLS_CC) == FAILURE) {
+				RETURN_FALSE;
+			}
+			RETURN_TRUE;
+		}
 	}
-	RETURN_TRUE;
 }
 /* }}} */
 
@@ -635,41 +789,59 @@ static int php_array_user_compare(const void *a, const void *b TSRMLS_DC) /* {{{
 PHP_FUNCTION(usort)
 {
 	zval *array;
+	zval *cmp_function;
 	unsigned int refcount;
 	PHP_ARRAY_CMP_FUNC_VARS;
 
-	PHP_ARRAY_CMP_FUNC_BACKUP();
-
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
-		PHP_ARRAY_CMP_FUNC_RESTORE();
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &array, &cmp_function) == FAILURE) {
 		return;
 	}
 
-	/* Clear the is_ref flag, so the attemts to modify the array in user
-	 * comparison function will create a copy of array and won't affect the
-	 * original array. The fact of modification is detected using refcount
-	 * comparison. The result of sorting in such case is undefined and the
-	 * function returns FALSE.
-	 */
-	Z_UNSET_ISREF_P(array);
-	refcount = Z_REFCOUNT_P(array);
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its usort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zend_call_method_with_1_params(&array, NULL, NULL, "usort", &retval, cmp_function);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
+		}
+		default: {
+			PHP_ARRAY_CMP_FUNC_BACKUP();
+
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
+				PHP_ARRAY_CMP_FUNC_RESTORE();
+				return;
+			}
+			/* Clear the is_ref flag, so the attemts to modify the array in user
+			 * comparison function will create a copy of array and won't affect the
+			 * original array. The fact of modification is detected using refcount
+			 * comparison. The result of sorting in such case is undefined and the
+			 * function returns FALSE.
+			 */
+			Z_UNSET_ISREF_P(array);
+			refcount = Z_REFCOUNT_P(array);
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 1 TSRMLS_CC) == FAILURE) {
+				RETVAL_FALSE;
+			} else {
+				if (refcount > Z_REFCOUNT_P(array)) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
+					RETVAL_FALSE;
+				} else {
+					RETVAL_TRUE;
+				}
+			}
+
+			if (Z_REFCOUNT_P(array) > 1) {
+				Z_SET_ISREF_P(array);
+			}
 
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 1 TSRMLS_CC) == FAILURE) {
-		RETVAL_FALSE;
-	} else {
-		if (refcount > Z_REFCOUNT_P(array)) {
-			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
-			RETVAL_FALSE;
-		} else {
-			RETVAL_TRUE;
+			PHP_ARRAY_CMP_FUNC_RESTORE();
 		}
 	}
-	
-	if (Z_REFCOUNT_P(array) > 1) {
-		Z_SET_ISREF_P(array);
-	}
-
-	PHP_ARRAY_CMP_FUNC_RESTORE();
 }
 /* }}} */
 
@@ -678,41 +850,59 @@ PHP_FUNCTION(usort)
 PHP_FUNCTION(uasort)
 {
 	zval *array;
+	zval *cmp_function;
 	unsigned int refcount;
 	PHP_ARRAY_CMP_FUNC_VARS;
 
-	PHP_ARRAY_CMP_FUNC_BACKUP();
-
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
-		PHP_ARRAY_CMP_FUNC_RESTORE();
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &array, &cmp_function) == FAILURE) {
 		return;
 	}
 
-	/* Clear the is_ref flag, so the attemts to modify the array in user
-	 * comaprison function will create a copy of array and won't affect the
-	 * original array. The fact of modification is detected using refcount
-	 * comparison. The result of sorting in such case is undefined and the
-	 * function returns FALSE.
-	 */
-	Z_UNSET_ISREF_P(array);
-	refcount = Z_REFCOUNT_P(array);
-
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 0 TSRMLS_CC) == FAILURE) {
-		RETVAL_FALSE;
-	} else {
-		if (refcount > Z_REFCOUNT_P(array)) {
-			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
-			RETVAL_FALSE;
-		} else {
-			RETVAL_TRUE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its uasort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zend_call_method_with_1_params(&array, NULL, NULL, "uasort", &retval, cmp_function);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
 		}
-	}
+		default: {
+			PHP_ARRAY_CMP_FUNC_BACKUP();
 
-	if (Z_REFCOUNT_P(array) > 1) {
-		Z_SET_ISREF_P(array);
-	}
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
+				PHP_ARRAY_CMP_FUNC_RESTORE();
+				return;
+			}
+			/* Clear the is_ref flag, so the attemts to modify the array in user
+			 * comparison function will create a copy of array and won't affect the
+			 * original array. The fact of modification is detected using refcount
+			 * comparison. The result of sorting in such case is undefined and the
+			 * function returns FALSE.
+			 */
+			Z_UNSET_ISREF_P(array);
+			refcount = Z_REFCOUNT_P(array);
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 0 TSRMLS_CC) == FAILURE) {
+				RETVAL_FALSE;
+			} else {
+				if (refcount > Z_REFCOUNT_P(array)) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
+					RETVAL_FALSE;
+				} else {
+					RETVAL_TRUE;
+				}
+			}
 
-	PHP_ARRAY_CMP_FUNC_RESTORE();
+			if (Z_REFCOUNT_P(array) > 1) {
+				Z_SET_ISREF_P(array);
+			}
+
+			PHP_ARRAY_CMP_FUNC_RESTORE();
+		}
+	}
 }
 /* }}} */
 
@@ -774,41 +964,59 @@ static int php_array_user_key_compare(const void *a, const void *b TSRMLS_DC) /*
 PHP_FUNCTION(uksort)
 {
 	zval *array;
+	zval *cmp_function;
 	unsigned int refcount;
 	PHP_ARRAY_CMP_FUNC_VARS;
 
-	PHP_ARRAY_CMP_FUNC_BACKUP();
-
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
-		PHP_ARRAY_CMP_FUNC_RESTORE();
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &array, &cmp_function) == FAILURE) {
 		return;
 	}
 
-	/* Clear the is_ref flag, so the attemts to modify the array in user
-	 * comaprison function will create a copy of array and won't affect the
-	 * original array. The fact of modification is detected using refcount
-	 * comparison. The result of sorting in such case is undefined and the
-	 * function returns FALSE.
-	 */
-	Z_UNSET_ISREF_P(array);
-	refcount = Z_REFCOUNT_P(array);
-
-	if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
-		RETVAL_FALSE;
-	} else {
-		if (refcount > Z_REFCOUNT_P(array)) {
-			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
-			RETVAL_FALSE;
-		} else {
-			RETVAL_TRUE;
+	switch (Z_TYPE_P(array)) {
+		case IS_OBJECT: {
+#ifdef HAVE_SPL
+			zval *retval;
+			/* If the object implements Sortable we call its uksort() method */
+			if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Sortable TSRMLS_CC)) {
+				zend_call_method_with_1_params(&array, NULL, NULL, "uksort", &retval, cmp_function);
+				RETURN_ZVAL(retval, 1, 0);
+			}
+#endif
 		}
-	}
+		default: {
+			PHP_ARRAY_CMP_FUNC_BACKUP();
 
-	if (Z_REFCOUNT_P(array) > 1) {
-		Z_SET_ISREF_P(array);
-	}
+			if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
+				PHP_ARRAY_CMP_FUNC_RESTORE();
+				return;
+			}
+			/* Clear the is_ref flag, so the attemts to modify the array in user
+			 * comparison function will create a copy of array and won't affect the
+			 * original array. The fact of modification is detected using refcount
+			 * comparison. The result of sorting in such case is undefined and the
+			 * function returns FALSE.
+			 */
+			Z_UNSET_ISREF_P(array);
+			refcount = Z_REFCOUNT_P(array);
+
+			if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
+				RETVAL_FALSE;
+			} else {
+				if (refcount > Z_REFCOUNT_P(array)) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
+					RETVAL_FALSE;
+				} else {
+					RETVAL_TRUE;
+				}
+			}
 
-	PHP_ARRAY_CMP_FUNC_RESTORE();
+			if (Z_REFCOUNT_P(array) > 1) {
+				Z_SET_ISREF_P(array);
+			}
+
+			PHP_ARRAY_CMP_FUNC_RESTORE();
+		}
+	}
 }
 /* }}} */
 
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 21:01:28 2024 UTC