├── .gitignore ├── .gitmodules ├── .travis.yml ├── CREDITS ├── EXPERIMENTAL ├── LICENSE ├── README.md ├── collection.c ├── collection.php ├── config.m4 ├── config.w32 ├── example ├── all.php ├── avg.php ├── chunk.php ├── collapse.php ├── combine.php ├── concat.php ├── contains.php ├── count.php ├── diff.php ├── diffAssoc.php ├── every.php ├── except.php ├── filter.php ├── first.php ├── firstWhere.php ├── flatMap.php ├── flatten.php ├── flip.php ├── forget.php ├── forpage.php ├── get.php ├── groupBy.php ├── has.php ├── implode.php ├── init.php ├── intersect.php ├── intersectByKeys.php ├── isEmpty.php ├── isNotEmpty.php ├── key_by.php ├── keys.php ├── last.php ├── map.php ├── mapToGroups.php ├── max.php └── toarray.php ├── image └── cover.jpg ├── php_collection.h ├── src ├── common.c ├── common.h ├── exception.c ├── include.h ├── kernel.c └── method.c ├── tests ├── all.phpt ├── avg.phpt ├── chunk.phpt ├── collapse.phpt ├── combine.phpt ├── concat.phpt ├── contains.phpt ├── count.phpt ├── diff.phpt ├── diff_assoc.phpt ├── every.phpt ├── except.phpt ├── filter.phpt ├── first.phpt ├── first_where.phpt ├── flat_map.phpt ├── flatten.phpt ├── flip.phpt ├── for_page.phpt ├── forget.phpt ├── get.phpt ├── group_by.phpt ├── has.phpt ├── implode.phpt ├── init.phpt ├── intersect.phpt ├── intersect_by_key.phpt ├── is_empty.phpt ├── is_not_empty.phpt ├── key_by.phpt ├── keys.phpt ├── last.phpt ├── load.phpt ├── map.phpt ├── map_to_groups.phpt ├── max.phpt └── toarray.phpt └── travis └── run-test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | *.lo 3 | *.la 4 | .libs 5 | acinclude.m4 6 | aclocal.m4 7 | autom4te.cache 8 | build 9 | config.guess 10 | config.h 11 | config.h.in 12 | config.log 13 | config.nice 14 | config.status 15 | config.sub 16 | configure 17 | configure.in 18 | include 19 | install-sh 20 | libtool 21 | ltmain.sh 22 | Makefile 23 | Makefile.fragments 24 | Makefile.global 25 | Makefile.objects 26 | missing 27 | mkinstalldirs 28 | modules 29 | run-tests.php 30 | tests/*/*.diff 31 | tests/*/*.out 32 | tests/*/*.php 33 | tests/*/*.exp 34 | tests/*/*.log 35 | tests/*/*.sh 36 | /.vscode 37 | .idea/ 38 | CMakeLists.txt 39 | cmake-build-debug/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viest/php-ext-collection/8bf52852a2160186a74acd825be8b692b0685aa0/.gitmodules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | os: 8 | - linux 9 | 10 | php: 11 | - 7.0 12 | - 7.1 13 | - 7.2 14 | 15 | notifications: 16 | email: dev@service.viest.me 17 | 18 | before_script: 19 | - phpize && ./configure && make clean && make 20 | 21 | branches: 22 | only: 23 | - master 24 | - refactoring 25 | script: 26 | - ./travis/run-test.sh -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | collection 2 | -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viest/php-ext-collection/8bf52852a2160186a74acd825be8b692b0685aa0/EXPERIMENTAL -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 viest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

6 | Build Status 7 |

8 | 9 | ## 介绍: 10 | `vcollect` 是一个PHP c extension,提供流畅、便利的数组数据操作。 11 | 12 | ******* 13 | 14 | ## 安装: 15 | 16 | #### 1、Clone 17 | 18 | 定位于PHP下的ext目录,执行 19 | ```bash 20 | https://github.com/viest/php-ext-collection 21 | ``` 22 | 23 | #### 2、编译安装 24 | 25 | 在扩展目录内,执行 26 | ```bash 27 | phpize 28 | ./configure 29 | make && make install 30 | ``` 31 | 32 | #### 3、修改ini 33 | 34 | 在php.ini文件中加入`extension = collection.so` 35 | 36 | ## 使用 37 | 38 | #### 创建集合 39 | 40 | ```php 41 | $collection = \Vtiful\Kernel\Collection::init([1]); 42 | ``` 43 | 44 | #### Documention 45 | 46 | [wiki](https://github.com/VikinDev/v-collect/wiki) 47 | 48 | ## License 49 | 50 | MIT -------------------------------------------------------------------------------- /collection.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #ifdef HAVE_CONFIG_H 14 | #include "config.h" 15 | #endif 16 | 17 | #include "php.h" 18 | #include "php_ini.h" 19 | #include "ext/standard/info.h" 20 | #include "php_collection.h" 21 | 22 | #include "src/include.h" 23 | 24 | /* {{{ PHP_MINIT_FUNCTION 25 | */ 26 | PHP_MINIT_FUNCTION(collection) 27 | { 28 | COLLECTION_STARTUP_MODULE(kernel); 29 | COLLECTION_STARTUP_MODULE(exception); 30 | 31 | return SUCCESS; 32 | } 33 | /* }}} */ 34 | 35 | /* {{{ PHP_MSHUTDOWN_FUNCTION 36 | */ 37 | PHP_MSHUTDOWN_FUNCTION(collection) 38 | { 39 | return SUCCESS; 40 | } 41 | /* }}} */ 42 | 43 | /* {{{ PHP_RINIT_FUNCTION 44 | */ 45 | PHP_RINIT_FUNCTION(collection) 46 | { 47 | #if defined(COMPILE_DL_COLLECTION) && defined(ZTS) 48 | ZEND_TSRMLS_CACHE_UPDATE(); 49 | #endif 50 | return SUCCESS; 51 | } 52 | /* }}} */ 53 | 54 | /* {{{ PHP_RSHUTDOWN_FUNCTION 55 | */ 56 | PHP_RSHUTDOWN_FUNCTION(collection) 57 | { 58 | return SUCCESS; 59 | } 60 | /* }}} */ 61 | 62 | /* {{{ PHP_MINFO_FUNCTION 63 | */ 64 | PHP_MINFO_FUNCTION(collection) 65 | { 66 | php_info_print_table_start(); 67 | php_info_print_table_header(2, "collection support", "enabled"); 68 | php_info_print_table_end(); 69 | 70 | #if defined(PHP_COLLECTION_VERSION) 71 | php_info_print_table_row(2, "Collection Version", PHP_COLLECTION_VERSION); 72 | #endif 73 | 74 | php_info_print_table_end(); 75 | } 76 | /* }}} */ 77 | 78 | /* {{{ collection_functions[] 79 | */ 80 | const zend_function_entry collection_functions[] = { 81 | PHP_FE_END /* Must be the last line in collection_functions[] */ 82 | }; 83 | /* }}} */ 84 | 85 | /* {{{ collection_module_entry 86 | */ 87 | zend_module_entry collection_module_entry = { 88 | STANDARD_MODULE_HEADER, 89 | "collection", 90 | collection_functions, 91 | PHP_MINIT(collection), 92 | PHP_MSHUTDOWN(collection), 93 | PHP_RINIT(collection), 94 | PHP_RSHUTDOWN(collection), 95 | PHP_MINFO(collection), 96 | PHP_COLLECTION_VERSION, 97 | STANDARD_MODULE_PROPERTIES 98 | }; 99 | /* }}} */ 100 | 101 | #ifdef COMPILE_DL_COLLECTION 102 | #ifdef ZTS 103 | ZEND_TSRMLS_CACHE_DEFINE() 104 | #endif 105 | ZEND_GET_MODULE(collection) 106 | #endif 107 | 108 | /* 109 | * Local variables: 110 | * tab-width: 4 111 | * c-basic-offset: 4 112 | * End: 113 | * vim600: noet sw=4 ts=4 fdm=marker 114 | * vim<600: noet sw=4 ts=4 115 | */ 116 | -------------------------------------------------------------------------------- /collection.php: -------------------------------------------------------------------------------- 1 | "; 3 | 4 | if(!extension_loaded('vcollect')) { 5 | dl('vcollect.' . PHP_SHLIB_SUFFIX); 6 | } 7 | $module = 'vcollect'; 8 | $functions = get_extension_funcs($module); 9 | echo "Functions available in the test extension:$br\n"; 10 | foreach($functions as $func) { 11 | echo $func."$br\n"; 12 | } 13 | echo "$br\n"; 14 | $function = 'confirm_' . $module . '_compiled'; 15 | if (extension_loaded($module)) { 16 | $str = $function($module); 17 | } else { 18 | $str = "Module $module is not compiled into PHP"; 19 | } 20 | echo "$str\n"; 21 | ?> 22 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH(collection, for collection support, 2 | [ --with-collection Include collection support]) 3 | 4 | if test "$PHP_COLLECTION" != "no"; then 5 | PHP_ADD_EXTENSION_DEP(collection, ds) 6 | 7 | PHP_NEW_EXTENSION(collection, collection.c src/kernel.c src/method.c src/exception.c src/common.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) 8 | 9 | PHP_ADD_BUILD_DIR([$ext_builddir/src]) 10 | fi -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | // If your extension references something external, use ARG_WITH 5 | // ARG_WITH("vcollect", "for vcollect support", "no"); 6 | 7 | // Otherwise, use ARG_ENABLE 8 | // ARG_ENABLE("vcollect", "enable vcollect support", "no"); 9 | 10 | if (PHP_VCOLLECT != "no") { 11 | EXTENSION("vcollect", "vcollect_application.c vcollect_common.c vcollect.c", PHP_EXTNAME_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /example/all.php: -------------------------------------------------------------------------------- 1 | all(); 8 | 9 | var_dump($result1); -------------------------------------------------------------------------------- /example/avg.php: -------------------------------------------------------------------------------- 1 | avg(); 8 | 9 | var_dump($result1); 10 | 11 | $collection2 = \Vtiful\Kernel\Collection::init([ 12 | ['name' => 'vikin', 'age' => 20], 13 | ['name' => 'viest', 'age' => 30] 14 | ]); 15 | 16 | $result2 = $collection2->avg('age'); 17 | 18 | var_dump($result2); -------------------------------------------------------------------------------- /example/chunk.php: -------------------------------------------------------------------------------- 1 | chunk(4); 8 | 9 | var_dump($result); -------------------------------------------------------------------------------- /example/collapse.php: -------------------------------------------------------------------------------- 1 | collapse(); 8 | 9 | var_dump($result1); 10 | 11 | var_dump($result1->count()); 12 | var_dump($result1->toArray()); -------------------------------------------------------------------------------- /example/combine.php: -------------------------------------------------------------------------------- 1 | combine(['George', 29]); 6 | 7 | var_dump($result1); -------------------------------------------------------------------------------- /example/concat.php: -------------------------------------------------------------------------------- 1 | concat(['address'])->concat([12])->concat([ 6 | 'obj' => new \stdClass() 7 | ]); 8 | 9 | var_dump($result1); -------------------------------------------------------------------------------- /example/contains.php: -------------------------------------------------------------------------------- 1 | 'Desk', 'price' => 100]); 4 | 5 | $true = $collection->contains('Desk'); 6 | 7 | var_dump($true); 8 | 9 | $false = $collection->contains('New York'); 10 | 11 | var_dump($false); 12 | 13 | $collection = \Vtiful\Kernel\Collection::init([ 14 | ['product' => 'Desk', 'price' => 200, 'VV'], 15 | ['product' => 'Chair', 'price' => 100, 'BB'], 16 | ]); 17 | 18 | $true2 = $collection->contains('product', 'Desk'); 19 | 20 | var_dump($true2); 21 | 22 | $false2 = $collection->contains('product', 'Bookcase'); 23 | 24 | var_dump($false2); 25 | 26 | -------------------------------------------------------------------------------- /example/count.php: -------------------------------------------------------------------------------- 1 | count(); 8 | 9 | var_dump($result); -------------------------------------------------------------------------------- /example/diff.php: -------------------------------------------------------------------------------- 1 | diff([ 8 | 2, 4, 6, 8 9 | ]); 10 | 11 | var_dump($result); -------------------------------------------------------------------------------- /example/diffAssoc.php: -------------------------------------------------------------------------------- 1 | 'orange', 5 | 'type' => 'fruit', 6 | 'remain' => 6 7 | ]); 8 | 9 | $diff = $collection->diffAssoc([ 10 | 'color' => 'yellow', 11 | 'type' => 'fruit', 12 | 'remain' => 3, 13 | 'used' => 6 14 | ]); 15 | 16 | var_dump($diff); -------------------------------------------------------------------------------- /example/every.php: -------------------------------------------------------------------------------- 1 | every(function ($value, $key) { 8 | return $value > 0; 9 | }); 10 | 11 | var_dump($result); -------------------------------------------------------------------------------- /example/except.php: -------------------------------------------------------------------------------- 1 | 1, 5 | 'price' => 100, 6 | 'discount' => false, 7 | ]); 8 | 9 | $filtered = $collection->except([ 10 | 'price', 11 | 'discount', 12 | ]); 13 | 14 | var_dump($filtered); -------------------------------------------------------------------------------- /example/filter.php: -------------------------------------------------------------------------------- 1 | filter(function ($value, $key) { 9 | return $value > 2; 10 | }); 11 | 12 | var_dump($callbackRes); 13 | 14 | 15 | // 没有传递回调函数 16 | $collection2 = \Vtiful\Kernel\Collection::init([ 17 | 1, 2, 3, null, false, '', 0, [] 18 | ]); 19 | 20 | $noCallback = $collection2->filter(); 21 | 22 | var_dump($noCallback); -------------------------------------------------------------------------------- /example/first.php: -------------------------------------------------------------------------------- 1 | first(function ($value, $key) { 8 | return $value > 2; 9 | }); 10 | 11 | $noCollback = $collection->first(); 12 | 13 | var_dump($collbackRes); 14 | var_dump($noCollback); 15 | -------------------------------------------------------------------------------- /example/firstWhere.php: -------------------------------------------------------------------------------- 1 | 'Regena', 'age' => 12], 5 | ['name' => 'Linda', 'age' => 14], 6 | ['name' => 'Diego', 'age' => 23], 7 | ['name' => 'Linda', 'age' => 84], 8 | ]); 9 | 10 | $result1 = $collection->firstWhere('name', 'Linda'); 11 | $result2 = $collection->firstWhere('age', '>=', 18); 12 | 13 | var_dump($result1); 14 | var_dump($result2); -------------------------------------------------------------------------------- /example/flatMap.php: -------------------------------------------------------------------------------- 1 | 'Sally'], 5 | ['school' => 'Arkansas'], 6 | ['age' => 28] 7 | ]); 8 | 9 | $flattened = $collection->flatMap(function ($values) { 10 | return array_map('strtoupper', $values); 11 | }); 12 | 13 | var_dump($flattened); 14 | -------------------------------------------------------------------------------- /example/flatten.php: -------------------------------------------------------------------------------- 1 | 'viest', 5 | 'languages' => [ 6 | 'php', 'c' 7 | ] 8 | ]); 9 | 10 | $flattened = $collection1->flatten(); 11 | 12 | var_dump($flattened); 13 | 14 | $collection2 = \Vtiful\Kernel\Collection::init([ 15 | 'Apple' => [ 16 | ['name' => 'iPhone 6S', 'brand' => 'Apple'], 17 | ], 18 | 'Samsung' => [ 19 | ['name' => 'Galaxy S7', 'brand' => 'Samsung'] 20 | ], 21 | ]); 22 | 23 | $products = $collection2->flatten(2); 24 | 25 | var_dump($products); -------------------------------------------------------------------------------- /example/flip.php: -------------------------------------------------------------------------------- 1 | 'taylor', 5 | 'framework' => 'laravel' 6 | ]); 7 | 8 | $flipped = $collection->flip(); 9 | 10 | var_dump($flipped); -------------------------------------------------------------------------------- /example/forget.php: -------------------------------------------------------------------------------- 1 | 'viest', 5 | 'extension' => 'collection' 6 | ]); 7 | 8 | $result = $collection->forget('name'); 9 | 10 | var_dump($result); -------------------------------------------------------------------------------- /example/forpage.php: -------------------------------------------------------------------------------- 1 | forPage(2, 3); 8 | 9 | var_dump($chunk); -------------------------------------------------------------------------------- /example/get.php: -------------------------------------------------------------------------------- 1 | 'viest', 5 | 'extension' => 'collection', 6 | ]); 7 | 8 | $name = $collection->get('name'); 9 | $null = $collection->get('age'); 10 | $age = $collection->get('age', 22); 11 | 12 | var_dump($name, $null, $age); -------------------------------------------------------------------------------- /example/groupBy.php: -------------------------------------------------------------------------------- 1 | 'account-x10', 'product' => 'Chair'], 5 | ['account_id' => 'account-x10', 'product' => 'Bookcase'], 6 | ['account_id' => 'account-x11', 'product' => 'Desk'], 7 | ]); 8 | 9 | $grouped = $collection->groupBy(function ($item, $key) { 10 | return substr($item['account_id'], -3); 11 | }); 12 | 13 | var_dump($grouped->toArray()); 14 | 15 | $grouped = $collection->groupBy('account_id'); 16 | 17 | var_dump($grouped->toArray()); -------------------------------------------------------------------------------- /example/has.php: -------------------------------------------------------------------------------- 1 | 'viest', 5 | 'age' => 21 6 | ]); 7 | 8 | $true = $collection->has('age'); 9 | $false = $collection->has('address'); 10 | 11 | var_dump($true, $false); -------------------------------------------------------------------------------- /example/implode.php: -------------------------------------------------------------------------------- 1 | implode('-'); 8 | 9 | var_dump($result1); 10 | 11 | $collection2 = \Vtiful\Kernel\Collection::init([ 12 | ['name' => 'viest', 'age' => 21], 13 | ['name' => 'vikin', 'age' => 20], 14 | ['name' => 'wjx', 'age' => 22], 15 | ]); 16 | 17 | $result2 = $collection2->implode('name', '-'); 18 | 19 | var_dump($result2); -------------------------------------------------------------------------------- /example/init.php: -------------------------------------------------------------------------------- 1 | intersect([2, 7, 5, 9, 10, 'b']); 6 | 7 | var_dump($intersect->toArray()); -------------------------------------------------------------------------------- /example/intersectByKeys.php: -------------------------------------------------------------------------------- 1 | 'UX301', 'type' => 'screen', 'year' => 2009 5 | ]); 6 | 7 | $intersect = $collection->intersectByKeys([ 8 | 'reference' => 'UX404', 'type' => 'tab', 'year' => 2011 9 | ]); 10 | 11 | var_dump($intersect); -------------------------------------------------------------------------------- /example/isEmpty.php: -------------------------------------------------------------------------------- 1 | isEmpty(); 6 | 7 | $collection2 = \Vtiful\Kernel\Collection::init([]); 8 | 9 | $false = $collection2->isEmpty(); 10 | 11 | var_dump($true, $false); -------------------------------------------------------------------------------- /example/isNotEmpty.php: -------------------------------------------------------------------------------- 1 | isNotEmpty(); 6 | 7 | $collection2 = \Vtiful\Kernel\Collection::init([]); 8 | 9 | $true = $collection2->isNotEmpty(); 10 | 11 | var_dump($false, $true); -------------------------------------------------------------------------------- /example/key_by.php: -------------------------------------------------------------------------------- 1 | 'prod-100', 'name' => 'Desk'], 5 | ['product_id' => 'prod-200', 'name' => 'Chair'], 6 | ]); 7 | 8 | $keyed1 = $collection1->keyBy('product_id'); 9 | 10 | $collection2 = \Vtiful\Kernel\Collection::init([ 11 | ['product_id' => 'prod-100', 'name' => 'Desk'], 12 | ['product_id' => 'prod-200', 'name' => 'Chair'], 13 | ]); 14 | 15 | $keyed2 = $collection2->keyBy(function ($item) { 16 | return strtoupper($item['product_id']); 17 | }); 18 | 19 | var_dump($keyed1, $keyed2); -------------------------------------------------------------------------------- /example/keys.php: -------------------------------------------------------------------------------- 1 | ['product_id' => 'prod-100', 'name' => 'Desk'], 5 | 'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], 6 | ]); 7 | 8 | $keys = $collection->keys(); 9 | 10 | var_dump($keys); -------------------------------------------------------------------------------- /example/last.php: -------------------------------------------------------------------------------- 1 | last(function ($value, $key) { 6 | return $value < 3; 7 | }); 8 | 9 | $defaultLast = $collection->last(); 10 | 11 | 12 | var_dump($callbackLast, $defaultLast); -------------------------------------------------------------------------------- /example/map.php: -------------------------------------------------------------------------------- 1 | map(function ($item, $key) { 6 | return $item * 2; 7 | }); 8 | 9 | var_dump($multiplied); -------------------------------------------------------------------------------- /example/mapToGroups.php: -------------------------------------------------------------------------------- 1 | 'John Doe', 6 | 'department' => 'Sales', 7 | ],[ 8 | 'name' => 'Jane Doe', 9 | 'department' => 'Sales', 10 | ],[ 11 | 'name' => 'Johnny Doe', 12 | 'department' => 'Marketing', 13 | ] 14 | ]); 15 | 16 | $grouped = $collection->mapToGroups(function ($item, $key) { 17 | return [$item['department'] => $item['name']]; 18 | }); 19 | 20 | var_dump($grouped->toArray()); -------------------------------------------------------------------------------- /example/max.php: -------------------------------------------------------------------------------- 1 | max(); 6 | 7 | var_dump($default); 8 | 9 | $collection2 = \Vtiful\Kernel\Collection::init([ 10 | ['foo' => 10], 11 | ['foo' => 50], 12 | ['foo' => 20], 13 | ]); 14 | 15 | $defaultKey = $collection2->max('foo'); 16 | 17 | var_dump($defaultKey); -------------------------------------------------------------------------------- /example/toarray.php: -------------------------------------------------------------------------------- 1 | toArray(); 8 | 9 | var_dump($result); -------------------------------------------------------------------------------- /image/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viest/php-ext-collection/8bf52852a2160186a74acd825be8b692b0685aa0/image/cover.jpg -------------------------------------------------------------------------------- /php_collection.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #ifndef PHP_COLLECTION_H 14 | #define PHP_COLLECTION_H 15 | 16 | extern zend_module_entry collection_module_entry; 17 | #define phpext_collection_ptr &collection_module_entry 18 | 19 | #define PHP_COLLECTION_VERSION "0.1.0" 20 | 21 | #ifdef PHP_WIN32 22 | # define PHP_COLLECTION_API __declspec(dllexport) 23 | #elif defined(__GNUC__) && __GNUC__ >= 4 24 | # define PHP_COLLECTION_API __attribute__ ((visibility("default"))) 25 | #else 26 | # define PHP_COLLECTION_API 27 | #endif 28 | 29 | #ifdef ZTS 30 | #include "TSRM.h" 31 | #endif 32 | 33 | #define COLLECTION_STARTUP_MODULE(module) ZEND_MODULE_STARTUP_N(vtiful_collection_##module)(INIT_FUNC_ARGS_PASSTHRU) 34 | #define COLLECTION_STARTUP_FUNCTION(module) ZEND_MINIT_FUNCTION(vtiful_collection_##module) 35 | 36 | #if defined(ZTS) && defined(COMPILE_DL_COLLECTION) 37 | ZEND_TSRMLS_CACHE_EXTERN() 38 | #endif 39 | 40 | PHP_MINIT_FUNCTION(collection); 41 | PHP_MSHUTDOWN_FUNCTION(collection); 42 | PHP_RINIT_FUNCTION(collection); 43 | PHP_RSHUTDOWN_FUNCTION(collection); 44 | PHP_MINFO_FUNCTION(collection); 45 | 46 | #endif 47 | 48 | 49 | /* 50 | * Local variables: 51 | * tab-width: 4 52 | * c-basic-offset: 4 53 | * End: 54 | * vim600: noet sw=4 ts=4 fdm=marker 55 | * vim<600: noet sw=4 ts=4 56 | */ 57 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #include "include.h" 14 | #include "common.h" 15 | 16 | double average_no_column(zend_array *current) 17 | { 18 | double sum = 0; 19 | 20 | ZEND_HASH_FOREACH_VAL(current, zval* value) 21 | if (Z_TYPE_P(value) == IS_LONG) { 22 | sum += Z_LVAL_P(value); 23 | } else if (Z_TYPE_P(value) == IS_DOUBLE) { 24 | sum += Z_DVAL_P(value); 25 | } 26 | ZEND_HASH_FOREACH_END(); 27 | 28 | return sum; 29 | } 30 | 31 | double average_column(zend_array *current, zend_string *column) 32 | { 33 | double sum = 0; 34 | 35 | zval args[2], ret_val; 36 | 37 | ZVAL_ARR(&args[0], current); 38 | ZVAL_STR(&args[1], column); 39 | 40 | call_internal_function(INTERNAL_FUN(column), 2, args, &ret_val); 41 | 42 | if (Z_TYPE(ret_val) == IS_ARRAY) { 43 | sum = average_no_column(Z_ARRVAL(ret_val)); 44 | } 45 | 46 | zval_ptr_dtor(&ret_val); 47 | 48 | return sum; 49 | } 50 | 51 | void collection_chunk(zend_array *current, zend_long length, zval *object) 52 | { 53 | zval args[2], ret_val; 54 | 55 | ZVAL_ARR (&args[0], current); 56 | ZVAL_LONG(&args[1], length); 57 | 58 | call_internal_function(INTERNAL_FUN(chunk), 2, args, &ret_val); 59 | 60 | UPDATE_OBJ_COLLECTION(object, &ret_val); 61 | 62 | zval_ptr_dtor(&ret_val); 63 | } 64 | 65 | void collection_collapse(zend_array *z_array_p, zval *ret_val) 66 | { 67 | ZEND_HASH_FOREACH_VAL(z_array_p, zval *zval_p) 68 | if (Z_TYPE_P(zval_p) == IS_ARRAY) { 69 | collection_collapse(Z_ARRVAL_P(zval_p), ret_val); 70 | } else { 71 | add_next_index_zval(ret_val, zval_p); 72 | } 73 | ZEND_HASH_FOREACH_END(); 74 | } 75 | 76 | void collection_combine(zend_array *current_collection, zval *z_arr_val, zval *ret_val) 77 | { 78 | zend_long z_arr_val_length = ZVAL_ARRAY_COUNT(z_arr_val); 79 | 80 | ZEND_HASH_FOREACH_BUCKET(current_collection, Bucket *bucket) 81 | if (bucket->h < z_arr_val_length) { 82 | ZVAL_ARRAY_INSERT_BUCKET_KEY_ZVAL_VAL(ret_val, bucket, z_arr_val); 83 | } 84 | ZEND_HASH_FOREACH_END(); 85 | } 86 | 87 | void collection_concat(zend_array *current_collection, zval *z_arr, zval *ret_val) 88 | { 89 | zend_hash_copy(Z_ARRVAL_P(ret_val), current_collection, zval_add_ref); 90 | 91 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_arr), zval *val) 92 | GC_ZVAL_ADDREF(val); 93 | add_next_index_zval(ret_val, val); 94 | ZEND_HASH_FOREACH_END(); 95 | } 96 | 97 | void collection_in_array_val(zend_array *current_collection, zval *search_val, zval *ret_val) 98 | { 99 | if (Z_TYPE_P(search_val) == IS_LONG) { 100 | ZEND_HASH_FOREACH_VAL(current_collection, zval *val) 101 | if (fast_equal_check_long(search_val, val)) { 102 | ZVAL_TRUE(ret_val); 103 | return; 104 | } 105 | ZEND_HASH_FOREACH_END(); 106 | } else if (Z_TYPE_P(search_val) == IS_STRING) { 107 | ZEND_HASH_FOREACH_VAL(current_collection, zval *val) 108 | if (fast_equal_check_string(search_val, val)) { 109 | ZVAL_TRUE(ret_val); 110 | return; 111 | } 112 | ZEND_HASH_FOREACH_END(); 113 | } else { 114 | ZEND_HASH_FOREACH_VAL(current_collection, zval *val) 115 | if (fast_equal_check_function(search_val, val)) { 116 | ZVAL_TRUE(ret_val); 117 | return; 118 | } 119 | ZEND_HASH_FOREACH_END(); 120 | } 121 | 122 | ZVAL_FALSE(ret_val); 123 | } 124 | 125 | int zval_equal(zval *z1, zval *z2) 126 | { 127 | if (Z_TYPE_P(z1) == IS_LONG && Z_TYPE_P(z2) == IS_LONG) { 128 | if (fast_equal_check_long(z1, z2)) { 129 | return 1; 130 | } 131 | } else if (Z_TYPE_P(z1) == IS_STRING && Z_TYPE_P(z2) == IS_STRING) { 132 | if (fast_equal_check_string(z1, z2)) { 133 | return 1; 134 | } 135 | } else { 136 | if (fast_equal_check_function(z1, z2)) { 137 | return 1; 138 | } 139 | } 140 | 141 | return 0; 142 | } 143 | 144 | void collection_in_array_kv(zend_array *current_collection, zval *search_key, zval *search_val, zval *ret_val) 145 | { 146 | zval *find_res = NULL; 147 | 148 | ZEND_HASH_FOREACH_VAL(current_collection, zval *val) 149 | if (Z_TYPE_P(val) == IS_ARRAY) { 150 | if (Z_TYPE_P(search_key) == IS_LONG) { 151 | find_res = zend_hash_index_find(Z_ARR_P(val), Z_LVAL_P(search_key)); 152 | } else { 153 | find_res = zend_hash_find(Z_ARR_P(val), Z_STR_P(search_key)); 154 | } 155 | 156 | if (find_res != NULL && zval_equal(find_res, search_val) == 1) { 157 | ZVAL_TRUE(ret_val); 158 | return; 159 | 160 | } 161 | } 162 | ZEND_HASH_FOREACH_END(); 163 | 164 | ZVAL_FALSE(ret_val); 165 | } 166 | 167 | void collection_diff(zend_array *current_collection, zval *search_val, zval *ret_val) 168 | { 169 | zval args[2]; 170 | 171 | ZVAL_ARR (&args[0], current_collection); 172 | ZVAL_COPY(&args[1], search_val); 173 | 174 | GC_ZVAL_ADDREF(&args[0]); 175 | 176 | call_internal_function(INTERNAL_FUN(diff), 2, args, ret_val); 177 | } 178 | 179 | void collection_diff_assoc(zend_array *current_collection, zval *search_val, zval *ret_val) 180 | { 181 | zval args[2]; 182 | 183 | ZVAL_ARR (&args[0], current_collection); 184 | ZVAL_COPY(&args[1], search_val); 185 | 186 | GC_ZVAL_ADDREF(&args[0]); 187 | 188 | call_internal_function(INTERNAL_FUN(diff_assoc), 2, args, ret_val); 189 | } 190 | 191 | void collection_except(zend_array *current_collection, zval *excluded_keys, zval *ret_val) 192 | { 193 | zend_hash_copy(Z_ARR_P(ret_val), current_collection, zval_add_ref); 194 | 195 | ZEND_HASH_FOREACH_VAL(Z_ARR_P(excluded_keys), zval *val) 196 | if (Z_TYPE_P(val) == IS_LONG) { 197 | if (zend_hash_index_exists(current_collection, Z_LVAL_P(val))) { 198 | zend_hash_index_del(Z_ARR_P(ret_val), Z_LVAL_P(val)); 199 | } 200 | } else { 201 | if (zend_hash_exists(current_collection, Z_STR_P(val))) { 202 | zend_hash_del(Z_ARR_P(ret_val), Z_STR_P(val)); 203 | } 204 | } 205 | ZEND_HASH_FOREACH_END(); 206 | } 207 | 208 | void collection_flatten(zend_array *current_collection, zend_long depth, zval *ret_val) 209 | { 210 | ZEND_HASH_FOREACH_VAL(current_collection, zval *val) 211 | if (Z_TYPE_P(val) == IS_ARRAY && depth > 0) { 212 | collection_flatten(Z_ARR_P(val), depth - 1, ret_val); 213 | } else { 214 | add_next_index_zval(ret_val, val); 215 | GC_ZVAL_ADDREF(val); 216 | } 217 | ZEND_HASH_FOREACH_END(); 218 | } 219 | 220 | void collection_flip(zend_array *current_collection, zval *ret_val) 221 | { 222 | zval args[1]; 223 | 224 | ZVAL_ARR(&args[0], current_collection); 225 | 226 | GC_ZVAL_ADDREF(&args[0]); 227 | 228 | call_internal_function(INTERNAL_FUN(flip), 1, args, ret_val); 229 | } 230 | 231 | void collection_for_page(zend_array *current_collection, zend_long page, zend_long number, zval *ret_val) 232 | { 233 | int64_t start_index; 234 | int64_t end_index = page * number; 235 | 236 | for (start_index = end_index - number; start_index < end_index; ++start_index) { 237 | add_next_index_zval(ret_val, &(current_collection->arData[start_index].val)); 238 | 239 | } 240 | } 241 | 242 | void collection_group(zval *foreach_val, zval *tmp, zend_string *group_by_where, zval *group_key, zval *result) 243 | { 244 | if (Z_TYPE_P(foreach_val) == IS_ARRAY) { 245 | zval *group_current_list = NULL, *_group_key = NULL; 246 | 247 | if (group_key != NULL) { 248 | _group_key = group_key; 249 | } 250 | 251 | if (group_by_where != NULL) { 252 | COLLECTION_STR_FIND(Z_ARR_P(foreach_val), group_by_where, _group_key); 253 | } 254 | 255 | COLLECTION_STR_FIND(Z_ARR_P(result), Z_STR_P(_group_key), group_current_list); 256 | 257 | GC_ZVAL_ADDREF(foreach_val); 258 | 259 | if (group_current_list == NULL) { 260 | COLLECTION_INIT(tmp); 261 | add_next_index_zval(tmp, foreach_val); 262 | zend_hash_add(Z_ARRVAL_P(result), Z_STR_P(_group_key), tmp); 263 | ZVAL_NULL(tmp); 264 | } else { 265 | add_next_index_zval(group_current_list, foreach_val); 266 | } 267 | } 268 | } 269 | 270 | void collection_implode(zend_array *current_collection, zend_string *str, zend_string *result) 271 | { 272 | char *c_char_p = NULL; 273 | zend_string *z_str_p = NULL; 274 | 275 | c_char_p = ZSTR_VAL(result); 276 | *c_char_p = 0; 277 | 278 | ZEND_HASH_FOREACH_VAL(current_collection, zval *val) 279 | z_str_p = Z_STR_P(val); 280 | memcpy(c_char_p, ZSTR_VAL(z_str_p), ZSTR_LEN(z_str_p)); 281 | c_char_p += ZSTR_LEN(z_str_p); 282 | memcpy(c_char_p, ZSTR_VAL(str), ZSTR_LEN(str)); 283 | c_char_p += ZSTR_LEN(str); 284 | ZEND_HASH_FOREACH_END(); 285 | } 286 | 287 | int collection_compare(const void *a, const void *b) 288 | { 289 | zval result; 290 | zval *first = NULL, *second = NULL; 291 | 292 | first = &((Bucket *)a)->val; 293 | second = &((Bucket *)b)->val; 294 | 295 | if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) { 296 | first = Z_INDIRECT_P(first); 297 | } 298 | if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) { 299 | second = Z_INDIRECT_P(second); 300 | } 301 | if (compare_function(&result, first, second) == FAILURE) { 302 | return 0; 303 | } 304 | 305 | ZEND_ASSERT(Z_TYPE(result) == IS_LONG); 306 | return ZEND_NORMALIZE_BOOL(Z_LVAL(result)); 307 | } 308 | 309 | int collection_compare_by_key(const void *a, const void *b, const void *key) 310 | { 311 | zval result; 312 | zval *first_arr = NULL, *second_arr = NULL, *first = NULL, *second = NULL; 313 | 314 | first_arr = &((Bucket *)a)->val; 315 | second_arr = &((Bucket *)b)->val; 316 | 317 | if (Z_TYPE_P(first_arr) == IS_ARRAY) { 318 | first = zend_hash_find(Z_ARR_P(first_arr), (zend_string *)key); 319 | } else { 320 | first = first_arr; 321 | } 322 | 323 | if (Z_TYPE_P(second_arr) == IS_ARRAY) { 324 | second = zend_hash_find(Z_ARR_P(second_arr), (zend_string *)key); 325 | } else { 326 | second = second_arr; 327 | } 328 | 329 | if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) { 330 | first = Z_INDIRECT_P(first); 331 | } 332 | if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) { 333 | second = Z_INDIRECT_P(second); 334 | } 335 | if (compare_function(&result, first, second) == FAILURE) { 336 | return 0; 337 | } 338 | 339 | ZEND_ASSERT(Z_TYPE(result) == IS_LONG); 340 | return ZEND_NORMALIZE_BOOL(Z_LVAL(result)); 341 | } 342 | 343 | zval* ZEND_FASTCALL zend_hash_key_minmax(const HashTable *ht, const zend_string *key, compare_key_func_t compar, uint32_t flag) 344 | { 345 | uint32_t idx; 346 | Bucket *p, *res; 347 | 348 | if (ht->nNumOfElements == 0 ) { 349 | return NULL; 350 | } 351 | 352 | idx = 0; 353 | while (1) { 354 | if (idx == ht->nNumUsed) { 355 | return NULL; 356 | } 357 | if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) break; 358 | idx++; 359 | } 360 | res = ht->arData + idx; 361 | for (; idx < ht->nNumUsed; idx++) { 362 | p = ht->arData + idx; 363 | if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue; 364 | 365 | if (flag) { 366 | if (compar(res, p, key) < 0) { /* max */ 367 | res = p; 368 | } 369 | } else { 370 | if (compar(res, p, key) > 0) { /* min */ 371 | res = p; 372 | } 373 | } 374 | } 375 | 376 | if (Z_TYPE_P(&res->val) == IS_ARRAY) { 377 | return zend_hash_str_find_ind(Z_ARR(res->val), ZSTR_VAL(key), ZSTR_LEN(key)); 378 | } else { 379 | return &res->val; 380 | } 381 | } 382 | 383 | int zval_comparison_operations(zend_string *operator, zval *left, zval *right) 384 | { 385 | if (strcmp(operator->val, "==") == 0) { 386 | if (zval_equal(left, right)) { 387 | return 1; 388 | } 389 | 390 | return 0; 391 | } 392 | 393 | if (strcmp(operator->val, "!=") == 0) { 394 | if (zval_equal(left, right)) { 395 | return 0; 396 | } 397 | 398 | return 1; 399 | } 400 | 401 | if (strcmp(operator->val, ">=") == 0) { 402 | if (EXPECTED(Z_TYPE_P(left) == IS_LONG)) { 403 | if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 404 | return (Z_LVAL_P(left) >= Z_LVAL_P(right)); 405 | } else if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 406 | return ((double)Z_LVAL_P(left) >= Z_DVAL_P(right)); 407 | } 408 | } else if (EXPECTED(Z_TYPE_P(left) == IS_DOUBLE)) { 409 | if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 410 | return (Z_DVAL_P(left) >= Z_DVAL_P(right)); 411 | } else if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 412 | return (Z_DVAL_P(left) >= ((double)Z_LVAL_P(right))); 413 | } 414 | } 415 | 416 | return 0; 417 | } 418 | 419 | if (strcmp(operator->val, "<=") == 0) { 420 | if (EXPECTED(Z_TYPE_P(left) == IS_LONG)) { 421 | if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 422 | return (Z_LVAL_P(left) <= Z_LVAL_P(right)); 423 | } else if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 424 | return ((double)Z_LVAL_P(left) <= Z_DVAL_P(right)); 425 | } 426 | } else if (EXPECTED(Z_TYPE_P(left) == IS_DOUBLE)) { 427 | if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 428 | return (Z_DVAL_P(left) <= Z_DVAL_P(right)); 429 | } else if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 430 | return (Z_DVAL_P(left) <= ((double)Z_LVAL_P(right))); 431 | } 432 | } 433 | 434 | return 0; 435 | } 436 | 437 | if (strcmp(operator->val, ">") == 0) { 438 | if (EXPECTED(Z_TYPE_P(left) == IS_LONG)) { 439 | if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 440 | return (Z_LVAL_P(left) > Z_LVAL_P(right)); 441 | } else if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 442 | return ((double)Z_LVAL_P(left) > Z_DVAL_P(right)); 443 | } 444 | } else if (EXPECTED(Z_TYPE_P(left) == IS_DOUBLE)) { 445 | if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 446 | return (Z_DVAL_P(left) > Z_DVAL_P(right)); 447 | } else if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 448 | return (Z_DVAL_P(left) > ((double)Z_LVAL_P(right))); 449 | } 450 | } 451 | 452 | return 0; 453 | } 454 | 455 | if (strcmp(operator->val, "<") == 0) { 456 | if (EXPECTED(Z_TYPE_P(left) == IS_LONG)) { 457 | if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 458 | return (Z_LVAL_P(left) < Z_LVAL_P(right)); 459 | } else if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 460 | return ((double)Z_LVAL_P(left) < Z_DVAL_P(right)); 461 | } 462 | } else if (EXPECTED(Z_TYPE_P(left) == IS_DOUBLE)) { 463 | if (EXPECTED(Z_TYPE_P(right) == IS_DOUBLE)) { 464 | return (Z_DVAL_P(left) < Z_DVAL_P(right)); 465 | } else if (EXPECTED(Z_TYPE_P(right) == IS_LONG)) { 466 | return (Z_DVAL_P(left) < ((double)Z_LVAL_P(right))); 467 | } 468 | } 469 | 470 | return 0; 471 | } 472 | 473 | return 0; 474 | } 475 | 476 | void call_internal_function(const char *function_name, uint32_t param_count, zval *params, zval *ret_val) 477 | { 478 | int index; 479 | zval z_f_name; 480 | 481 | ZVAL_STRINGL(&z_f_name, function_name, strlen(function_name)); 482 | 483 | call_user_function(EG(function_table), NULL, &z_f_name, ret_val, param_count, params); 484 | 485 | if (Z_ISUNDEF_P(ret_val)) { 486 | ZVAL_NULL(ret_val); 487 | } 488 | 489 | for (index = 0; index < (int)param_count; index++) { 490 | VC_ZVAL_DTOR(params[index]); 491 | } 492 | 493 | VC_ZVAL_DTOR(z_f_name); 494 | } -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #ifndef PHP_EXT_COLLECTION_COMMON_H 14 | #define PHP_EXT_COLLECTION_COMMON_H 15 | 16 | #define VAL_IN_COLLECTION(cc, search, ret) \ 17 | collection_in_array_val(cc, search, ret) 18 | 19 | #define KV_IN_COLLECTION(cc, k, v, ret) \ 20 | collection_in_array_kv(cc, k, v, ret) 21 | 22 | #define INTERNAL_ARR "array_" 23 | #define INTERNAL_FUN(m) INTERNAL_ARR#m 24 | 25 | typedef int (*compare_key_func_t)(const void *, const void *, const void *); 26 | 27 | void call_internal_function(const char *function_name, uint32_t param_count, zval params[], zval *ret_val); 28 | 29 | zval* ZEND_FASTCALL zend_hash_key_minmax(const HashTable *ht, const zend_string *key, compare_key_func_t compar, uint32_t flag); 30 | 31 | int zval_equal(zval *z1, zval *z2); 32 | int zval_comparison_operations(zend_string *operator, zval *left, zval *right); 33 | 34 | double average_no_column(zend_array *current); 35 | double average_column(zend_array *current, zend_string *column); 36 | void collection_chunk(zend_array *current, zend_long length, zval *object); 37 | void collection_collapse(zend_array *z_array_p, zval *ret_val); 38 | void collection_combine(zend_array *current_collection, zval *z_arr_val, zval *ret_val); 39 | void collection_concat(zend_array *current_collection, zval *z_arr, zval *ret_val); 40 | void collection_in_array_val(zend_array *current_collection, zval *search_val, zval *ret_val); 41 | void collection_in_array_kv(zend_array *current_collection, zval *search_key, zval *search_val, zval *ret_val); 42 | void collection_diff(zend_array *current_collection, zval *search_val, zval *ret_val); 43 | void collection_diff_assoc(zend_array *current_collection, zval *search_val, zval *ret_val); 44 | void collection_except(zend_array *current_collection, zval *excluded_keys, zval *ret_val); 45 | void collection_flatten(zend_array *current_collection, zend_long depth, zval *ret_val); 46 | void collection_flip(zend_array *current_collection, zval *ret_val); 47 | void collection_for_page(zend_array *current_collection, zend_long page, zend_long number, zval *ret_val); 48 | void collection_group(zval *foreach_val, zval *tmp, zend_string *group_by_where, zval *group_key, zval *result); 49 | void collection_implode(zend_array *current_collection, zend_string *str, zend_string *result); 50 | int collection_compare(const void *a, const void *b); 51 | int collection_compare_by_key(const void *a, const void *b, const void *key); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/exception.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #include "include.h" 14 | 15 | zend_class_entry *vtiful_collection_exception_ce; 16 | 17 | /** {{{ exception_methods 18 | */ 19 | zend_function_entry exception_methods[] = { 20 | PHP_FE_END 21 | }; 22 | /* }}} */ 23 | 24 | /** {{{ COLLECTION_STARTUP_FUNCTION 25 | */ 26 | COLLECTION_STARTUP_FUNCTION(exception) { 27 | zend_class_entry ce; 28 | 29 | INIT_NS_CLASS_ENTRY(ce, "Vtiful\\Kernel\\Collection", "Exception", exception_methods); 30 | 31 | vtiful_collection_exception_ce = zend_register_internal_class_ex(&ce, zend_ce_exception); 32 | 33 | return SUCCESS; 34 | } 35 | /* }}} */ 36 | -------------------------------------------------------------------------------- /src/include.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #ifndef PHP_EXT_COLLECTION_INCLUDE_H 14 | #define PHP_EXT_COLLECTION_INCLUDE_H 15 | 16 | #include 17 | 18 | #include "ext/standard/php_var.h" 19 | 20 | #include "zend_types.h" 21 | #include "zend_exceptions.h" 22 | #include "zend.h" 23 | #include "zend_API.h" 24 | #include "php.h" 25 | 26 | #include "../php_collection.h" 27 | 28 | // Class 29 | extern zend_class_entry *vtiful_collection_ce; 30 | extern zend_class_entry *vtiful_collection_exception_ce; 31 | 32 | // Startup Module 33 | COLLECTION_STARTUP_FUNCTION(exception); 34 | COLLECTION_STARTUP_FUNCTION(kernel); 35 | 36 | // Kernel Class Method 37 | PHP_METHOD(vtiful_collection, __construct); 38 | PHP_METHOD(vtiful_collection, __clone); 39 | PHP_METHOD(vtiful_collection, init); 40 | PHP_METHOD(vtiful_collection, map); 41 | PHP_METHOD(vtiful_collection, all); 42 | PHP_METHOD(vtiful_collection, avg); 43 | PHP_METHOD(vtiful_collection, chunk); 44 | PHP_METHOD(vtiful_collection, collapse); 45 | PHP_METHOD(vtiful_collection, count); 46 | PHP_METHOD(vtiful_collection, toArray); 47 | PHP_METHOD(vtiful_collection, combine); 48 | PHP_METHOD(vtiful_collection, concat); 49 | PHP_METHOD(vtiful_collection, contains); 50 | PHP_METHOD(vtiful_collection, diff); 51 | PHP_METHOD(vtiful_collection, diffAssoc); 52 | PHP_METHOD(vtiful_collection, every); 53 | PHP_METHOD(vtiful_collection, except); 54 | PHP_METHOD(vtiful_collection, filter); 55 | PHP_METHOD(vtiful_collection, first); 56 | PHP_METHOD(vtiful_collection, firstWhere); 57 | PHP_METHOD(vtiful_collection, flatMap); 58 | PHP_METHOD(vtiful_collection, flatten); 59 | PHP_METHOD(vtiful_collection, flip); 60 | PHP_METHOD(vtiful_collection, forget); 61 | PHP_METHOD(vtiful_collection, forPage); 62 | PHP_METHOD(vtiful_collection, get); 63 | PHP_METHOD(vtiful_collection, groupBy); 64 | PHP_METHOD(vtiful_collection, has); 65 | PHP_METHOD(vtiful_collection, implode); 66 | PHP_METHOD(vtiful_collection, intersect); 67 | PHP_METHOD(vtiful_collection, intersectByKeys); 68 | PHP_METHOD(vtiful_collection, isEmpty); 69 | PHP_METHOD(vtiful_collection, isNotEmpty); 70 | PHP_METHOD(vtiful_collection, keyBy); 71 | PHP_METHOD(vtiful_collection, keys); 72 | PHP_METHOD(vtiful_collection, last); 73 | PHP_METHOD(vtiful_collection, mapToGroups); 74 | PHP_METHOD(vtiful_collection, max); 75 | 76 | // PHP Compatible 77 | #ifndef GC_ADDREF 78 | #define GC_ADDREF(p) ++(&(p->gc))->refcount 79 | #endif 80 | 81 | #define GC_ZVAL_ADDREF(zval_p) \ 82 | do { \ 83 | zend_refcounted *gc = Z_COUNTED_P(zval_p); \ 84 | uint32_t t = Z_TYPE_INFO_P(zval_p); \ 85 | if((t & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0) { \ 86 | GC_REFCOUNT(gc)++; \ 87 | } \ 88 | } while (0) 89 | 90 | #define VC_ZVAL_DTOR(zval) zval_ptr_dtor(&zval); 91 | 92 | // Define 93 | #define CURRENT_COLLECTION \ 94 | Z_OBJ_HT_P(getThis())->get_properties(getThis()) 95 | 96 | #define CURRENT_COLLECTION_COUNT \ 97 | zend_hash_num_elements(CURRENT_COLLECTION) 98 | 99 | #define ZVAL_ARRAY_COUNT(zval_p) \ 100 | zend_hash_num_elements(Z_ARR_P(zval_p)) 101 | 102 | #define COLLECTION_INDEX_ZVAL(zval_p, index) \ 103 | &Z_ARR_P(zval_p)->arData[index].val 104 | 105 | #define COLLECTION_INIT(zval_p) \ 106 | do { \ 107 | array_init(zval_p); \ 108 | } while (0) 109 | 110 | #define COLLECTION_TMP(zval_p) \ 111 | zval collection_tmp; \ 112 | zval_p = &collection_tmp; \ 113 | array_init(&collection_tmp); 114 | 115 | 116 | #define COLLECTION_ADD_INDEX_ZVAL(collection_zval_p, zval_p) \ 117 | add_next_index_zval(collection_zval_p, zval_p); 118 | 119 | #define COLLECTION_STRING_DELETE(collection_array_p, zs_key) \ 120 | zend_hash_del(collection_array_p, zs_key); 121 | 122 | #define COLLECTION_INDEX_DELETE(collection_array_p, ulong_key) \ 123 | zend_hash_index_del(collection_array_p, ulong_key); 124 | 125 | #define COLLECTION_INIT_IN_CURRENT(zval_p) \ 126 | COLLECTION_INIT(zval_p); \ 127 | zend_hash_copy(Z_ARR_P(zval_p), CURRENT_COLLECTION, zval_add_ref); 128 | 129 | #define COLLECTION_UPDATE(array_p, bucket, new_zval_p) \ 130 | ZVAL_COPY_VALUE(&(Z_ARR_P(array_p)->arData[bucket->h].val), new_zval_p) 131 | 132 | #define NEW_ZVAL_OBJ(zval_p) \ 133 | do { \ 134 | object_init_ex(zval_p, vtiful_collection_ce); \ 135 | } while (0) 136 | 137 | #define UPDATE_OBJ_COLLECTION(zo_p, z_collection_p) \ 138 | do { \ 139 | if (Z_TYPE_P(z_collection_p) == IS_ARRAY) { \ 140 | zend_object *obj = Z_OBJ_P(zo_p); \ 141 | GC_ZVAL_ADDREF(z_collection_p); \ 142 | obj->properties = Z_ARRVAL_P(z_collection_p); \ 143 | } \ 144 | } while (0) 145 | 146 | #define NEW_COLLECTION_OBJ(ret_val, collection) \ 147 | NEW_ZVAL_OBJ(ret_val); \ 148 | UPDATE_OBJ_COLLECTION(ret_val, collection); 149 | 150 | #define INIT_FCALL(arg_num, ret_val_p) \ 151 | zval args[arg_num]; \ 152 | fci.param_count = arg_num; \ 153 | fci.retval = ret_val_p; \ 154 | fci.params = args; 155 | 156 | #define FCALL_DTOR(arg_num) \ 157 | int i = 0; \ 158 | for (i; i < arg_num; i++) { \ 159 | VC_ZVAL_DTOR(args[i]) \ 160 | } 161 | 162 | #define FCALL_TWO_ARGS(bucket) \ 163 | ZVAL_COPY_VALUE(&args[0], &bucket->val); \ 164 | if (bucket->key) { \ 165 | ZVAL_STR(&args[1], bucket->key); \ 166 | } else { \ 167 | ZVAL_LONG(&args[1], bucket->h); \ 168 | } \ 169 | zend_call_function(&fci, &fci_cache); 170 | 171 | #define FCALL_ONE_ARGS(bucket) \ 172 | ZVAL_COPY_VALUE(&args[0], &bucket->val); \ 173 | zend_call_function(&fci, &fci_cache); 174 | 175 | #define ARRAY_INDEX_FIND(zval_p, index, zval_result_p) \ 176 | do { \ 177 | ZVAL_COPY(zval_result_p, &(Z_ARR_P(zval_p)->arData[index].val));\ 178 | } while (0) 179 | 180 | #define ARRAY_STR_FIND(zval_p, zs_key_p, zval_result_p) \ 181 | do { \ 182 | zval_result_p = zend_hash_find(Z_ARR_P(zval_p), zs_key_p); \ 183 | } while (0) 184 | 185 | #define COLLECTION_INDEX_FIND(collection, index, zval_result_p) \ 186 | do { \ 187 | if (index < collection->nNumOfElements) { \ 188 | zval_result_p = &(collection->arData[index].val); \ 189 | } \ 190 | } while (0) 191 | 192 | #define COLLECTION_STR_FIND(collection, zs_key_p, zval_result_p) \ 193 | do { \ 194 | zval_result_p = zend_hash_find(collection, zs_key_p); \ 195 | } while (0) 196 | 197 | #define ZVAL_ARRAY_INSERT_BUCKET_KEY_ZVAL_VAL(zval_p, bucket, zval_val_p) \ 198 | do { \ 199 | zval value; \ 200 | if (Z_TYPE(bucket->val) == IS_STRING) { \ 201 | ARRAY_INDEX_FIND(zval_val_p, bucket->h, &value); \ 202 | zend_hash_str_update(Z_ARR_P(zval_p), Z_STRVAL(bucket->val), Z_STRLEN(bucket->val), &value); \ 203 | } \ 204 | if (Z_TYPE(bucket->val) == IS_LONG) { \ 205 | ARRAY_INDEX_FIND(zval_val_p, bucket->h, &value); \ 206 | zend_hash_index_update(Z_ARR_P(zval_p), Z_LVAL(bucket->val), &value); \ 207 | } \ 208 | } while(0) 209 | 210 | #define ZVAL_IS_NOT_ARRAY_SO_CONTINUE(zval_p) \ 211 | if (Z_TYPE_P(value) != IS_ARRAY) continue; 212 | 213 | #define RETURN_THIS \ 214 | ZVAL_COPY(return_value, getThis()); 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /src/kernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #include "include.h" 14 | 15 | zend_class_entry *vtiful_collection_ce; 16 | 17 | /* {{{ ARG_INFO 18 | */ 19 | ZEND_BEGIN_ARG_INFO_EX(collection_init_arginfo, 0, 0, 1) 20 | ZEND_ARG_INFO(0, collection) 21 | ZEND_END_ARG_INFO() 22 | 23 | ZEND_BEGIN_ARG_INFO_EX(collection_map_arginfo, 0, 0, 1) 24 | ZEND_ARG_INFO(0, callback) 25 | ZEND_END_ARG_INFO() 26 | 27 | ZEND_BEGIN_ARG_INFO_EX(collection_avg_arginfo, 0, 0, 0) 28 | ZEND_ARG_INFO(0, column) 29 | ZEND_END_ARG_INFO() 30 | 31 | ZEND_BEGIN_ARG_INFO_EX(collection_chunk_arginfo, 0, 0, 1) 32 | ZEND_ARG_INFO(0, length) 33 | ZEND_END_ARG_INFO() 34 | 35 | ZEND_BEGIN_ARG_INFO_EX(collection_combine_arginfo, 0, 0, 1) 36 | ZEND_ARG_INFO(0, array) 37 | ZEND_END_ARG_INFO() 38 | 39 | ZEND_BEGIN_ARG_INFO_EX(collection_concat_arginfo, 0, 0, 1) 40 | ZEND_ARG_INFO(0, array) 41 | ZEND_END_ARG_INFO() 42 | 43 | ZEND_BEGIN_ARG_INFO_EX(collection_contains_arginfo, 0, 0, 1) 44 | ZEND_ARG_INFO(0, key) 45 | ZEND_ARG_INFO(0, val) 46 | ZEND_END_ARG_INFO() 47 | 48 | ZEND_BEGIN_ARG_INFO_EX(collection_diff_arginfo, 0, 0, 1) 49 | ZEND_ARG_INFO(0, array) 50 | ZEND_END_ARG_INFO() 51 | 52 | ZEND_BEGIN_ARG_INFO_EX(collection_every_arginfo, 0, 0, 1) 53 | ZEND_ARG_INFO(0, callback) 54 | ZEND_END_ARG_INFO() 55 | 56 | ZEND_BEGIN_ARG_INFO_EX(collection_except_arginfo, 0, 0, 1) 57 | ZEND_ARG_INFO(0, excluded_keys) 58 | ZEND_END_ARG_INFO() 59 | 60 | ZEND_BEGIN_ARG_INFO_EX(collection_filter_arginfo, 0, 0, 0) 61 | ZEND_ARG_INFO(0, callback) 62 | ZEND_END_ARG_INFO() 63 | 64 | ZEND_BEGIN_ARG_INFO_EX(collection_first_arginfo, 0, 0, 0) 65 | ZEND_ARG_INFO(0, callback) 66 | ZEND_END_ARG_INFO() 67 | 68 | ZEND_BEGIN_ARG_INFO_EX(collection_first_where_arginfo, 0, 0, 2) 69 | ZEND_ARG_INFO(0, column) 70 | ZEND_ARG_INFO(0, val) 71 | ZEND_ARG_INFO(0, symbol) 72 | ZEND_END_ARG_INFO() 73 | 74 | ZEND_BEGIN_ARG_INFO_EX(collection_flat_map_arginfo, 0, 0, 1) 75 | ZEND_ARG_INFO(0, callback) 76 | ZEND_END_ARG_INFO() 77 | 78 | ZEND_BEGIN_ARG_INFO_EX(collection_flatten_arginfo, 0, 0, 0) 79 | ZEND_ARG_INFO(0, callback) 80 | ZEND_END_ARG_INFO() 81 | 82 | ZEND_BEGIN_ARG_INFO_EX(collection_forget_arginfo, 0, 0, 1) 83 | ZEND_ARG_INFO(0, key) 84 | ZEND_END_ARG_INFO() 85 | 86 | ZEND_BEGIN_ARG_INFO_EX(collection_for_page_arginfo, 0, 0, 2) 87 | ZEND_ARG_INFO(0, page) 88 | ZEND_ARG_INFO(0, number) 89 | ZEND_END_ARG_INFO() 90 | 91 | ZEND_BEGIN_ARG_INFO_EX(collection_get_arginfo, 0, 0, 1) 92 | ZEND_ARG_INFO(0, key) 93 | ZEND_ARG_INFO(0, default_val) 94 | ZEND_END_ARG_INFO() 95 | 96 | ZEND_BEGIN_ARG_INFO_EX(collection_group_by_arginfo, 0, 0, 1) 97 | ZEND_ARG_INFO(0, key) 98 | ZEND_END_ARG_INFO() 99 | 100 | ZEND_BEGIN_ARG_INFO_EX(collection_has_arginfo, 0, 0, 1) 101 | ZEND_ARG_INFO(0, key) 102 | ZEND_END_ARG_INFO() 103 | 104 | ZEND_BEGIN_ARG_INFO_EX(collection_implode_arginfo, 0, 0, 1) 105 | ZEND_ARG_INFO(0, key) 106 | ZEND_ARG_INFO(0, str) 107 | ZEND_END_ARG_INFO() 108 | 109 | ZEND_BEGIN_ARG_INFO_EX(collection_intersect_arginfo, 0, 0, 1) 110 | ZEND_ARG_INFO(0, array) 111 | ZEND_END_ARG_INFO() 112 | 113 | ZEND_BEGIN_ARG_INFO_EX(collection_intersect_keys_arginfo, 0, 0, 1) 114 | ZEND_ARG_INFO(0, array) 115 | ZEND_END_ARG_INFO() 116 | 117 | ZEND_BEGIN_ARG_INFO_EX(collection_key_by_arginfo, 0, 0, 1) 118 | ZEND_ARG_INFO(0, key) 119 | ZEND_END_ARG_INFO() 120 | 121 | ZEND_BEGIN_ARG_INFO_EX(collection_last_arginfo, 0, 0, 0) 122 | ZEND_ARG_INFO(0, callback) 123 | ZEND_END_ARG_INFO() 124 | 125 | ZEND_BEGIN_ARG_INFO_EX(collection_map_group_arginfo, 0, 0, 1) 126 | ZEND_ARG_INFO(0, callback) 127 | ZEND_END_ARG_INFO() 128 | 129 | ZEND_BEGIN_ARG_INFO_EX(collection_max_arginfo, 0, 0, 0) 130 | ZEND_ARG_INFO(0, key) 131 | ZEND_END_ARG_INFO() 132 | /* }}} */ 133 | 134 | /** {{{ collection_methods 135 | */ 136 | zend_function_entry collection_methods[] = { 137 | PHP_ME(vtiful_collection, __construct, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR) 138 | PHP_ME(vtiful_collection, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) 139 | PHP_ME(vtiful_collection, init, collection_init_arginfo, ZEND_ACC_PUBLIC |ZEND_ACC_STATIC) 140 | PHP_ME(vtiful_collection, map, collection_map_arginfo, ZEND_ACC_PUBLIC) 141 | PHP_ME(vtiful_collection, all, NULL, ZEND_ACC_PUBLIC) 142 | PHP_ME(vtiful_collection, avg, collection_avg_arginfo, ZEND_ACC_PUBLIC) 143 | PHP_ME(vtiful_collection, chunk, collection_chunk_arginfo, ZEND_ACC_PUBLIC) 144 | PHP_ME(vtiful_collection, collapse, NULL, ZEND_ACC_PUBLIC) 145 | PHP_ME(vtiful_collection, count, NULL, ZEND_ACC_PUBLIC) 146 | PHP_ME(vtiful_collection, toArray, NULL, ZEND_ACC_PUBLIC) 147 | PHP_ME(vtiful_collection, combine, collection_combine_arginfo, ZEND_ACC_PUBLIC) 148 | PHP_ME(vtiful_collection, concat, collection_concat_arginfo, ZEND_ACC_PUBLIC) 149 | PHP_ME(vtiful_collection, contains, collection_contains_arginfo, ZEND_ACC_PUBLIC) 150 | PHP_ME(vtiful_collection, diff, collection_diff_arginfo, ZEND_ACC_PUBLIC) 151 | PHP_ME(vtiful_collection, diffAssoc, collection_diff_arginfo, ZEND_ACC_PUBLIC) 152 | PHP_ME(vtiful_collection, every, collection_every_arginfo, ZEND_ACC_PUBLIC) 153 | PHP_ME(vtiful_collection, except, collection_except_arginfo, ZEND_ACC_PUBLIC) 154 | PHP_ME(vtiful_collection, filter, collection_filter_arginfo, ZEND_ACC_PUBLIC) 155 | PHP_ME(vtiful_collection, first, collection_first_arginfo, ZEND_ACC_PUBLIC) 156 | PHP_ME(vtiful_collection, firstWhere, collection_first_where_arginfo, ZEND_ACC_PUBLIC) 157 | PHP_ME(vtiful_collection, flatMap, collection_flat_map_arginfo, ZEND_ACC_PUBLIC) 158 | PHP_ME(vtiful_collection, flatten, collection_flatten_arginfo, ZEND_ACC_PUBLIC) 159 | PHP_ME(vtiful_collection, flip, NULL, ZEND_ACC_PUBLIC) 160 | PHP_ME(vtiful_collection, forget, collection_forget_arginfo, ZEND_ACC_PUBLIC) 161 | PHP_ME(vtiful_collection, forPage, collection_for_page_arginfo, ZEND_ACC_PUBLIC) 162 | PHP_ME(vtiful_collection, get, collection_get_arginfo, ZEND_ACC_PUBLIC) 163 | PHP_ME(vtiful_collection, groupBy, collection_group_by_arginfo, ZEND_ACC_PUBLIC) 164 | PHP_ME(vtiful_collection, has, collection_has_arginfo, ZEND_ACC_PUBLIC) 165 | PHP_ME(vtiful_collection, implode, collection_implode_arginfo, ZEND_ACC_PUBLIC) 166 | PHP_ME(vtiful_collection, intersect, collection_intersect_arginfo, ZEND_ACC_PUBLIC) 167 | PHP_ME(vtiful_collection, intersectByKeys, collection_intersect_keys_arginfo, ZEND_ACC_PUBLIC) 168 | PHP_ME(vtiful_collection, isEmpty, NULL, ZEND_ACC_PUBLIC) 169 | PHP_ME(vtiful_collection, isNotEmpty, NULL, ZEND_ACC_PUBLIC) 170 | PHP_ME(vtiful_collection, keyBy, collection_key_by_arginfo, ZEND_ACC_PUBLIC) 171 | PHP_ME(vtiful_collection, keys, NULL, ZEND_ACC_PUBLIC) 172 | PHP_ME(vtiful_collection, last, collection_last_arginfo, ZEND_ACC_PUBLIC) 173 | PHP_ME(vtiful_collection, mapToGroups, collection_map_group_arginfo, ZEND_ACC_PUBLIC) 174 | PHP_ME(vtiful_collection, max, collection_max_arginfo, ZEND_ACC_PUBLIC) 175 | PHP_FE_END 176 | }; 177 | /* }}} */ 178 | 179 | /** {{{ COLLECTION_STARTUP_FUNCTION 180 | */ 181 | COLLECTION_STARTUP_FUNCTION(kernel) 182 | { 183 | zend_class_entry ce; 184 | 185 | INIT_NS_CLASS_ENTRY(ce, "Vtiful\\Kernel", "Collection", collection_methods); 186 | 187 | vtiful_collection_ce = zend_register_internal_class(&ce); 188 | 189 | return SUCCESS; 190 | } 191 | /* }}} */ 192 | -------------------------------------------------------------------------------- /src/method.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Collection Extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016-2018 The Viest | 6 | +----------------------------------------------------------------------+ 7 | | http://www.viest.me | 8 | +----------------------------------------------------------------------+ 9 | | Author: viest | 10 | +----------------------------------------------------------------------+ 11 | */ 12 | 13 | #include "include.h" 14 | #include "common.h" 15 | 16 | /** {{{ \Vtiful\Kernel\Collection::__construct() 17 | */ 18 | PHP_METHOD(vtiful_collection, __construct) 19 | { 20 | 21 | } 22 | /* }}} */ 23 | 24 | /** {{{ \Vtiful\Kernel\Collection::__clone() 25 | */ 26 | PHP_METHOD(vtiful_collection, __clone) 27 | { 28 | 29 | } 30 | /* }}} */ 31 | 32 | /** {{{ \Vtiful\Kernel\Collection::init([array $collection]) 33 | */ 34 | PHP_METHOD(vtiful_collection, init) 35 | { 36 | zval *collection = NULL; 37 | 38 | ZEND_PARSE_PARAMETERS_START(0, 1) 39 | Z_PARAM_OPTIONAL 40 | Z_PARAM_ARRAY(collection) 41 | ZEND_PARSE_PARAMETERS_END(); 42 | 43 | NEW_COLLECTION_OBJ(return_value, collection); 44 | } 45 | /* }}} */ 46 | 47 | /** {{{ \Vtiful\Kernel\Collection::map(closures $callback) 48 | */ 49 | PHP_METHOD(vtiful_collection, map) 50 | { 51 | zval fcall_result, result; 52 | zend_fcall_info fci = empty_fcall_info; 53 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 54 | 55 | ZEND_PARSE_PARAMETERS_START(1, 1) 56 | Z_PARAM_FUNC(fci, fci_cache) 57 | ZEND_PARSE_PARAMETERS_END(); 58 | 59 | INIT_FCALL(2, &fcall_result) 60 | 61 | COLLECTION_INIT(&result); 62 | 63 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket* bucket) 64 | FCALL_TWO_ARGS(bucket) 65 | COLLECTION_ADD_INDEX_ZVAL(&result, &fcall_result) 66 | ZEND_HASH_FOREACH_END(); 67 | 68 | NEW_COLLECTION_OBJ(return_value, &result); 69 | 70 | VC_ZVAL_DTOR(result); 71 | } 72 | /* }}} */ 73 | 74 | /** {{{ \Vtiful\Kernel\Collection::all() 75 | */ 76 | PHP_METHOD(vtiful_collection, all) 77 | { 78 | GC_ADDREF(CURRENT_COLLECTION); 79 | 80 | ZVAL_ARR(return_value, CURRENT_COLLECTION); 81 | } 82 | /* }}} */ 83 | 84 | /** {{{ \Vtiful\Kernel\Collection::avg([string $key]) 85 | */ 86 | PHP_METHOD(vtiful_collection, avg) 87 | { 88 | zend_string *column = NULL; 89 | 90 | ZEND_PARSE_PARAMETERS_START(0, 1) 91 | Z_PARAM_OPTIONAL 92 | Z_PARAM_STR(column) 93 | ZEND_PARSE_PARAMETERS_END(); 94 | 95 | double sum = 0; 96 | 97 | if (column == NULL) { 98 | sum = average_no_column(CURRENT_COLLECTION); 99 | } else { 100 | sum = average_column(CURRENT_COLLECTION, column); 101 | } 102 | 103 | ZVAL_DOUBLE(return_value, (sum/zend_hash_num_elements(CURRENT_COLLECTION))) 104 | } 105 | /* }}} */ 106 | 107 | /** {{{ \Vtiful\Kernel\Collection::chunk(int $length) 108 | */ 109 | PHP_METHOD(vtiful_collection, chunk) 110 | { 111 | zend_long length; 112 | 113 | ZEND_PARSE_PARAMETERS_START(1, 1) 114 | Z_PARAM_LONG(length) 115 | ZEND_PARSE_PARAMETERS_END(); 116 | 117 | if (length < 1) { 118 | zend_throw_exception(vtiful_collection_exception_ce, "Parameter cannot be less than 1", 10); 119 | } 120 | 121 | NEW_ZVAL_OBJ(return_value); 122 | 123 | collection_chunk(CURRENT_COLLECTION, length, return_value); 124 | } 125 | /* }}} */ 126 | 127 | /** {{{ \Vtiful\Kernel\Collection::collapse() 128 | */ 129 | PHP_METHOD(vtiful_collection, collapse) 130 | { 131 | zval result; 132 | 133 | COLLECTION_INIT(&result); 134 | 135 | collection_collapse(CURRENT_COLLECTION, &result); 136 | 137 | NEW_COLLECTION_OBJ(return_value, &result); 138 | 139 | VC_ZVAL_DTOR(result); 140 | } 141 | /* }}} */ 142 | 143 | /** {{{ \Vtiful\Kernel\Collection::count() 144 | */ 145 | PHP_METHOD(vtiful_collection, count) 146 | { 147 | ZVAL_LONG(return_value, CURRENT_COLLECTION_COUNT); 148 | } 149 | /* }}} */ 150 | 151 | /** {{{ \Vtiful\Kernel\Collection::toArray() 152 | */ 153 | PHP_METHOD(vtiful_collection, toArray) 154 | { 155 | ZVAL_ARR(return_value, CURRENT_COLLECTION); 156 | 157 | GC_ZVAL_ADDREF(return_value); 158 | } 159 | /* }}} */ 160 | 161 | /** {{{ \Vtiful\Kernel\Collection::combine(array $arrVal) 162 | */ 163 | PHP_METHOD(vtiful_collection, combine) 164 | { 165 | zval result, *val = NULL; 166 | 167 | ZEND_PARSE_PARAMETERS_START(1, 1) 168 | Z_PARAM_ARRAY(val) 169 | ZEND_PARSE_PARAMETERS_END(); 170 | 171 | COLLECTION_INIT(&result); 172 | 173 | collection_combine(CURRENT_COLLECTION, val, &result); 174 | 175 | NEW_COLLECTION_OBJ(return_value, &result); 176 | 177 | VC_ZVAL_DTOR(result); 178 | } 179 | /* }}} */ 180 | 181 | /** {{{ \Vtiful\Kernel\Collection::concat(array $arrVal) 182 | */ 183 | PHP_METHOD(vtiful_collection, concat) 184 | { 185 | zval result, *val = NULL; 186 | 187 | ZEND_PARSE_PARAMETERS_START(1, 1) 188 | Z_PARAM_ARRAY(val) 189 | ZEND_PARSE_PARAMETERS_END(); 190 | 191 | COLLECTION_INIT(&result); 192 | 193 | collection_concat(CURRENT_COLLECTION, val, &result); 194 | 195 | NEW_COLLECTION_OBJ(return_value, &result); 196 | 197 | VC_ZVAL_DTOR(result); 198 | } 199 | /* }}} */ 200 | 201 | /** {{{ \Vtiful\Kernel\Collection::contains(string $value[, string $value]) 202 | */ 203 | PHP_METHOD(vtiful_collection, contains) 204 | { 205 | zval *key = NULL, *val = NULL; 206 | 207 | ZEND_PARSE_PARAMETERS_START(1, 2) 208 | Z_PARAM_ZVAL(key) 209 | Z_PARAM_OPTIONAL 210 | Z_PARAM_ZVAL(val) 211 | ZEND_PARSE_PARAMETERS_END(); 212 | 213 | if (val == NULL) { 214 | VAL_IN_COLLECTION(CURRENT_COLLECTION, key, return_value); 215 | } else { 216 | KV_IN_COLLECTION(CURRENT_COLLECTION, key, val, return_value); 217 | } 218 | } 219 | /* }}} */ 220 | 221 | /** {{{ \Vtiful\Kernel\Collection::diff(array $array) 222 | */ 223 | PHP_METHOD(vtiful_collection, diff) 224 | { 225 | zval result, *val = NULL; 226 | 227 | ZEND_PARSE_PARAMETERS_START(1, 1) 228 | Z_PARAM_ARRAY(val) 229 | ZEND_PARSE_PARAMETERS_END(); 230 | 231 | collection_diff(CURRENT_COLLECTION, val, &result); 232 | 233 | NEW_COLLECTION_OBJ(return_value, &result); 234 | 235 | VC_ZVAL_DTOR(result); 236 | } 237 | /* }}} */ 238 | 239 | /** {{{ \Vtiful\Kernel\Collection::diffAssoc(array $array) 240 | */ 241 | PHP_METHOD(vtiful_collection, diffAssoc) 242 | { 243 | zval result, *val = NULL; 244 | 245 | ZEND_PARSE_PARAMETERS_START(1, 1) 246 | Z_PARAM_ARRAY(val) 247 | ZEND_PARSE_PARAMETERS_END(); 248 | 249 | collection_diff_assoc(CURRENT_COLLECTION, val, &result); 250 | 251 | NEW_COLLECTION_OBJ(return_value, &result); 252 | 253 | VC_ZVAL_DTOR(result); 254 | } 255 | /* }}} */ 256 | 257 | /** {{{ \Vtiful\Kernel\Collection::every(closures $callback) 258 | */ 259 | PHP_METHOD(vtiful_collection, every) 260 | { 261 | zval fcall_result; 262 | zend_fcall_info fci = empty_fcall_info; 263 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 264 | 265 | ZEND_PARSE_PARAMETERS_START(1, 1) 266 | Z_PARAM_FUNC(fci, fci_cache) 267 | ZEND_PARSE_PARAMETERS_END(); 268 | 269 | INIT_FCALL(2, &fcall_result) 270 | 271 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket* bucket) 272 | FCALL_TWO_ARGS(bucket) 273 | 274 | if (Z_TYPE_INFO(fcall_result) == IS_FALSE) { 275 | ZVAL_FALSE(return_value); 276 | break; 277 | } 278 | ZEND_HASH_FOREACH_END(); 279 | 280 | ZVAL_TRUE(return_value); 281 | } 282 | /* }}} */ 283 | 284 | /** {{{ \Vtiful\Kernel\Collection::except(array $excludedKeys) 285 | */ 286 | PHP_METHOD(vtiful_collection, except) 287 | { 288 | zval result, *excluded_keys = NULL; 289 | 290 | ZEND_PARSE_PARAMETERS_START(1,1) 291 | Z_PARAM_ARRAY(excluded_keys) 292 | ZEND_PARSE_PARAMETERS_END(); 293 | 294 | COLLECTION_INIT(&result); 295 | 296 | collection_except(CURRENT_COLLECTION, excluded_keys, &result); 297 | 298 | NEW_COLLECTION_OBJ(return_value, &result); 299 | 300 | VC_ZVAL_DTOR(result); 301 | } 302 | /* }}} */ 303 | 304 | /** {{{ \Vtiful\Kernel\Collection::filter(closures $callback) 305 | */ 306 | PHP_METHOD(vtiful_collection, filter) 307 | { 308 | zval fcall_result, result; 309 | zend_fcall_info fci = empty_fcall_info; 310 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 311 | 312 | ZEND_PARSE_PARAMETERS_START(0, 1) 313 | Z_PARAM_OPTIONAL 314 | Z_PARAM_FUNC(fci, fci_cache) 315 | ZEND_PARSE_PARAMETERS_END(); 316 | 317 | COLLECTION_INIT(&result); 318 | 319 | if (ZEND_NUM_ARGS() < 1) { 320 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket* bucket) 321 | ZVAL_COPY(&fcall_result, &bucket->val); 322 | convert_to_boolean(&fcall_result); 323 | if (Z_TYPE_INFO(fcall_result) == IS_FALSE) { 324 | continue; 325 | } 326 | add_next_index_zval(&result, &bucket->val); 327 | ZEND_HASH_FOREACH_END(); 328 | } else { 329 | INIT_FCALL(2, &fcall_result) 330 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket* bucket) 331 | FCALL_TWO_ARGS(bucket) 332 | if (Z_TYPE_INFO(fcall_result) == IS_FALSE) { 333 | continue; 334 | } 335 | add_next_index_zval(&result, &bucket->val); 336 | ZEND_HASH_FOREACH_END(); 337 | } 338 | 339 | NEW_COLLECTION_OBJ(return_value, &result); 340 | 341 | VC_ZVAL_DTOR(result); 342 | } 343 | /* }}} */ 344 | 345 | /** {{{ \Vtiful\Kernel\Collection::first([closures $callback]) 346 | */ 347 | PHP_METHOD(vtiful_collection, first) 348 | { 349 | zend_fcall_info fci = empty_fcall_info; 350 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 351 | 352 | ZEND_PARSE_PARAMETERS_START(0, 1) 353 | Z_PARAM_OPTIONAL 354 | Z_PARAM_FUNC(fci, fci_cache) 355 | ZEND_PARSE_PARAMETERS_END(); 356 | 357 | if (ZEND_NUM_ARGS() < 1) { 358 | ZVAL_COPY(return_value, &(CURRENT_COLLECTION->arData[0].val)); 359 | } else { 360 | zval fcall_result; 361 | 362 | INIT_FCALL(2, &fcall_result) 363 | 364 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket* bucket) 365 | FCALL_TWO_ARGS(bucket) 366 | 367 | if (Z_TYPE_INFO(fcall_result) == IS_TRUE) { 368 | ZVAL_COPY(return_value, &(bucket->val)); 369 | break; 370 | } 371 | ZEND_HASH_FOREACH_END(); 372 | } 373 | } 374 | /* }}} */ 375 | 376 | 377 | /** {{{ \Vtiful\Kernel\Collection::firstWhere(mixed $column, mixed $val) 378 | */ 379 | PHP_METHOD(vtiful_collection, firstWhere) 380 | { 381 | zval result, *find_res = NULL, *symbol = NULL; 382 | zend_string *column = NULL, *val = NULL; 383 | 384 | ZEND_PARSE_PARAMETERS_START(2, 3) 385 | Z_PARAM_STR(column) 386 | Z_PARAM_STR(val) 387 | Z_PARAM_OPTIONAL 388 | Z_PARAM_ZVAL(symbol) 389 | ZEND_PARSE_PARAMETERS_END(); 390 | 391 | if (ZEND_NUM_ARGS() == 2) { 392 | zval zval_zstr; 393 | 394 | ZEND_HASH_FOREACH_VAL(CURRENT_COLLECTION, zval *value) 395 | ZVAL_IS_NOT_ARRAY_SO_CONTINUE(value) 396 | 397 | ARRAY_STR_FIND(value, column, find_res); 398 | 399 | if (find_res != NULL) { 400 | ZVAL_STR(&zval_zstr, val); 401 | if (zval_equal(find_res, &zval_zstr)) { 402 | ZVAL_COPY(&result, value); 403 | break; 404 | } 405 | } 406 | ZEND_HASH_FOREACH_END(); 407 | 408 | VC_ZVAL_DTOR(zval_zstr); 409 | } else if (ZEND_NUM_ARGS() == 3) { 410 | ZEND_HASH_FOREACH_VAL(CURRENT_COLLECTION, zval *value) 411 | ZVAL_IS_NOT_ARRAY_SO_CONTINUE(value) 412 | 413 | ARRAY_STR_FIND(value, column, find_res); 414 | 415 | if (find_res != NULL) { 416 | if (zval_comparison_operations(val, find_res, symbol)) { 417 | ZVAL_COPY(&result, value); 418 | break; 419 | } 420 | } 421 | ZEND_HASH_FOREACH_END(); 422 | } 423 | 424 | NEW_COLLECTION_OBJ(return_value, &result); 425 | 426 | VC_ZVAL_DTOR(result); 427 | } 428 | /* }}} */ 429 | 430 | /** {{{ \Vtiful\Kernel\Collection::flatMap(closures $callback) 431 | */ 432 | PHP_METHOD(vtiful_collection, flatMap) 433 | { 434 | zval fcall_result, result; 435 | zend_fcall_info fci = empty_fcall_info; 436 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 437 | 438 | ZEND_PARSE_PARAMETERS_START(1, 1) 439 | Z_PARAM_FUNC(fci, fci_cache) 440 | ZEND_PARSE_PARAMETERS_END(); 441 | 442 | INIT_FCALL(1, &fcall_result); 443 | 444 | COLLECTION_INIT_IN_CURRENT(&result); 445 | 446 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket *bucket) 447 | FCALL_ONE_ARGS(bucket); 448 | COLLECTION_UPDATE(&result, bucket, &fcall_result); 449 | FCALL_DTOR(1); 450 | ZEND_HASH_FOREACH_END(); 451 | 452 | NEW_COLLECTION_OBJ(return_value, &result); 453 | 454 | VC_ZVAL_DTOR(result); 455 | } 456 | /* }}} */ 457 | 458 | /** {{{ \Vtiful\Kernel\Collection::flatten([int $depth]) 459 | */ 460 | PHP_METHOD(vtiful_collection, flatten) 461 | { 462 | zval result; 463 | zend_long depth = 1; 464 | 465 | ZEND_PARSE_PARAMETERS_START(0, 1) 466 | Z_PARAM_OPTIONAL 467 | Z_PARAM_LONG(depth) 468 | ZEND_PARSE_PARAMETERS_END(); 469 | 470 | COLLECTION_INIT(&result); 471 | 472 | collection_flatten(CURRENT_COLLECTION, depth, &result); 473 | 474 | NEW_COLLECTION_OBJ(return_value, &result); 475 | 476 | VC_ZVAL_DTOR(result); 477 | } 478 | /* }}} */ 479 | 480 | /** {{{ \Vtiful\Kernel\Collection::flip() 481 | */ 482 | PHP_METHOD(vtiful_collection, flip) 483 | { 484 | zval result; 485 | 486 | collection_flip(CURRENT_COLLECTION, &result); 487 | 488 | NEW_COLLECTION_OBJ(return_value, &result); 489 | 490 | VC_ZVAL_DTOR(result); 491 | } 492 | /* }}} */ 493 | 494 | /** {{{ \Vtiful\Kernel\Collection::forget(string $key) 495 | */ 496 | PHP_METHOD(vtiful_collection, forget) 497 | { 498 | zend_string *key = NULL; 499 | 500 | ZEND_PARSE_PARAMETERS_START(1, 1) 501 | Z_PARAM_STR(key) 502 | ZEND_PARSE_PARAMETERS_END(); 503 | 504 | COLLECTION_STRING_DELETE(CURRENT_COLLECTION, key); 505 | 506 | RETURN_THIS 507 | } 508 | /* }}} */ 509 | 510 | /** {{{ \Vtiful\Kernel\Collection::forPage(int $page, int $number) 511 | */ 512 | PHP_METHOD(vtiful_collection, forPage) 513 | { 514 | zval result; 515 | zend_long page, number; 516 | 517 | ZEND_PARSE_PARAMETERS_START(2, 2) 518 | Z_PARAM_LONG(page) 519 | Z_PARAM_LONG(number) 520 | ZEND_PARSE_PARAMETERS_END(); 521 | 522 | COLLECTION_INIT(&result); 523 | 524 | collection_for_page(CURRENT_COLLECTION, page, number, &result); 525 | 526 | NEW_COLLECTION_OBJ(return_value, &result); 527 | 528 | VC_ZVAL_DTOR(result); 529 | } 530 | /* }}} */ 531 | 532 | /** {{{ \Vtiful\Kernel\Collection::get(mixed $key [, mixed $default]) 533 | */ 534 | PHP_METHOD(vtiful_collection, get) 535 | { 536 | zval *key, *default_val = NULL, *find_result = NULL; 537 | 538 | ZEND_PARSE_PARAMETERS_START(1, 2) 539 | Z_PARAM_ZVAL(key) 540 | Z_PARAM_OPTIONAL 541 | Z_PARAM_ZVAL(default_val) 542 | ZEND_PARSE_PARAMETERS_END(); 543 | 544 | if (Z_TYPE_P(key) == IS_LONG) { 545 | COLLECTION_INDEX_FIND(CURRENT_COLLECTION, Z_LVAL_P(key), find_result); 546 | } 547 | 548 | if (Z_TYPE_P(key) == IS_STRING) { 549 | COLLECTION_STR_FIND(CURRENT_COLLECTION, Z_STR_P(key), find_result); 550 | } 551 | 552 | if (find_result == NULL || Z_TYPE_P(find_result) == IS_NULL) { 553 | if (ZEND_NUM_ARGS() < 2) { 554 | ZVAL_NULL(return_value); 555 | } else { 556 | ZVAL_COPY(return_value, default_val); 557 | } 558 | } else { 559 | ZVAL_COPY(return_value, find_result); 560 | } 561 | } 562 | /* }}} */ 563 | 564 | /** {{{ \Vtiful\Kernel\Collection::groupBy(mixed $key) 565 | */ 566 | PHP_METHOD(vtiful_collection, groupBy) 567 | { 568 | zval result; 569 | 570 | zend_string *key = NULL; 571 | 572 | zend_fcall_info fci = empty_fcall_info; 573 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 574 | 575 | ZEND_PARSE_PARAMETERS_START(1, 1) 576 | _real_arg++; 577 | if (Z_TYPE_P(_real_arg) == IS_STRING) { 578 | _real_arg--; 579 | Z_PARAM_STR(key); 580 | } 581 | if (Z_TYPE_P(_real_arg) == IS_OBJECT) { 582 | _real_arg--; 583 | Z_PARAM_FUNC(fci, fci_cache); 584 | } 585 | ZEND_PARSE_PARAMETERS_END(); 586 | 587 | COLLECTION_INIT(&result); 588 | 589 | if (key == NULL) { 590 | zval fcall_res; 591 | 592 | INIT_FCALL(2, &fcall_res); 593 | 594 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket *bucket) 595 | FCALL_TWO_ARGS(bucket); 596 | collection_group(&(bucket->val), return_value, NULL, &fcall_res, &result); 597 | VC_ZVAL_DTOR(fcall_res); 598 | ZEND_HASH_FOREACH_END(); 599 | } else { 600 | ZEND_HASH_FOREACH_VAL(CURRENT_COLLECTION, zval *value) 601 | collection_group(value, return_value, key, NULL, &result); 602 | ZEND_HASH_FOREACH_END(); 603 | } 604 | 605 | NEW_COLLECTION_OBJ(return_value, &result); 606 | 607 | VC_ZVAL_DTOR(result); 608 | } 609 | /* }}} */ 610 | 611 | /** {{{ \Vtiful\Kernel\Collection::hash(mixed $key) 612 | */ 613 | PHP_METHOD(vtiful_collection, has) 614 | { 615 | zval *key = NULL, *find_res = NULL; 616 | 617 | ZEND_PARSE_PARAMETERS_START(1, 1) 618 | Z_PARAM_ZVAL(key) 619 | ZEND_PARSE_PARAMETERS_END(); 620 | 621 | if (Z_TYPE_P(key) == IS_STRING) { 622 | COLLECTION_STR_FIND(CURRENT_COLLECTION, Z_STR_P(key), find_res); 623 | } 624 | 625 | if (Z_TYPE_P(key) == IS_LONG) { 626 | COLLECTION_INDEX_FIND(CURRENT_COLLECTION, Z_LVAL_P(key), find_res); 627 | } 628 | 629 | if (find_res == NULL) { 630 | ZVAL_FALSE(return_value); 631 | return; 632 | } 633 | 634 | ZVAL_TRUE(return_value); 635 | } 636 | /* }}} */ 637 | 638 | /** {{{ \Vtiful\Kernel\Collection::implode(mixed $key, string $str) 639 | */ 640 | PHP_METHOD(vtiful_collection, implode) 641 | { 642 | zend_string *key = NULL, *str = NULL, *result = NULL, *z_str_p = NULL; 643 | size_t element_char_len = 0, elements_len = 0, new_string_len = 0; 644 | zval tmp_zval_array; 645 | 646 | ZEND_PARSE_PARAMETERS_START(1, 2) 647 | Z_PARAM_STR(key) 648 | Z_PARAM_OPTIONAL 649 | Z_PARAM_STR(str) 650 | ZEND_PARSE_PARAMETERS_END(); 651 | 652 | COLLECTION_INIT(&tmp_zval_array); 653 | 654 | elements_len = zend_hash_num_elements(CURRENT_COLLECTION); 655 | 656 | if (str == NULL) { 657 | ZEND_HASH_FOREACH_VAL(CURRENT_COLLECTION, zval *val) 658 | z_str_p = _zval_get_string_func(val); 659 | element_char_len += ZSTR_LEN(z_str_p); 660 | add_next_index_str(&tmp_zval_array, z_str_p); 661 | ZEND_HASH_FOREACH_END(); 662 | } else { 663 | zval *find_result = NULL; 664 | 665 | ZEND_HASH_FOREACH_VAL(CURRENT_COLLECTION, zval *val) 666 | if (Z_TYPE_P(val) != IS_ARRAY) { 667 | continue; 668 | } 669 | COLLECTION_STR_FIND(Z_ARR_P(val), key, find_result); 670 | z_str_p = _zval_get_string_func(find_result); 671 | element_char_len += ZSTR_LEN(z_str_p); 672 | add_next_index_str(&tmp_zval_array, z_str_p); 673 | ZEND_HASH_FOREACH_END(); 674 | } 675 | 676 | if (ZEND_NUM_ARGS() < 2) { 677 | new_string_len = element_char_len+(ZSTR_LEN(key)*elements_len)-ZSTR_LEN(key); 678 | result = zend_string_safe_alloc(elements_len - 1, ZSTR_LEN(key), element_char_len, 0); 679 | collection_implode(Z_ARR(tmp_zval_array), key, result); 680 | ZSTR_VAL(result)[new_string_len] = '\0'; 681 | } else { 682 | new_string_len = element_char_len+(ZSTR_LEN(str)*elements_len)-ZSTR_LEN(str); 683 | result = zend_string_safe_alloc(elements_len - 1, ZSTR_LEN(str), element_char_len, 0); 684 | collection_implode(Z_ARR(tmp_zval_array), str, result); 685 | ZSTR_VAL(result)[new_string_len] = '\0'; 686 | } 687 | 688 | ZVAL_STR(return_value, result); 689 | 690 | VC_ZVAL_DTOR(tmp_zval_array); 691 | } 692 | /* }}} */ 693 | 694 | /** {{{ \Vtiful\Kernel\Collection::intersect(array $array) 695 | */ 696 | PHP_METHOD(vtiful_collection, intersect) 697 | { 698 | zval *array = NULL, *find_res = NULL; 699 | zval total, screening, result; 700 | size_t current_length = 0; 701 | 702 | ZEND_PARSE_PARAMETERS_START(1, 1) 703 | Z_PARAM_ARRAY(array) 704 | ZEND_PARSE_PARAMETERS_END(); 705 | 706 | COLLECTION_INIT_IN_CURRENT(&total); 707 | 708 | current_length = CURRENT_COLLECTION_COUNT; 709 | 710 | ZEND_HASH_FOREACH_VAL(Z_ARR_P(array), zval *val) 711 | add_index_zval(&total, ++current_length, val); 712 | GC_ZVAL_ADDREF(val); 713 | ZEND_HASH_FOREACH_END(); 714 | 715 | COLLECTION_INIT(&screening); 716 | COLLECTION_INIT(&result); 717 | 718 | ZEND_HASH_FOREACH_VAL(Z_ARR(total), zval *val) 719 | if (Z_TYPE_P(val) == IS_STRING) { 720 | zend_string *tmp = Z_STR_P(val); 721 | 722 | find_res = zend_hash_find(Z_ARR(screening), tmp); 723 | 724 | if (find_res == NULL) { 725 | add_assoc_long_ex(&screening, ZSTR_VAL(tmp), ZSTR_LEN(tmp), 1); 726 | } else { 727 | add_next_index_zval(&result, val); 728 | } 729 | } 730 | 731 | if (Z_TYPE_P(val) == IS_LONG) { 732 | find_res = zend_hash_index_find(Z_ARR(screening), Z_LVAL_P(val)); 733 | 734 | if (find_res == NULL) { 735 | add_index_long(&screening, Z_LVAL_P(val), 1); 736 | } else { 737 | add_next_index_zval(&result, val); 738 | } 739 | } 740 | ZEND_HASH_FOREACH_END(); 741 | 742 | NEW_COLLECTION_OBJ(return_value, &result); 743 | 744 | VC_ZVAL_DTOR(screening); 745 | VC_ZVAL_DTOR(result); 746 | VC_ZVAL_DTOR(total); 747 | } 748 | /* }}} */ 749 | 750 | /** {{{ \Vtiful\Kernel\Collection::intersectByKeys(array $array) 751 | */ 752 | PHP_METHOD(vtiful_collection, intersectByKeys) 753 | { 754 | zval *array = NULL, *find_res = NULL; 755 | zval result; 756 | 757 | ZEND_PARSE_PARAMETERS_START(1, 1) 758 | Z_PARAM_ARRAY(array) 759 | ZEND_PARSE_PARAMETERS_END(); 760 | 761 | COLLECTION_INIT(&result); 762 | 763 | ZEND_HASH_FOREACH_KEY_VAL(Z_ARR_P(array), zend_ulong long_key, zend_string *str_key, zval *val) 764 | if (str_key == NULL) { 765 | find_res = zend_hash_index_find(CURRENT_COLLECTION, long_key); 766 | } else { 767 | find_res = zend_hash_find(CURRENT_COLLECTION, str_key); 768 | } 769 | 770 | if (find_res != NULL) { 771 | if (str_key == NULL) { 772 | add_index_zval(&result, long_key, find_res); 773 | } else { 774 | add_assoc_zval_ex(&result, ZSTR_VAL(str_key), ZSTR_LEN(str_key), find_res); 775 | } 776 | 777 | GC_ZVAL_ADDREF(find_res); 778 | } 779 | ZEND_HASH_FOREACH_END(); 780 | 781 | NEW_COLLECTION_OBJ(return_value, &result); 782 | 783 | VC_ZVAL_DTOR(result); 784 | } 785 | /* }}} */ 786 | 787 | /** {{{ \Vtiful\Kernel\Collection::isEmpty() 788 | */ 789 | PHP_METHOD(vtiful_collection, isEmpty) 790 | { 791 | if (CURRENT_COLLECTION_COUNT) { 792 | RETURN_TRUE; 793 | } 794 | 795 | RETURN_FALSE; 796 | } 797 | /* }}} */ 798 | 799 | /** {{{ \Vtiful\Kernel\Collection::isNotEmpty() 800 | */ 801 | PHP_METHOD(vtiful_collection, isNotEmpty) 802 | { 803 | if (CURRENT_COLLECTION_COUNT) { 804 | RETURN_FALSE; 805 | } 806 | 807 | RETURN_TRUE; 808 | } 809 | /* }}} */ 810 | 811 | /** {{{ \Vtiful\Kernel\Collection::keyBy(string $key) 812 | */ 813 | PHP_METHOD(vtiful_collection, keyBy) 814 | { 815 | zval result; 816 | 817 | zend_string *key = NULL; 818 | 819 | zend_fcall_info fci = empty_fcall_info; 820 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 821 | 822 | ZEND_PARSE_PARAMETERS_START(1, 1) 823 | _real_arg++; 824 | if (Z_TYPE_P(_real_arg) == IS_STRING) { 825 | _real_arg--; 826 | Z_PARAM_STR(key); 827 | } 828 | if (Z_TYPE_P(_real_arg) == IS_OBJECT) { 829 | _real_arg--; 830 | Z_PARAM_FUNC(fci, fci_cache); 831 | } 832 | ZEND_PARSE_PARAMETERS_END(); 833 | 834 | COLLECTION_INIT(&result); 835 | 836 | if (key) { 837 | zval *find_res = NULL; 838 | 839 | ZEND_HASH_FOREACH_VAL(CURRENT_COLLECTION, zval *val) 840 | if (Z_TYPE_P(val) != IS_ARRAY) 841 | continue; 842 | COLLECTION_STR_FIND(Z_ARR_P(val), key, find_res); 843 | if (find_res == NULL) 844 | continue; 845 | if (Z_TYPE_P(find_res) == IS_STRING) 846 | add_assoc_zval_ex(&result, Z_STRVAL_P(find_res), Z_STRLEN_P(find_res), val); 847 | GC_ZVAL_ADDREF(val); 848 | ZEND_HASH_FOREACH_END(); 849 | } else { 850 | zval fcall_res; 851 | 852 | INIT_FCALL(1, &fcall_res); 853 | 854 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket *bucket) 855 | if (Z_TYPE(bucket->val) != IS_ARRAY) 856 | continue; 857 | FCALL_ONE_ARGS(bucket); 858 | add_assoc_zval_ex(&result, Z_STRVAL(fcall_res), Z_STRLEN(fcall_res), &bucket->val); 859 | VC_ZVAL_DTOR(fcall_res); 860 | GC_ZVAL_ADDREF(&bucket->val); 861 | ZEND_HASH_FOREACH_END(); 862 | } 863 | 864 | NEW_COLLECTION_OBJ(return_value, &result); 865 | 866 | VC_ZVAL_DTOR(result); 867 | } 868 | /* }}} */ 869 | 870 | /** {{{ \Vtiful\Kernel\Collection::keys() 871 | */ 872 | PHP_METHOD(vtiful_collection, keys) 873 | { 874 | zval result; 875 | 876 | COLLECTION_INIT(&result); 877 | 878 | ZEND_HASH_FOREACH_KEY(CURRENT_COLLECTION, zend_ulong long_key, zend_string *str_key) 879 | if (str_key) { 880 | add_next_index_str(&result, str_key); 881 | } else { 882 | add_next_index_long(&result, long_key); 883 | } 884 | ZEND_HASH_FOREACH_END(); 885 | 886 | NEW_COLLECTION_OBJ(return_value, &result); 887 | 888 | VC_ZVAL_DTOR(result); 889 | } 890 | /* }}} */ 891 | 892 | /** {{{ \Vtiful\Kernel\Collection::last([callback $callback]) 893 | */ 894 | PHP_METHOD(vtiful_collection, last) 895 | { 896 | zend_fcall_info fci = empty_fcall_info; 897 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 898 | 899 | ZEND_PARSE_PARAMETERS_START(0, 1) 900 | Z_PARAM_OPTIONAL 901 | Z_PARAM_FUNC(fci, fci_cache); 902 | ZEND_PARSE_PARAMETERS_END(); 903 | 904 | if (fci.size) { 905 | zval fcall_res; 906 | INIT_FCALL(2, &fcall_res); 907 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket *bucket) 908 | FCALL_TWO_ARGS(bucket); 909 | if (Z_TYPE(fcall_res) == IS_TRUE) 910 | ZVAL_COPY(return_value, &bucket->val); 911 | ZEND_HASH_FOREACH_END(); 912 | } else { 913 | zval *find_res; 914 | COLLECTION_INDEX_FIND(CURRENT_COLLECTION, CURRENT_COLLECTION_COUNT-1, find_res); 915 | ZVAL_COPY(return_value, find_res); 916 | } 917 | } 918 | /* }}} */ 919 | 920 | /** {{{ \Vtiful\Kernel\Collection::mapToGroups(callback $callback) 921 | */ 922 | PHP_METHOD(vtiful_collection, mapToGroups) 923 | { 924 | zval fcall_res, result; 925 | zval *find_res = NULL, *new_val = NULL; 926 | zend_string *str_key = NULL; 927 | zend_ulong long_key; 928 | zend_fcall_info fci = empty_fcall_info; 929 | zend_fcall_info_cache fci_cache = empty_fcall_info_cache; 930 | 931 | ZEND_PARSE_PARAMETERS_START(1, 1) 932 | Z_PARAM_FUNC(fci, fci_cache); 933 | ZEND_PARSE_PARAMETERS_END(); 934 | 935 | COLLECTION_INIT(&result); 936 | INIT_FCALL(2, &fcall_res); 937 | 938 | ZEND_HASH_FOREACH_BUCKET(CURRENT_COLLECTION, Bucket *bucket) 939 | FCALL_TWO_ARGS(bucket); 940 | if (Z_TYPE(fcall_res) != IS_ARRAY) 941 | continue; 942 | 943 | zend_hash_get_current_key(Z_ARR(fcall_res), &str_key, &long_key); 944 | 945 | if(str_key) { 946 | COLLECTION_STR_FIND(Z_ARR(result), str_key, find_res); 947 | if (find_res == NULL) { 948 | COLLECTION_TMP(find_res); 949 | } 950 | new_val = COLLECTION_INDEX_ZVAL(&fcall_res, 0); 951 | zend_hash_next_index_insert(Z_ARR_P(find_res), new_val); 952 | zend_hash_add(Z_ARR(result), str_key, find_res); 953 | zend_string_release(str_key); 954 | } else { 955 | COLLECTION_INDEX_FIND(Z_ARR(result), long_key, find_res); 956 | if (find_res == NULL) { 957 | COLLECTION_TMP(find_res); 958 | } 959 | new_val = COLLECTION_INDEX_ZVAL(&fcall_res, long_key); 960 | zend_hash_next_index_insert(Z_ARR_P(find_res), new_val); 961 | zend_hash_index_add(Z_ARR(result), long_key, find_res); 962 | } 963 | GC_ZVAL_ADDREF(new_val); 964 | VC_ZVAL_DTOR(fcall_res); 965 | ZEND_HASH_FOREACH_END(); 966 | 967 | NEW_COLLECTION_OBJ(return_value, &result); 968 | VC_ZVAL_DTOR(result); 969 | } 970 | /* }}} */ 971 | 972 | /** {{{ \Vtiful\Kernel\Collection::max([string $key]) 973 | */ 974 | PHP_METHOD(vtiful_collection, max) 975 | { 976 | zval *result = NULL; 977 | zend_string *key = NULL; 978 | 979 | ZEND_PARSE_PARAMETERS_START(0, 1) 980 | Z_PARAM_OPTIONAL 981 | Z_PARAM_STR(key); 982 | ZEND_PARSE_PARAMETERS_END(); 983 | 984 | if (ZEND_NUM_ARGS() < 1) { 985 | result = zend_hash_minmax(CURRENT_COLLECTION, collection_compare, 1); 986 | } else { 987 | result = zend_hash_key_minmax(CURRENT_COLLECTION, key, collection_compare_by_key, 1); 988 | } 989 | 990 | ZVAL_COPY(return_value, result); 991 | } 992 | /* }}} */ -------------------------------------------------------------------------------- /tests/all.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | all(); 12 | 13 | var_dump($result); 14 | ?> 15 | --EXPECT-- 16 | array(5) { 17 | [0]=> 18 | int(1) 19 | [1]=> 20 | int(2) 21 | [2]=> 22 | int(3) 23 | [3]=> 24 | int(4) 25 | [4]=> 26 | int(5) 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/avg.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | avg(); 9 | $collection2 = \Vtiful\Kernel\Collection::init([ 10 | ['name' => 'vikin', 'age' => 20], 11 | ['name' => 'viest', 'age' => 30] 12 | ]); 13 | $result2 = $collection2->avg('age'); 14 | 15 | var_dump($result1); 16 | var_dump($result2); 17 | ?> 18 | --EXPECT-- 19 | float(3) 20 | float(25) 21 | -------------------------------------------------------------------------------- /tests/chunk.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | chunk(4); 12 | 13 | var_dump($result); 14 | ?> 15 | --EXPECT-- 16 | object(Vtiful\Kernel\Collection)#2 (2) { 17 | [0]=> 18 | array(4) { 19 | [0]=> 20 | int(1) 21 | [1]=> 22 | int(2) 23 | [2]=> 24 | int(3) 25 | [3]=> 26 | int(4) 27 | } 28 | [1]=> 29 | array(1) { 30 | [0]=> 31 | int(5) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/collapse.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | collapse(); 12 | 13 | var_dump($result); 14 | ?> 15 | --EXPECT-- 16 | object(Vtiful\Kernel\Collection)#2 (4) { 17 | [0]=> 18 | int(1) 19 | [1]=> 20 | int(2) 21 | [2]=> 22 | int(3) 23 | [3]=> 24 | int(4) 25 | } 26 | -------------------------------------------------------------------------------- /tests/combine.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | combine(['George', 29]); 9 | 10 | var_dump($result); 11 | ?> 12 | --EXPECT-- 13 | object(Vtiful\Kernel\Collection)#2 (2) { 14 | ["name"]=> 15 | string(6) "George" 16 | ["age"]=> 17 | int(29) 18 | } 19 | -------------------------------------------------------------------------------- /tests/concat.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | concat(['address'])->concat([12])->concat([ 9 | 'obj' => new \stdClass() 10 | ]); 11 | 12 | var_dump($result); 13 | ?> 14 | --EXPECT-- 15 | object(Vtiful\Kernel\Collection)#4 (5) { 16 | [0]=> 17 | string(4) "name" 18 | [1]=> 19 | string(3) "age" 20 | [2]=> 21 | string(7) "address" 22 | [3]=> 23 | int(12) 24 | [4]=> 25 | object(stdClass)#2 (0) { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/contains.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'Desk', 'price' => 100]); 8 | 9 | $true = $collection->contains('Desk'); 10 | 11 | var_dump($true); 12 | 13 | $false = $collection->contains('New York'); 14 | 15 | var_dump($false); 16 | 17 | $collection = \Vtiful\Kernel\Collection::init([ 18 | ['product' => 'Desk', 'price' => 200, 'VV'], 19 | ['product' => 'Chair', 'price' => 100, 'BB'], 20 | ]); 21 | 22 | $true2 = $collection->contains('product', 'Desk'); 23 | 24 | var_dump($true2); 25 | 26 | $false2 = $collection->contains('product', 'Bookcase'); 27 | 28 | var_dump($false2); 29 | ?> 30 | --EXPECT-- 31 | bool(true) 32 | bool(false) 33 | bool(true) 34 | bool(false) 35 | -------------------------------------------------------------------------------- /tests/count.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | count(); 9 | var_dump($result); 10 | ?> 11 | --EXPECT-- 12 | int(5) 13 | -------------------------------------------------------------------------------- /tests/diff.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | diff([2, 4, 6, 8]); 9 | var_dump($result); 10 | ?> 11 | --EXPECT-- 12 | object(Vtiful\Kernel\Collection)#2 (3) { 13 | [0]=> 14 | int(1) 15 | [2]=> 16 | int(3) 17 | [4]=> 18 | int(5) 19 | } 20 | -------------------------------------------------------------------------------- /tests/diff_assoc.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'orange', 9 | 'type' => 'fruit', 10 | 'remain' => 6 11 | ]); 12 | 13 | $diff = $collection->diffAssoc([ 14 | 'color' => 'yellow', 15 | 'type' => 'fruit', 16 | 'remain' => 3, 17 | 'used' => 6 18 | ]); 19 | 20 | var_dump($diff); 21 | ?> 22 | --EXPECT-- 23 | object(Vtiful\Kernel\Collection)#2 (2) { 24 | ["color"]=> 25 | string(6) "orange" 26 | ["remain"]=> 27 | int(6) 28 | } 29 | -------------------------------------------------------------------------------- /tests/every.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | every(function ($value, $key) { 10 | return $value > 0; 11 | }); 12 | 13 | var_dump($result); 14 | ?> 15 | --EXPECT-- 16 | bool(true) 17 | -------------------------------------------------------------------------------- /tests/except.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 1, 9 | 'price' => 100, 10 | 'discount' => false 11 | ]); 12 | 13 | $filtered = $collection->except([ 14 | 'price', 15 | 'discount' 16 | ]); 17 | 18 | var_dump($filtered); 19 | ?> 20 | --EXPECT-- 21 | object(Vtiful\Kernel\Collection)#2 (1) { 22 | ["product_id"]=> 23 | int(1) 24 | } 25 | -------------------------------------------------------------------------------- /tests/filter.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | filter(function ($value, $key) { 12 | return $value > 2; 13 | }); 14 | 15 | $collection2 = \Vtiful\Kernel\Collection::init([ 16 | 1, 2, 3, null, false, '', 0, [] 17 | ]); 18 | 19 | $noCallback = $collection2->filter(); 20 | 21 | var_dump($callbackRes); 22 | var_dump($noCallback); 23 | ?> 24 | --EXPECT-- 25 | object(Vtiful\Kernel\Collection)#3 (2) { 26 | [0]=> 27 | int(3) 28 | [1]=> 29 | int(4) 30 | } 31 | object(Vtiful\Kernel\Collection)#4 (3) { 32 | [0]=> 33 | int(1) 34 | [1]=> 35 | int(2) 36 | [2]=> 37 | int(3) 38 | } 39 | -------------------------------------------------------------------------------- /tests/first.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | first(function ($value, $key) { 12 | return $value > 2; 13 | }); 14 | 15 | $noCollback = $collection->first(); 16 | 17 | var_dump($collbackRes); 18 | var_dump($noCollback); 19 | ?> 20 | --EXPECT-- 21 | int(3) 22 | int(1) 23 | -------------------------------------------------------------------------------- /tests/first_where.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'Regena', 'age' => 12], 9 | ['name' => 'Linda', 'age' => 14], 10 | ['name' => 'Diego', 'age' => 23], 11 | ['name' => 'Linda', 'age' => 84], 12 | ]); 13 | 14 | $result1 = $collection->firstWhere('name', 'Linda'); 15 | $result2 = $collection->firstWhere('age', '>=', 18); 16 | 17 | var_dump($result1); 18 | var_dump($result2); 19 | ?> 20 | --EXPECT-- 21 | object(Vtiful\Kernel\Collection)#2 (2) { 22 | ["name"]=> 23 | string(5) "Linda" 24 | ["age"]=> 25 | int(14) 26 | } 27 | object(Vtiful\Kernel\Collection)#3 (2) { 28 | ["name"]=> 29 | string(5) "Diego" 30 | ["age"]=> 31 | int(23) 32 | } 33 | -------------------------------------------------------------------------------- /tests/flat_map.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'Sally'], 9 | ['school' => 'Arkansas'], 10 | ['age' => 28] 11 | ]); 12 | 13 | $flattened = $collection->flatMap(function ($values) { 14 | return array_map('strtoupper', $values); 15 | }); 16 | 17 | var_dump($flattened); 18 | ?> 19 | --EXPECT-- 20 | object(Vtiful\Kernel\Collection)#3 (3) { 21 | [0]=> 22 | array(1) { 23 | ["name"]=> 24 | string(5) "SALLY" 25 | } 26 | [1]=> 27 | array(1) { 28 | ["school"]=> 29 | string(8) "ARKANSAS" 30 | } 31 | [2]=> 32 | array(1) { 33 | ["age"]=> 34 | string(2) "28" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/flatten.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'viest', 9 | 'languages' => [ 10 | 'php', 'c' 11 | ] 12 | ]); 13 | 14 | $flattened = $collection1->flatten(); 15 | 16 | var_dump($flattened); 17 | 18 | $collection2 = \Vtiful\Kernel\Collection::init([ 19 | 'Apple' => [ 20 | ['name' => 'iPhone 6S', 'brand' => 'Apple'], 21 | ], 22 | 'Samsung' => [ 23 | ['name' => 'Galaxy S7', 'brand' => 'Samsung'] 24 | ], 25 | ]); 26 | 27 | $products = $collection2->flatten(2); 28 | 29 | var_dump($products); 30 | ?> 31 | --EXPECT-- 32 | object(Vtiful\Kernel\Collection)#2 (3) { 33 | [0]=> 34 | string(5) "viest" 35 | [1]=> 36 | string(3) "php" 37 | [2]=> 38 | string(1) "c" 39 | } 40 | object(Vtiful\Kernel\Collection)#4 (4) { 41 | [0]=> 42 | string(9) "iPhone 6S" 43 | [1]=> 44 | string(5) "Apple" 45 | [2]=> 46 | string(9) "Galaxy S7" 47 | [3]=> 48 | string(7) "Samsung" 49 | } 50 | -------------------------------------------------------------------------------- /tests/flip.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'viest', 9 | 'extension' => 'collection' 10 | ]); 11 | 12 | $flipped = $collection->flip(); 13 | 14 | var_dump($flipped); 15 | ?> 16 | --EXPECT-- 17 | object(Vtiful\Kernel\Collection)#2 (2) { 18 | ["viest"]=> 19 | string(4) "name" 20 | ["collection"]=> 21 | string(9) "extension" 22 | } 23 | -------------------------------------------------------------------------------- /tests/for_page.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | forPage(2, 3); 12 | 13 | var_dump($chunk); 14 | ?> 15 | --EXPECT-- 16 | object(Vtiful\Kernel\Collection)#2 (3) { 17 | [0]=> 18 | int(4) 19 | [1]=> 20 | int(5) 21 | [2]=> 22 | int(6) 23 | } 24 | -------------------------------------------------------------------------------- /tests/forget.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'viest', 9 | 'extension' => 'collection' 10 | ]); 11 | 12 | $result = $collection->forget('name'); 13 | 14 | var_dump($result); 15 | ?> 16 | --EXPECT-- 17 | object(Vtiful\Kernel\Collection)#1 (1) { 18 | ["extension"]=> 19 | string(10) "collection" 20 | } 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/get.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'viest', 9 | 'extension' => 'collection', 10 | ]); 11 | 12 | $name = $collection->get('name'); 13 | $null = $collection->get('age'); 14 | $age = $collection->get('age', 22); 15 | 16 | var_dump($name, $null, $age); 17 | ?> 18 | --EXPECT-- 19 | string(5) "viest" 20 | NULL 21 | int(22) 22 | -------------------------------------------------------------------------------- /tests/group_by.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'account-x10', 'product' => 'Chair'], 9 | ['account_id' => 'account-x10', 'product' => 'Bookcase'], 10 | ['account_id' => 'account-x11', 'product' => 'Desk'], 11 | ]); 12 | 13 | $grouped = $collection->groupBy(function ($item, $key) { 14 | return substr($item['account_id'], -3); 15 | }); 16 | 17 | var_dump($grouped->toArray()); 18 | 19 | $grouped = $collection->groupBy('account_id'); 20 | 21 | var_dump($grouped->toArray()); 22 | ?> 23 | --EXPECT-- 24 | array(2) { 25 | ["x10"]=> 26 | array(2) { 27 | [0]=> 28 | array(2) { 29 | ["account_id"]=> 30 | string(11) "account-x10" 31 | ["product"]=> 32 | string(5) "Chair" 33 | } 34 | [1]=> 35 | array(2) { 36 | ["account_id"]=> 37 | string(11) "account-x10" 38 | ["product"]=> 39 | string(8) "Bookcase" 40 | } 41 | } 42 | ["x11"]=> 43 | array(1) { 44 | [0]=> 45 | array(2) { 46 | ["account_id"]=> 47 | string(11) "account-x11" 48 | ["product"]=> 49 | string(4) "Desk" 50 | } 51 | } 52 | } 53 | array(2) { 54 | ["account-x10"]=> 55 | array(2) { 56 | [0]=> 57 | array(2) { 58 | ["account_id"]=> 59 | string(11) "account-x10" 60 | ["product"]=> 61 | string(5) "Chair" 62 | } 63 | [1]=> 64 | array(2) { 65 | ["account_id"]=> 66 | string(11) "account-x10" 67 | ["product"]=> 68 | string(8) "Bookcase" 69 | } 70 | } 71 | ["account-x11"]=> 72 | array(1) { 73 | [0]=> 74 | array(2) { 75 | ["account_id"]=> 76 | string(11) "account-x11" 77 | ["product"]=> 78 | string(4) "Desk" 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/has.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'viest', 9 | 'age' => 21 10 | ]); 11 | 12 | $true = $collection->has('age'); 13 | $false = $collection->has('address'); 14 | 15 | var_dump($true, $false); 16 | ?> 17 | --EXPECT-- 18 | bool(true) 19 | bool(false) 20 | -------------------------------------------------------------------------------- /tests/implode.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | implode('-'); 12 | 13 | $collection2 = \Vtiful\Kernel\Collection::init([ 14 | ['name' => 'viest', 'age' => 21], 15 | ['name' => 'vikin', 'age' => 20], 16 | ['name' => 'wjx', 'age' => 22], 17 | ]); 18 | 19 | $result2 = $collection2->implode('name', '-'); 20 | 21 | var_dump($result1, $result2); 22 | ?> 23 | --EXPECT-- 24 | string(3) "1-a" 25 | string(15) "viest-vikin-wjx" 26 | -------------------------------------------------------------------------------- /tests/init.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection initialization 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 11 | --EXPECT-- 12 | object(Vtiful\Kernel\Collection)#1 (1) { 13 | [0]=> 14 | int(1) 15 | } 16 | -------------------------------------------------------------------------------- /tests/intersect.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | intersect([2, 7, 5, 9, 10, 'b']); 10 | 11 | var_dump($intersect->toArray()); 12 | ?> 13 | --EXPECT-- 14 | array(2) { 15 | [0]=> 16 | int(2) 17 | [1]=> 18 | int(5) 19 | } 20 | -------------------------------------------------------------------------------- /tests/intersect_by_key.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'UX301', 'type' => 'screen', 'year' => 2009 9 | ]); 10 | 11 | $intersect = $collection->intersectByKeys([ 12 | 'reference' => 'UX404', 'type' => 'tab', 'year' => 2011 13 | ]); 14 | 15 | var_dump($intersect); 16 | ?> 17 | --EXPECT-- 18 | object(Vtiful\Kernel\Collection)#2 (2) { 19 | ["type"]=> 20 | string(6) "screen" 21 | ["year"]=> 22 | int(2009) 23 | } 24 | -------------------------------------------------------------------------------- /tests/is_empty.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | isEmpty(); 10 | 11 | $collection2 = \Vtiful\Kernel\Collection::init([]); 12 | 13 | $false = $collection2->isEmpty(); 14 | 15 | var_dump($true, $false); 16 | ?> 17 | --EXPECT-- 18 | bool(true) 19 | bool(false) 20 | -------------------------------------------------------------------------------- /tests/is_not_empty.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | isNotEmpty(); 10 | 11 | $collection2 = \Vtiful\Kernel\Collection::init([]); 12 | 13 | $true = $collection2->isNotEmpty(); 14 | 15 | var_dump($false, $true); 16 | ?> 17 | --EXPECT-- 18 | bool(false) 19 | bool(true) -------------------------------------------------------------------------------- /tests/key_by.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'prod-100', 'name' => 'Desk'], 9 | ['product_id' => 'prod-200', 'name' => 'Chair'], 10 | ]); 11 | 12 | $keyed1 = $collection1->keyBy('product_id'); 13 | 14 | $collection2 = \Vtiful\Kernel\Collection::init([ 15 | ['product_id' => 'prod-100', 'name' => 'Desk'], 16 | ['product_id' => 'prod-200', 'name' => 'Chair'], 17 | ]); 18 | 19 | $keyed2 = $collection2->keyBy(function ($item) { 20 | return strtoupper($item['product_id']); 21 | }); 22 | 23 | var_dump($keyed1, $keyed2); 24 | ?> 25 | --EXPECT-- 26 | object(Vtiful\Kernel\Collection)#2 (2) { 27 | ["prod-100"]=> 28 | array(2) { 29 | ["product_id"]=> 30 | string(8) "prod-100" 31 | ["name"]=> 32 | string(4) "Desk" 33 | } 34 | ["prod-200"]=> 35 | array(2) { 36 | ["product_id"]=> 37 | string(8) "prod-200" 38 | ["name"]=> 39 | string(5) "Chair" 40 | } 41 | } 42 | object(Vtiful\Kernel\Collection)#5 (2) { 43 | ["PROD-100"]=> 44 | array(2) { 45 | ["product_id"]=> 46 | string(8) "prod-100" 47 | ["name"]=> 48 | string(4) "Desk" 49 | } 50 | ["PROD-200"]=> 51 | array(2) { 52 | ["product_id"]=> 53 | string(8) "prod-200" 54 | ["name"]=> 55 | string(5) "Chair" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/keys.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | ['product_id' => 'prod-100', 'name' => 'Desk'], 9 | 'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'], 10 | ]); 11 | 12 | $keys = $collection->keys(); 13 | 14 | var_dump($keys); 15 | ?> 16 | --EXPECT-- 17 | object(Vtiful\Kernel\Collection)#2 (2) { 18 | [0]=> 19 | string(8) "prod-100" 20 | [1]=> 21 | string(8) "prod-200" 22 | } 23 | -------------------------------------------------------------------------------- /tests/last.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | last(function ($value, $key) { 10 | return $value < 3; 11 | }); 12 | 13 | $defaultLast = $collection->last(); 14 | 15 | var_dump($callbackLast, $defaultLast); 16 | ?> 17 | --EXPECT-- 18 | int(2) 19 | int(4) 20 | -------------------------------------------------------------------------------- /tests/load.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for collection presence 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 9 | --EXPECT-- 10 | collection extension is available 11 | -------------------------------------------------------------------------------- /tests/map.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | map(function ($item, $key) { 9 | return $item * 2; 10 | }); 11 | var_dump($multiplied); 12 | ?> 13 | --EXPECT-- 14 | object(Vtiful\Kernel\Collection)#3 (5) { 15 | [0]=> 16 | int(2) 17 | [1]=> 18 | int(4) 19 | [2]=> 20 | int(6) 21 | [3]=> 22 | int(8) 23 | [4]=> 24 | int(10) 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/map_to_groups.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 'John Doe', 10 | 'department' => 'Sales', 11 | ],[ 12 | 'name' => 'Jane Doe', 13 | 'department' => 'Sales', 14 | ],[ 15 | 'name' => 'Johnny Doe', 16 | 'department' => 'Marketing', 17 | ] 18 | ]); 19 | 20 | $grouped = $collection->mapToGroups(function ($item, $key) { 21 | return [$item['department'] => $item['name']]; 22 | }); 23 | 24 | var_dump($grouped); 25 | ?> 26 | --EXPECT-- 27 | object(Vtiful\Kernel\Collection)#3 (2) { 28 | ["Sales"]=> 29 | array(2) { 30 | [0]=> 31 | string(8) "John Doe" 32 | [1]=> 33 | string(8) "Jane Doe" 34 | } 35 | ["Marketing"]=> 36 | array(1) { 37 | [0]=> 38 | string(10) "Johnny Doe" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/max.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | max(); 10 | 11 | $collection2 = \Vtiful\Kernel\Collection::init([ 12 | ['foo' => 10], 13 | ['foo' => 50], 14 | ['foo' => 20], 15 | ]); 16 | 17 | $defaultKey = $collection2->max('foo'); 18 | 19 | var_dump($default, $defaultKey); 20 | ?> 21 | --EXPECT-- 22 | int(6) 23 | int(50) -------------------------------------------------------------------------------- /tests/toarray.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check Collection operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | toArray(); 9 | var_dump($result); 10 | ?> 11 | --EXPECT-- 12 | array(5) { 13 | [0]=> 14 | int(1) 15 | [1]=> 16 | int(2) 17 | [2]=> 18 | int(3) 19 | [3]=> 20 | int(4) 21 | [4]=> 22 | int(5) 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /travis/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | TEST_DIR="`pwd`/tests/" 3 | 4 | make test 5 | 6 | for file in `find $TEST_DIR -name "*.diff" 2>/dev/null` 7 | do 8 | grep "\-\-XFAIL--" ${file/%diff/phpt} >/dev/null 2>&1 9 | if [ $? -gt 0 ] 10 | then 11 | FAILS[${#FAILS[@]}]="$file" 12 | fi 13 | done 14 | 15 | if [ ${#FAILS[@]} -gt 0 ] 16 | then 17 | for fail in "${FAILS[@]}" 18 | do 19 | sh -xc "cat $fail" 20 | done 21 | exit 1 22 | else 23 | exit 0 24 | fi --------------------------------------------------------------------------------