diff --git a/README.md b/README.md index 48c584d..22e8051 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ See [stubs](stubs/) directory for signature of all classes and methods of this e The `Collection` class implements `ArrayAccess` and `Countable` interface internally, you can treat an instance of `Collection` as an `ArrayObject`. * The `isset()`, `unset()` keywords can be used on elements of `Collection`. -* Elements can be accessed via property (string keys only) and bracket expression. +* Elements can be accessed via property and bracket expression. * `empty()`, `count()` can be used on instance of `Collection`. * Elements can be traversed via `foreach()` keyword. @@ -48,7 +48,7 @@ $names = Collection::init($employees) ->sortedByDescending(function ($value) { return $value['age']; }) - ->map(function ($value) { + ->mapValues(function ($value) { return $value['name']; }) ->toArray(); diff --git a/src/collections_methods.c b/src/collections_methods.c index d32aa3b..a4db1de 100644 --- a/src/collections_methods.c +++ b/src/collections_methods.c @@ -5,6 +5,7 @@ // #include +#include #include "php_collections.h" #include "php_collections_me.h" @@ -1142,17 +1143,77 @@ PHP_METHOD(Collection, reduceRight) PHP_METHOD(Collection, remove) { - + zval* key; + zval* value = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(key) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(value) + ZEND_PARSE_PARAMETERS_END(); + zend_array* current = COLLECTION_FETCH_CURRENT(); + zval* found; + if (Z_TYPE_P(key) == IS_LONG) { + if (value == NULL) + RETURN_BOOL(zend_hash_index_del(current, Z_LVAL_P(key)) == SUCCESS); + found = zend_hash_index_find(current, Z_LVAL_P(key)); + if (found == NULL || fast_equal_check_function(found, value) == 0) + RETURN_FALSE; + RETURN_BOOL(zend_hash_index_del(current, Z_LVAL_P(key)) == SUCCESS); + } + if (Z_TYPE_P(key) == IS_STRING) { + if (value == NULL) + RETURN_BOOL(zend_hash_del(current, Z_STR_P(key)) == SUCCESS); + found = zend_hash_find(current, Z_STR_P(key)); + if (found == NULL || fast_equal_check_function(found, value) == 0) + RETURN_FALSE; + RETURN_BOOL(zend_hash_del(current, Z_STR_P(key)) == SUCCESS); + } + ERR_BAD_KEY_TYPE(); + RETVAL_FALSE; } PHP_METHOD(Collection, removeAll) { - + zend_fcall_info fci; + zend_fcall_info_cache fcc; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_FUNC(fci, fcc) + ZEND_PARSE_PARAMETERS_END(); + zend_array* current = COLLECTION_FETCH_CURRENT(); + SEPARATE_CURRENT_COLLECTION(current); + if (EX_NUM_ARGS() == 0) { + zend_hash_clean(current); + return; + } + INIT_FCI(2); + ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) + CALLBACK_KEYVAL_INVOKE(params, bucket); + if (zend_is_true(&retval)) + zend_hash_del_bucket(current, bucket); + ZEND_HASH_FOREACH_END(); } PHP_METHOD(Collection, retainAll) { - + zend_fcall_info fci; + zend_fcall_info_cache fcc; + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_FUNC(fci, fcc) + ZEND_PARSE_PARAMETERS_END(); + zend_array* current = COLLECTION_FETCH_CURRENT(); + SEPARATE_CURRENT_COLLECTION(current); + if (EX_NUM_ARGS() == 0) { + zend_hash_clean(current); + return; + } + INIT_FCI(2); + ZEND_HASH_FOREACH_BUCKET(current, Bucket* bucket) + CALLBACK_KEYVAL_INVOKE(params, bucket); + if (!zend_is_true(&retval)) + zend_hash_del_bucket(current, bucket); + ZEND_HASH_FOREACH_END(); } PHP_METHOD(Collection, reverse) @@ -1179,12 +1240,13 @@ PHP_METHOD(Collection, set) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); zend_array* current = COLLECTION_FETCH_CURRENT(); - SEPARATE_CURRENT_COLLECTION(current); - if (Z_TYPE_P(key) == IS_STRING) + if (Z_TYPE_P(key) == IS_STRING) { + SEPARATE_CURRENT_COLLECTION(current); zend_hash_update(current, Z_STR_P(key), value); - else if (Z_TYPE_P(key) == IS_LONG) + } else if (Z_TYPE_P(key) == IS_LONG) { + SEPARATE_CURRENT_COLLECTION(current); zend_hash_index_update(current, Z_LVAL_P(key), value); - else + } else ERR_BAD_KEY_TYPE(); } diff --git a/stubs/Collection.php b/stubs/Collection.php index 6928203..c400a0d 100644 --- a/stubs/Collection.php +++ b/stubs/Collection.php @@ -680,14 +680,16 @@ class Collection implements ArrayAccess, Countable * * @param int|string $key * @param mixed $value[optional] + * @return bool */ function remove($key, $value) {} /** - * Removes all elements from this collection that match the given predicate. + * Removes all elements from this collection that match the given predicate. If predicate is not + * provided, all elements will be removed. * - * @param callable $predicate ($value, $key) -> bool - * @return bool + * @param callable $predicate[optional] ($value, $key) -> bool + * @return void */ function removeAll($predicate) {} @@ -695,7 +697,7 @@ class Collection implements ArrayAccess, Countable * Retains only elements of this collection that match the given predicate. * * @param callable $predicate ($value, $key) -> bool - * @return bool + * @return void */ function retainAll($predicate) {} diff --git a/tests/027-get-set.phpt b/tests/027-get-set-remove.phpt similarity index 68% rename from tests/027-get-set.phpt rename to tests/027-get-set-remove.phpt index 448d0e7..f733133 100644 --- a/tests/027-get-set.phpt +++ b/tests/027-get-set-remove.phpt @@ -13,5 +13,9 @@ if ($collection->toArray() != $array) if ($collection->get('a') != $array['a'] || $collection->get('f', function ($key) { return $key; }) != 'f') echo 'Collection::get() failed.', PHP_EOL; +if (!$collection->remove('a') || !is_null($collection->get('a'))) + echo 'Collection::remove() failed.', PHP_EOL; +if ($collection->remove('c', 'e') || $collection->get('c') != 'd') + echo 'Collection::remove() failed.', PHP_EOL; ?> --EXPECT-- diff --git a/tests/029-remove-retain-all.phpt b/tests/029-remove-retain-all.phpt new file mode 100644 index 0000000..f10d883 --- /dev/null +++ b/tests/029-remove-retain-all.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test Collection::removeAll() and Collection::retainAll(). +--FILE-- + 4, 'b' => 1, 'c' => 9, 'd' => -2, 'e' => 0]; +$pred_is_odd = function ($value) { + return $value % 2; +}; +$collection = Collection::init($array); +$collection->removeAll($pred_is_odd); +if ($collection->toArray() != ['a' => 4, 'd' => -2, 'e' => 0]) + echo 'Collection::removeAll() failed.', PHP_EOL; +$collection->removeAll(); +if ($collection->toArray() != []) + echo 'Collection::removeAll() failed.', PHP_EOL; +$collection = Collection::init($array); +$collection->retainAll($pred_is_odd); +if ($collection->toArray() != ['b' => 1, 'c' => 9]) + echo 'Collection::retainAll() failed.', PHP_EOL; +?> +--EXPECT--