├── .github └── workflows │ ├── fasttest.yml │ └── fulltest.yml ├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── examples ├── readme-functional-libary.php ├── readme-functional-native.php └── readme-structured.php ├── images ├── libary-functional-min.png ├── native-functional-min.png └── structured-min.png ├── phpunit.xml ├── src └── ArrayCreate.php └── tests ├── ArrayCreateTest.php ├── ExamplesTest.php └── WithoutComposerTest.php /.github/workflows/fasttest.yml: -------------------------------------------------------------------------------- 1 | name: Fast Test Suite 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | phpunit: 7 | name: PHP ${{ matrix.php }} / No Composer 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | php: ['5.4', '5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2'] 13 | 14 | steps: 15 | - name: Checkout Project 16 | uses: actions/checkout@v2 17 | 18 | - name: Install PHP ${{ matrix.php }} 19 | uses: shivammathur/setup-php@v2 20 | with: 21 | php-version: ${{ matrix.php }} 22 | extensions: mbstring 23 | ini-values: date.timezone='UTC', session.save_path="${{ runner.temp }}" 24 | 25 | - name: PHP Unit tests for PHP ${{ matrix.php }} 26 | run: php ./tests/WithoutComposerTest.php 27 | -------------------------------------------------------------------------------- /.github/workflows/fulltest.yml: -------------------------------------------------------------------------------- 1 | name: Full Test Suite 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | env: 12 | DEFAULT_COMPOSER_FLAGS: "--prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi" 13 | PHPUNIT_COVERAGE_FLAGS: "--coverage-clover=clover.xml" 14 | PHPUNIT_EXCLUDE_GROUP: "--exclude-group mssql,oci,wincache,xcache,zenddata,cubrid" 15 | XDEBUG_MODE: coverage, develop 16 | 17 | jobs: 18 | phpunit: 19 | name: PHP ${{ matrix.php }} / PHPUnit / Coverage / Composer 20 | runs-on: ubuntu-latest 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | php: ['7.4'] 25 | 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v2 29 | 30 | - name: Install PHP 31 | uses: shivammathur/setup-php@v2 32 | with: 33 | php-version: ${{ matrix.php }} 34 | tools: pecl 35 | extensions: mbstring 36 | ini-values: date.timezone='UTC', session.save_path="${{ runner.temp }}" 37 | 38 | - name: Get composer cache directory 39 | id: composer-cache 40 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 41 | 42 | - name: Cache composer dependencies 43 | uses: actions/cache@v1 44 | with: 45 | path: ${{ steps.composer-cache.outputs.dir }} 46 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 47 | restore-keys: ${{ runner.os }}-composer- 48 | 49 | - name: Install dependencies 50 | run: composer update ${{ env.DEFAULT_COMPOSER_FLAGS }} 51 | 52 | - name: PHP Unit tests for PHP ${{ matrix.php }} 53 | run: vendor/bin/phpunit --verbose ${{ env.PHPUNIT_COVERAGE_FLAGS }} ${{ env.PHPUNIT_EXCLUDE_GROUP }} --colors=always 54 | 55 | - name: Report Coverage to Codacy 56 | if: github.event_name == 'push' 57 | run: bash <(curl -Ls https://coverage.codacy.com/get.sh) report --project-token ${{ secrets.CODACY_PROJECT_TOKEN }} 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | composer.phar 3 | ocular.phar 4 | /vendor/ 5 | /.phpunit.cache/ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, RodrigoDornelles 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rodrigodornelles/php-array-lib 2 | 3 | [![version](https://img.shields.io/github/v/release/rodrigodornelles/php-array-lib?sort=semver&logo=packagist)](https://packagist.org/packages/rodrigodornelles/php-array-lib) 4 | [![license](https://img.shields.io/github/license/rodrigodornelles/php-array-lib)](https://github.com/RodrigoDornelles/php-array-lib/blob/master/LICENSE) 5 | [![quality](https://img.shields.io/codacy/grade/5ac185bc5cb44339ac8dc2ee98e8082d?logo=codacy)](https://www.codacy.com/gh/RodrigoDornelles/php-array-lib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=RodrigoDornelles/php-array-lib&utm_campaign=Badge_Grade) 6 | [![coverage](https://img.shields.io/codacy/coverage/5ac185bc5cb44339ac8dc2ee98e8082d?logo=codacy)](https://www.codacy.com/gh/RodrigoDornelles/php-array-lib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=RodrigoDornelles/php-array-lib&utm_campaign=Badge_Coverage) 7 | [![building](https://img.shields.io/github/checks-status/rodrigodornelles/php-array-lib/master?logo=github)](https://github.com/rodrigodornelles/php-array-lib/actions) 8 | 9 | 10 | > simple libary for functional programing paradigm with arrays 11 | 12 | ## Features ## 13 | 14 | * Test driven development style _(TDD)_ 15 | * PHP version compatibility **5.4** at **8.2** 16 | * Make your code cleaner and more readable 17 | * Adds new methods to manipulate arrays _(Inspired by **ruby**, **js** and other langs)_ 18 | 19 | 20 | ## How to Use 21 | 22 | ```PHP 23 | 24 | use ArrayCreate; # if you using namespaces 25 | 26 | $myNewArray = ArrayCreate::from($myOriginalArray) # instantiate pipeline class 27 | ->map(someItemFunction) # first function to iterate on each item 28 | ->map(anotherItemFunction) # next function to iterate on each item 29 | ->filter(anotherItemFunction2) # next function to filter on each item 30 | ->construct(); # returns new array 31 | ``` 32 | 33 | ## Examples ## 34 | 35 | ### side by side comparison ### 36 | 37 | Make an algorithm that sorts an array, removes the numbers not divisible by 3, and shows the result of each multiplied by 2 and separated by commas. 38 | 39 | | Libary
Functional | Native
Functional | Structured | 40 | | :-: | :-: | :-: | 41 | | [![libary functional example](/images/libary-functional-min.png)](./examples/readme-functional-libary.php) | [![native functional example](/images/native-functional-min.png)](./examples/readme-functional-native.php) | [![structured example](/images/structured-min.png)](./examples/readme-structured.php) 42 | 43 | ## Installation ## 44 | 45 | ### With Composer ### 46 | 47 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 48 | 49 | Either run 50 | 51 | ```SHELL 52 | $ composer require rodrigodornelles/php-array-lib "~1.0.0" 53 | ``` 54 | 55 | or add 56 | 57 | ```JSON 58 | "rodrigodornelles/php-array-lib": "~1.0.0" 59 | ``` 60 | 61 | to the `require` section of your `composer.json` file. 62 | 63 | ### Without Composer ### 64 | 65 | #### Step 1 #### 66 | 67 | Download libary in 68 | 69 | #### Step 2 #### 70 | 71 | Extract the file into your libraries folder 72 | 73 | #### Step 3 #### 74 | 75 | Import the main class 76 | 77 | ```PHP 78 | sort() 12 | ->filter(fn($n) => !($n % 3)) 13 | ->map(fn($n) => $n * 2) 14 | ->join(', '); 15 | } 16 | 17 | readmeFunctionalLibary(); 18 | -------------------------------------------------------------------------------- /examples/readme-functional-native.php: -------------------------------------------------------------------------------- 1 | $n * 2, 11 | array_filter($numbers, 12 | fn($n) => !($n % 3) 13 | ) 14 | ) 15 | ); 16 | } 17 | 18 | readmeFunctionalNative(); 19 | -------------------------------------------------------------------------------- /examples/readme-structured.php: -------------------------------------------------------------------------------- 1 | $number) 10 | { 11 | if ($number % 3) { 12 | continue; 13 | } 14 | 15 | echo $number * 2; 16 | 17 | if (array_key_last($numbers) !== $key) { 18 | echo ", "; 19 | } 20 | } 21 | } 22 | 23 | readmeStructured(); 24 | -------------------------------------------------------------------------------- /images/libary-functional-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/php-array-lib/9d5e531ac2ec3db5c76e37181e512a2746d09898/images/libary-functional-min.png -------------------------------------------------------------------------------- /images/native-functional-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/php-array-lib/9d5e531ac2ec3db5c76e37181e512a2746d09898/images/native-functional-min.png -------------------------------------------------------------------------------- /images/structured-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RodrigoDornelles/php-array-lib/9d5e531ac2ec3db5c76e37181e512a2746d09898/images/structured-min.png -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | tests 18 | 19 | 20 | 21 | 23 | 24 | src 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/ArrayCreate.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2022, Rodrigo Dornelles 7 | * 8 | ** 9 | * 10 | * @method construct 11 | * @method filter 12 | * @method first 13 | * @method flip 14 | * @method from 15 | * @method join 16 | * @method last 17 | * @method map 18 | * @method sort 19 | * 20 | ** 21 | */ 22 | class ArrayCreate 23 | { 24 | /** 25 | * Internal array 26 | * 27 | * @var array 28 | */ 29 | private $_array; 30 | 31 | /** 32 | * @param array $params 33 | */ 34 | private function __construct($params = []) 35 | { 36 | $this->_array = isset($params['from'])? (array) ($params['from']): []; 37 | } 38 | 39 | /** 40 | * @return array 41 | */ 42 | public function construct() 43 | { 44 | return $this->_array; 45 | } 46 | 47 | /** 48 | * @param Closure $func 49 | * 50 | * @return ArrayCreate 51 | */ 52 | public function filter($func) 53 | { 54 | $this->_array = array_filter($this->_array, $func); 55 | return $this; 56 | } 57 | 58 | /** 59 | * @return mixed 60 | */ 61 | public function first() 62 | { 63 | $item = current(array_slice($this->_array, 0, 1)); 64 | return is_array($item)? self::from($item): $item; 65 | } 66 | 67 | /** 68 | * @return ArrayCreate 69 | */ 70 | public function flip() 71 | { 72 | $this->_array = array_flip($this->_array); 73 | return $this; 74 | } 75 | 76 | /** 77 | * @param array $array 78 | * 79 | * @return ArrayCreate 80 | */ 81 | public static function from($array) 82 | { 83 | return new self(['from' => $array]); 84 | } 85 | 86 | /** 87 | * @param string $glue 88 | * 89 | * @return string 90 | */ 91 | public function join($glue = '') 92 | { 93 | return implode($glue, $this->_array); 94 | } 95 | 96 | /** 97 | * @return mixed 98 | */ 99 | public function last() 100 | { 101 | $item = end($this->_array); 102 | reset($this->_array); 103 | return is_array($item)? self::from($item): $item; 104 | } 105 | 106 | /** 107 | * @param Closure $func 108 | * 109 | * @return ArrayCreate 110 | */ 111 | public function map($func) 112 | { 113 | $this->_array = array_map($func, $this->_array); 114 | return $this; 115 | } 116 | 117 | /** 118 | * @param Int $sort_flags 119 | * 120 | * @return ArrayCreate 121 | */ 122 | public function sort($sort_flags = SORT_REGULAR) 123 | { 124 | sort($this->_array, $sort_flags); 125 | return $this; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /tests/ArrayCreateTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(ArrayCreate::class, $array); 15 | } 16 | 17 | public function testFilter() 18 | { 19 | $expected = [1, 3, 5, 7, 9]; 20 | $expected = array_combine($expected, $expected); 21 | $actual = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 22 | $actual = ArrayCreate::from($actual) 23 | ->filter(function($n){return $n % 2;}) 24 | ->construct(); 25 | 26 | $this->assertSame($expected, $actual); 27 | } 28 | 29 | public function testFirst() 30 | { 31 | $expected = 'first'; 32 | $actual = ['first', 'last']; 33 | $actual = ArrayCreate::from($actual) 34 | ->first(); 35 | 36 | $this->assertSame($expected, $actual); 37 | } 38 | 39 | public function testFlip() 40 | { 41 | $expected = ['bar' => 'foo']; 42 | $actual = ['foo' => 'bar']; 43 | $actual = ArrayCreate::from($actual) 44 | ->flip() 45 | ->construct(); 46 | 47 | $this->assertSame($expected, $actual); 48 | } 49 | 50 | public function testJoin() 51 | { 52 | $expected = 'foo, bar, z'; 53 | $actual = ['foo', 'bar', 'z']; 54 | $actual = ArrayCreate::from($actual) 55 | ->join(', '); 56 | 57 | $this->assertSame($expected, $actual); 58 | } 59 | 60 | public function testLast() 61 | { 62 | $expected = 'last'; 63 | $actual = ['first', 'last']; 64 | $actual = ArrayCreate::from($actual) 65 | ->last(); 66 | 67 | $this->assertSame($expected, $actual); 68 | } 69 | 70 | public function testMap() 71 | { 72 | $expected = [2, 4, 6, 8]; 73 | $actual = [1, 2, 3, 4]; 74 | $actual = ArrayCreate::from($actual) 75 | ->map(function($n){return $n * 2;}) 76 | ->construct(); 77 | 78 | $this->assertSame($expected, $actual); 79 | } 80 | } -------------------------------------------------------------------------------- /tests/ExamplesTest.php: -------------------------------------------------------------------------------- 1 | assertSame($expected, $content); 25 | } 26 | 27 | /** 28 | * @covers ::readmeFunctionalNative 29 | */ 30 | public function testFunctionalNative() 31 | { 32 | $expected = '6, 30, 84, 108'; 33 | ob_start(); 34 | require __DIR__.'/../examples/readme-functional-native.php'; 35 | $content = ob_get_contents(); 36 | ob_end_clean(); 37 | 38 | $this->assertSame($expected, $content); 39 | } 40 | 41 | /** 42 | * @covers ::readmeStructured 43 | */ 44 | public function testReadmeStructured() 45 | { 46 | $expected = '6, 30, 84, 108'; 47 | ob_start(); 48 | require __DIR__.'/../examples/readme-structured.php'; 49 | $content = ob_get_contents(); 50 | ob_end_clean(); 51 | 52 | $this->assertSame($expected, $content); 53 | } 54 | } -------------------------------------------------------------------------------- /tests/WithoutComposerTest.php: -------------------------------------------------------------------------------- 1 | join(',') == 'FOO,BAR,Z'); 11 | 12 | /** test 2 */ 13 | $string = "0,1,2,3,5"; 14 | $array = explode(",", $string); 15 | $array = ArrayCreate::from($array)->map(function($n) {return (int) $n;})->construct(); 16 | assert(array_filter($array, 'is_int')); 17 | 18 | /** test 3 */ 19 | $array = [1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]; 20 | $array = ArrayCreate::from($array)->filter(function($n) {return $n % 2;})->construct(); 21 | assert(count($array) == 5); 22 | 23 | /** test 4 */ 24 | $array = ['first', 'middle', 'last']; 25 | $array = ArrayCreate::from($array); 26 | assert($array->first() == 'first'); 27 | assert($array->last() == 'last'); 28 | 29 | /** test 5 */ 30 | $array = ['first', 'middle', 'last']; 31 | $array = ArrayCreate::from($array)->flip()->construct(); 32 | assert($array['first'] == 0); 33 | assert($array['last'] == 2); 34 | 35 | print("OK.\n"); 36 | --------------------------------------------------------------------------------