├── .gitignore ├── .scrutinizer.yml ├── .styleci.yml ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── composer.json ├── docs ├── PHPCollections-Checker.md ├── PHPCollections-Collections-ArrayList.md ├── PHPCollections-Collections-BaseCollection.md ├── PHPCollections-Collections-Dictionary.md ├── PHPCollections-Collections-GenericList.md ├── PHPCollections-Collections-Pair.md ├── PHPCollections-Collections-Stack.md ├── PHPCollections-DataHolder.md ├── PHPCollections-Exceptions-InvalidOperationException.md ├── PHPCollections-Interfaces-CollectionInterface.md ├── PHPCollections-Interfaces-DictionaryInterface.md ├── PHPCollections-Interfaces-MergeableInterface.md ├── PHPCollections-Interfaces-ObjectCollectionInterface.md ├── PHPCollections-Interfaces-SortableInterface.md └── README.md ├── phpunit.xml ├── src ├── Checker.php ├── Collections │ ├── ArrayList.php │ ├── BaseCollection.php │ ├── Dictionary.php │ ├── GenericList.php │ ├── Pair.php │ └── Stack.php ├── DataHolder.php ├── Exceptions │ └── InvalidOperationException.php ├── Interfaces │ ├── CollectionInterface.php │ ├── DictionaryInterface.php │ ├── IterableInterface.php │ ├── MergeableInterface.php │ ├── ObjectCollectionInterface.php │ └── SortableInterface.php └── utils.php └── tests └── Unit ├── ArrayListTest.php ├── CheckerTest.php ├── DataHolderTest.php ├── DictionaryTest.php ├── GenericListTest.php ├── InvalidOperationExceptionTest.php └── StackTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .vscode/ 3 | composer.lock 4 | docs/structure.xml 5 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | checks: 2 | php: 3 | code_rating: true 4 | duplication: true 5 | 6 | filter: 7 | excluded_paths: 8 | - tests/* 9 | 10 | build: 11 | environment: 12 | php: 13 | version: '7.2' 14 | nodes: 15 | analysis: 16 | tests: 17 | override: 18 | - php-scrutinizer-run 19 | - 20 | command: 'vendor/bin/phpunit --coverage-clover=coverage.clover' 21 | coverage: 22 | file: 'coverage.clover' 23 | format: 'clover' -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: recommended 2 | 3 | risky: false 4 | 5 | finder: 6 | name: 7 | - "*.php" 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - '7.2' 5 | 6 | before_script: 7 | - composer install 8 | 9 | script: 10 | - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Version 1.2 4 | - Added `diff` and `slice` methods to `BaseCollection` class. 5 | - Extracted `contains` method from `ArrayList` to `BaseCollection`, now is available on all child classes. 6 | - Removed `find` method from `ArrayList`, `Dictionary`, and `GenericList` classes. 7 | - Removed `search` method from `GenericList` class. 8 | - Updated documentation. 9 | 10 | ## Version 1.3 11 | - Added `equals` method to `BaseCollection` class. 12 | - Added `sum` method to `BaseCollection` class. 13 | - Added `fill` method to `BaseCollection` class. 14 | - Replaced `is_a` native function by `instanceof` operator. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![StyleCI](https://github.styleci.io/repos/106444310/shield?branch=master)](https://github.styleci.io/repos/106444310) 2 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/maxalmonte14/phpcollections/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/maxalmonte14/phpcollections/?branch=master) 3 | [![Build Status](https://scrutinizer-ci.com/g/maxalmonte14/phpcollections/badges/build.png?b=master)](https://scrutinizer-ci.com/g/maxalmonte14/phpcollections/build-status/master) 4 | 5 | ## About PHPCollections 6 | 7 | PHPCollections is a set of data structures that try to make your life easier when you're working with PHP and large sets of data. Inspired by languages like Java or C#, PHPCollections offers data structures like List, Map, Stack and more, check it out! 8 | 9 | ## Requirements 10 | 11 | ``` 12 | PHP >= 7.2 13 | ``` 14 | 15 | ## Installation 16 | 17 | ``` 18 | composer require "maxalmonte14/phpcollections" 19 | ``` 20 | 21 | ## Examples 22 | 23 | Imagine you're storing Post objects for fetching like so. 24 | 25 | ```php 26 | $posts[] = new Post(1, 'PHP 7.2 release notes'); 27 | $posts[] = new Post(2, 'New Laravel 5.5 LTS make:factory command'); 28 | ``` 29 | 30 | Everything is fine! But maybe you made a mistake for some mysterious reason and added a non-Post object. 31 | 32 | ```php 33 | $posts[] = 5 // This is not even an object! 34 | ``` 35 | 36 | When you'll try to fetch your posts array you'll be in troubles. 37 | 38 | ```html 39 | 40 | 41 | 42 | id; ?> 43 | title; ?> 44 | 45 | 46 | ``` 47 | 48 | Fortunately PHPCollections exists. 49 | 50 | ```php 51 | $posts = new GenericList( 52 | Post::class, 53 | new Post(1, 'PHP 7.2 release notes'), 54 | new Post(2, 'New Laravel 5.5 LTS make:factory command') 55 | ); 56 | $posts->add(5); // An InvalidArgumentException is thrown! 57 | ``` 58 | 59 | Of course there exist more flexible data structures like ArrayList. 60 | 61 | ```php 62 | $posts = new ArrayList(); 63 | $posts->add(new Post(1, 'PHP 7.2 release notes')); 64 | $posts->add(new Post(2, 'New Laravel 5.5 LTS make:factory command')); 65 | $posts->add(5); // Everything is fine, I need this 5 anyway 66 | ``` 67 | 68 | ## Features 69 | 70 | - Different types of collections like Dictionary, Stack and GenericList. 71 | - Simple API. 72 | - Lightweight, no extra packages needed. 73 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maxalmonte14/phpcollections", 3 | "description": "A set of collections for PHP.", 4 | "keywords": [ 5 | "collection", 6 | "php", 7 | "php7", 8 | "php-library", 9 | "collections", 10 | "collection", 11 | "generic", 12 | "arraylist", 13 | "stack", 14 | "dictionary", 15 | "pair" 16 | ], 17 | "license": "MIT", 18 | "support": { 19 | "issues": "https://github.com/maxalmonte14/phpcollections/issues", 20 | "source": "https://github.com/maxalmonte14/phpcollections" 21 | }, 22 | "authors": [ 23 | { 24 | "name": "Max Almonte", 25 | "email": "maxalmonte14@hotmail.com", 26 | "homepage": "https://www.devalmonte.com" 27 | } 28 | ], 29 | "require": { 30 | "php": "^7.2" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "PHPCollections\\": "src/" 35 | }, 36 | "files": [ 37 | "src/utils.php" 38 | ] 39 | }, 40 | "autoload-dev": { 41 | "psr-4": { 42 | "Tests\\": "tests/" 43 | } 44 | }, 45 | "require-dev": { 46 | "phpunit/phpunit": "^7.4", 47 | "evert/phpdoc-md": "^0.2.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /docs/PHPCollections-Checker.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Checker 2 | =============== 3 | 4 | An utility class for checking different type of data. 5 | 6 | * Class name: Checker 7 | * Namespace: PHPCollections 8 | 9 | Methods 10 | ------- 11 | 12 | ### isEqual 13 | 14 | bool PHPCollections\Checker::isEqual(mixed $firstValue, mixed $secondValue, string $message) 15 | 16 | Checks that two values are equals. 17 | 18 | * Visibility: **public static** 19 | 20 | #### Arguments 21 | * $value **mixed** 22 | * $message **string** 23 | 24 | #### Throws 25 | * **\InvalidArgumentException** 26 | 27 | ### isObject 28 | 29 | bool PHPCollections\Checker::isObject(mixed $value, string $message) 30 | 31 | Checks that a value is and object if not throws an exception. 32 | 33 | * Visibility: **public static** 34 | 35 | #### Arguments 36 | * $value **mixed** 37 | * $message **string** 38 | 39 | #### Throws 40 | * **\InvalidArgumentException** 41 | 42 | ### objectIsOfType 43 | 44 | bool PHPCollections\Checker::objectIsOfType(object $object, string $type, string $message) 45 | 46 | Checks that an object is of the desired type, if not throws an exception. 47 | 48 | * Visibility: **public static** 49 | 50 | #### Arguments 51 | * $object **object** 52 | * $type **string** 53 | * $message **string** 54 | 55 | #### Throws 56 | * **\InvalidArgumentException** 57 | 58 | ### valueIsOfType 59 | 60 | bool PHPCollections\Checker::valueIsOfType(mixed $value, mixed $valueType, string $message) 61 | 62 | Checks that a Dictionary key or value is of the desire type, if not throws an exception. 63 | 64 | * Visibility: **public static** 65 | 66 | #### Arguments 67 | * $value **mixed** 68 | * $valueType **mixed** 69 | * $message **string** 70 | 71 | #### Throws 72 | * **\InvalidArgumentException** 73 | -------------------------------------------------------------------------------- /docs/PHPCollections-Collections-ArrayList.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Collections\ArrayList 2 | =============== 3 | 4 | A list of values of any type. 5 | 6 | * Class name: ArrayList 7 | * Namespace: PHPCollections\Collections 8 | * This class implements: CollectionInterface, IterableInterface, MergeableInterface, SortableInterface 9 | 10 | Methods 11 | ------- 12 | 13 | ### add 14 | 15 | void PHPCollections\Collections\ArrayList::add(mixed $value) 16 | 17 | Adds a new element to the collection. 18 | 19 | * Visibility: **public** 20 | 21 | #### Arguments 22 | * $value **mixed** 23 | 24 | ### diff 25 | 26 | ArrayList PHPCollections\Collections\ArrayList::diff(ArrayList $newArrayList) 27 | 28 | Gets the difference between two ArrayList. 29 | 30 | * Visibility: **public** 31 | 32 | #### Arguments 33 | * $newArrayList **\PHPCollections\Collections\ArrayList** 34 | 35 | #### Throws 36 | * **\PHPCollections\Exceptions\InvalidOperationException** 37 | 38 | ### equals 39 | 40 | boolean PHPCollections\Collections\ArrayList::equals(ArrayList $collection) 41 | 42 | Determines if two ArrayList objects are equal. 43 | 44 | * Visibility: **public** 45 | 46 | #### Arguments 47 | * $collection **\PHPCollections\Collections\ArrayList** 48 | 49 | #### Throws 50 | * **\PHPCollections\Exceptions\InvalidOperationException** 51 | 52 | ### filter 53 | 54 | ?ArrayList PHPCollections\Collections\ArrayList::filter(callable $callback) 55 | 56 | Returns all the coincidences found 57 | for the given callback or null. 58 | 59 | * Visibility: **public** 60 | 61 | #### Arguments 62 | * $callback **callable** 63 | 64 | ### forEach 65 | 66 | void PHPCollections\Collections\ArrayList::forEach(callable $callback) 67 | 68 | Iterates over every element of the collection. 69 | 70 | * Visibility: **public** 71 | 72 | #### Arguments 73 | * $callback **callable** 74 | 75 | ### get 76 | 77 | mixed PHPCollections\Collections\ArrayList::get(integer $offset) 78 | 79 | Gets the element specified 80 | at the given index. 81 | 82 | * Visibility: **public** 83 | 84 | #### Arguments 85 | * $offset **integer** 86 | 87 | ### map 88 | 89 | ?ArrayList PHPCollections\Collections\ArrayList::map(callable $callback) 90 | 91 | Updates elements in the collection by 92 | applying a given callback function. 93 | 94 | * Visibility: **public** 95 | 96 | #### Arguments 97 | * $callback **callable** 98 | 99 | ### merge 100 | 101 | ArrayList PHPCollections\Collections\ArrayList::merge(ArrayList $newArrayList) 102 | 103 | Merges two ArrayList into a new one. 104 | 105 | * Visibility: **public** 106 | 107 | #### Arguments 108 | * $newArrayList **\PHPCollections\Collections\ArrayList** 109 | 110 | ### rand 111 | 112 | mixed PHPCollections\Collections\ArrayList::rand() 113 | 114 | Returns a random element of 115 | the collection. 116 | 117 | * Visibility: **public** 118 | 119 | #### Throws 120 | * **\PHPCollections\Exceptions\InvalidOperationException** 121 | 122 | ### remove 123 | 124 | void PHPCollections\Collections\ArrayList::remove(integer $offset) 125 | 126 | Removes an item from the collection 127 | and repopulates the data array. 128 | 129 | * Visibility: **public** 130 | 131 | #### Arguments 132 | * $offset **integer** 133 | 134 | #### Throws 135 | * **\OutOfRangeException** 136 | 137 | ### reverse 138 | 139 | ArrayList PHPCollections\Collections\ArrayList::reverse() 140 | 141 | Returns a new collection with the 142 | reversed values. 143 | 144 | * Visibility: **public** 145 | 146 | #### Throws 147 | * **\PHPCollections\Exceptions\InvalidOperationException** 148 | 149 | ### slice 150 | 151 | ?ArrayList PHPCollections\Collections\ArrayList::slice(int $offset, ?int $length = null) 152 | 153 | Returns a portion of the ArrayList. 154 | 155 | * Visibility: **public** 156 | 157 | #### Arguments 158 | * $offset **int** 159 | * $length **int** 160 | 161 | ### sort 162 | 163 | ?ArrayList PHPCollections\Collections\ArrayList::sort(callable $callback) 164 | 165 | Returns a new ArrayList with the values ordered by a given callback if couldn't sort returns null. 166 | 167 | * Visibility: **public** 168 | 169 | #### Arguments 170 | * $callback **callable** 171 | 172 | ### update 173 | 174 | bool PHPCollections\Collections\ArrayList::update(integer $index, mixed $value) 175 | 176 | Updates the value of the element 177 | at the given index. 178 | 179 | * Visibility: **public** 180 | 181 | #### Arguments 182 | * $index **integer** 183 | * $value **mixed** 184 | -------------------------------------------------------------------------------- /docs/PHPCollections-Collections-BaseCollection.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Collections\BaseCollection 2 | =============== 3 | 4 | The base class for countable and 5 | JSON serializable collections. 6 | 7 | * Class name: BaseCollection 8 | * Namespace: PHPCollections\Collections 9 | * This is an **abstract** class 10 | * This class implements: Countable, JsonSerializable 11 | 12 | Properties 13 | ---------- 14 | 15 | ### $dataHolder 16 | 17 | protected \PHPCollections\DataHolder $dataHolder 18 | 19 | The data container. 20 | 21 | * Visibility: **protected** 22 | 23 | Methods 24 | ------- 25 | 26 | ### __construct 27 | 28 | void PHPCollections\Collections\BaseCollection::__construct(array $data) 29 | 30 | Initializes the dataHolder property. 31 | 32 | * Visibility: **public** 33 | 34 | #### Arguments 35 | * $data **array** 36 | 37 | ### clear 38 | 39 | void PHPCollections\Collections\BaseCollection::clear() 40 | 41 | Reinitializes the dataHolder property. 42 | 43 | * Visibility: **public** 44 | 45 | ### contains 46 | 47 | boolean PHPCollections\Collections\ArrayList::contains(mixed $needle) 48 | 49 | Checks if the collection 50 | contains a given value. 51 | 52 | * Visibility: **public** 53 | 54 | #### Arguments 55 | * $needle **mixed** 56 | 57 | ### count 58 | 59 | integer PHPCollections\Collections\BaseCollection::count() 60 | 61 | Returns the length of the collection. 62 | 63 | * Visibility: **public** 64 | 65 | ### diff 66 | 67 | Basecollection PHPCollections\Collections\BaseCollection::diff(Basecollection $collection) 68 | 69 | Gets the difference between two collections. 70 | 71 | * Visibility: **public abstract** 72 | 73 | #### Arguments 74 | * $collection **\PHPCollections\Collections\BaseCollection** 75 | 76 | ### exists 77 | 78 | boolean PHPCollections\Collections\BaseCollection::exists(mixed $offset) 79 | 80 | Checks if the given index 81 | exists in the collection. 82 | 83 | * Visibility: **public** 84 | 85 | ### equals 86 | 87 | boolean PHPCollections\Collections\BaseCollection::equals(BaseCollection $collection) 88 | 89 | Determines if two collections are equal. 90 | 91 | * Visibility: **public abstract** 92 | 93 | #### Arguments 94 | * $collection **\PHPCollections\Collections\BaseCollection** 95 | 96 | ### fill 97 | 98 | void PHPCollections\Collections\BaseCollection::fill() 99 | 100 | Fills the collection with a set of data. 101 | 102 | * Visibility: **public** 103 | 104 | ### first 105 | 106 | mixed PHPCollections\Collections\BaseCollection::first() 107 | 108 | Gets the first element in the collection. 109 | 110 | * Visibility: **public** 111 | 112 | #### Throws 113 | **\OutOfRangeException** 114 | 115 | ### isEmpty 116 | 117 | boolean PHPCollections\Collections\BaseCollection::isEmpty() 118 | 119 | Checks if the collection is empty. 120 | 121 | * Visibility: **public** 122 | 123 | #### Throws 124 | **\OutOfRangeException** 125 | 126 | ### jsonSerialize 127 | 128 | array PHPCollections\Collections\BaseCollection::jsonSerialize() 129 | 130 | Defines the behavior of the collection 131 | when json_encode is called. 132 | 133 | * Visibility: **public** 134 | 135 | ### last 136 | 137 | mixed PHPCollections\Collections\BaseCollection::last() 138 | 139 | Gets the last element in the collection. 140 | 141 | * Visibility: **public** 142 | 143 | ### toArray 144 | 145 | array PHPCollections\Collections\BaseCollection::toArray() 146 | 147 | Returns a plain array with 148 | your dictionary data. 149 | 150 | * Visibility: **public** 151 | 152 | ### slice 153 | 154 | ?BaseCollection PHPCollections\Collections\BaseCollection::slice(int $offset, ?int $length = null) 155 | 156 | Returns a portion of the collection. 157 | 158 | * Visibility: **public abstract** 159 | 160 | #### Arguments 161 | * $offset **int** 162 | * $length **int** 163 | 164 | ### sum 165 | 166 | float PHPCollections\Collections\BaseCollection::sum(callable $callback) 167 | 168 | Returns the sum of a set of values. 169 | 170 | * Visibility: **public** 171 | 172 | #### Arguments 173 | * $callback **callable** 174 | 175 | #### Throws 176 | **\OutOfRangeException** -------------------------------------------------------------------------------- /docs/PHPCollections-Collections-Dictionary.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Collections\Dictionary 2 | =============== 3 | 4 | A Pair object collection 5 | represented by a generic 6 | type key and value. 7 | 8 | * Class name: Dictionary 9 | * Namespace: PHPCollections\Collections 10 | * This class extends: BaseCollection 11 | * This class implements: DictionaryInterface, MergeableInterface, SortableInterface 12 | 13 | Properties 14 | ---------- 15 | 16 | ### $keyType 17 | 18 | private mixed $keyType 19 | 20 | The type of the keys 21 | for this dictionary. 22 | 23 | * Visibility: **private** 24 | 25 | ### $valueType 26 | 27 | private mixed $valueType 28 | 29 | The type of the values 30 | for this dictionary. 31 | 32 | * Visibility: **private** 33 | 34 | Methods 35 | ------- 36 | 37 | ### __construct 38 | 39 | void PHPCollections\Collections\Dictionary::__construct(mixed $keyType, mixed $valueType, array $data = []) 40 | 41 | Creates a new Dictionary. 42 | 43 | * Visibility: **public** 44 | 45 | #### Arguments 46 | * $keyType **mixed** 47 | * $valueType **mixed** 48 | * $data **array** 49 | 50 | #### Throws 51 | * **\InvalidArgumentException** 52 | 53 | ### add 54 | 55 | void PHPCollections\Collections\Dictionary::add(mixed $key, mixed $value) 56 | 57 | Adds a new value to the dictionary. 58 | 59 | * Visibility: **public** 60 | 61 | #### Arguments 62 | * $key **mixed** 63 | * $value **mixed** 64 | 65 | #### Throws 66 | * **\InvalidArgumentException** 67 | 68 | ### diff 69 | 70 | Dictionary PHPCollections\Collections\Dictionary::diff(Dictionary $newDictionary) 71 | 72 | Gets the difference between two Dictionary. 73 | 74 | * Visibility: **public** 75 | 76 | #### Arguments 77 | * $newDictionary **\PHPCollections\Collections\Dictionary** 78 | 79 | #### Throws 80 | * **\PHPCollections\Exceptions\InvalidOperationException** 81 | 82 | ### equals 83 | 84 | boolean PHPCollections\Collections\Dictionary::equals(Dictionary $collection) 85 | 86 | Determines if two Dictionary objects are equal. 87 | 88 | * Visibility: **public** 89 | 90 | #### Arguments 91 | * $collection **\PHPCollections\Collections\Dictionary** 92 | 93 | #### Throws 94 | * **\PHPCollections\Exceptions\InvalidOperationException** 95 | 96 | ### filter 97 | 98 | ?Dictionary PHPCollections\Collections\Dictionary::filter(callable $callback) 99 | 100 | Filters the collection applying 101 | a given callback. 102 | 103 | * Visibility: **public** 104 | 105 | #### Arguments 106 | * $callback **callable** 107 | 108 | ### forEach 109 | 110 | void PHPCollections\Collections\Dictionary::forEach(callable $callback) 111 | 112 | Iterates over every element of the collection. 113 | 114 | * Visibility: **public** 115 | 116 | #### Arguments 117 | * $callback **callable** 118 | 119 | ### get 120 | 121 | ?mixed PHPCollections\Collections\Dictionary::get(mixed $key) 122 | 123 | Returns the value for the specified 124 | key or null if it's not defined. 125 | 126 | * Visibility: **public** 127 | 128 | #### Arguments 129 | * $key **mixed** 130 | 131 | ### getKeyType 132 | 133 | mixed PHPCollections\Collections\Dictionary::getKeyType() 134 | 135 | Returns the key type for this collection. 136 | 137 | * Visibility: **public** 138 | 139 | ### getValueType 140 | 141 | mixed PHPCollections\Collections\Dictionary::getValueType() 142 | 143 | Returns the key value for this collection. 144 | 145 | * Visibility: **public** 146 | 147 | ### initializePairs 148 | 149 | void PHPCollections\Collections\Dictionary::initializePairs(array $data) 150 | 151 | Populates the container with Pair objects. 152 | 153 | * Visibility: **private** 154 | 155 | #### Arguments 156 | * $data **array** 157 | 158 | ### map 159 | 160 | ?Dictionary PHPCollections\Collections\Dictionary::map(callable $callback) 161 | 162 | Updates elements in the collection by 163 | applying a given callback function. 164 | 165 | * Visibility: **public** 166 | 167 | #### Arguments 168 | * $callback **callable** 169 | 170 | ### merge 171 | 172 | Dictionary PHPCollections\Collections\Dictionary::merge(Dictionary $newDictionary) 173 | 174 | Merges two dictionaries into a new one. 175 | 176 | * Visibility: **public** 177 | 178 | #### Arguments 179 | * $newDictionary **PHPCollections\Collections\Dictionary** 180 | 181 | #### Throws 182 | * **\InvalidArgumentException** 183 | 184 | ### remove 185 | 186 | boolean PHPCollections\Collections\Dictionary::remove(mixed key) 187 | 188 | Removes a value from the dictionary. 189 | 190 | * Visibility: **public** 191 | 192 | #### Arguments 193 | * $key **mixed** 194 | 195 | ### slice 196 | 197 | ?Dictionary PHPCollections\Collections\Dictionary::slice(int $offset, ?int $length = null) 198 | 199 | Returns a portion of the Dictionary. 200 | 201 | * Visibility: **public** 202 | 203 | #### Arguments 204 | * $offset **int** 205 | * $length **int** 206 | 207 | ### sort 208 | 209 | ?Dictionary PHPCollections\Collections\Dictionary::sort(callable $callback) 210 | 211 | Returns a new Dictionary with the values ordered by a given callback if couldn't sort returns null. 212 | 213 | * Visibility: **public** 214 | 215 | #### Arguments 216 | * $callback **callable** 217 | 218 | ### toArray 219 | 220 | array PHPCollections\Collections\Dictionary::toArray() 221 | 222 | Returns an array representation 223 | of your dictionary data. 224 | 225 | * Visibility: **public** 226 | 227 | ### toJson 228 | 229 | string PHPCollections\Collections\Dictionary::toJson() 230 | 231 | Returns a JSON representation 232 | of your dictionary data. 233 | 234 | * Visibility: **public** 235 | 236 | #### Arguments 237 | * $key **mixed** 238 | * $value **mixed** 239 | 240 | ### update 241 | 242 | boolean PHPCollections\Collections\Dictionary::update(mixed $key, mixed $value) 243 | 244 | Updates the value of one Pair 245 | in the collection. 246 | 247 | * Visibility: **public** 248 | 249 | #### Arguments 250 | * $key **mixed** 251 | * $value **mixed** 252 | 253 | #### Throws 254 | * **\InvalidArgumentException** 255 | * **\PHPCollections\Exceptions\InvalidOperationException** 256 | 257 | ### validateEntry 258 | 259 | boolean PHPCollections\Collections\Dictionary::validateEntry(mixed $key, mixed $value) 260 | 261 | Validates that a key and value are of the specified types in the class. 262 | 263 | * Visibility: **private** 264 | 265 | #### Arguments 266 | * $key **mixed** 267 | * $value **mixed** 268 | 269 | #### Throws 270 | * **\InvalidArgumentException** -------------------------------------------------------------------------------- /docs/PHPCollections-Collections-GenericList.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Collections\GenericList 2 | =============== 3 | 4 | A list for a generic type of data. 5 | 6 | * Class name: GenericList 7 | * Namespace: PHPCollections\Collections 8 | * This class extends: BaseCollection 9 | * This class implements: ObjectCollectionInterface, IterableInterface, MergeableInterface,SortableInterface 10 | 11 | Properties 12 | ---------- 13 | 14 | ### $error 15 | 16 | private string $error 17 | 18 | The error message to show when someone try to store a value of a different type than the specified in the type property. 19 | 20 | * Visibility: **private** 21 | 22 | ### $type 23 | 24 | private string $type 25 | 26 | The type of data that 27 | will be stored. 28 | 29 | * Visibility: **private** 30 | 31 | Methods 32 | ------- 33 | 34 | ### __construct 35 | 36 | void PHPCollections\Collections\GenericList::__construct(string $type, object ...$data) 37 | 38 | Creates a new GenericList. 39 | 40 | * Visibility: **public** 41 | 42 | #### Arguments 43 | * $type **string** 44 | * $data **object ...** 45 | 46 | #### Throws 47 | * **\InvalidArgumentException** 48 | 49 | ### add 50 | 51 | void PHPCollections\Collections\GenericList::add(mixed $value) 52 | 53 | Adds a new object to the collection. 54 | 55 | * Visibility: **public** 56 | 57 | #### Arguments 58 | * $value **mixed** 59 | 60 | #### Throws 61 | * **\InvalidArgumentException** 62 | 63 | ### diff 64 | 65 | GenericList PHPCollections\Collections\GenericList::diff(GenericList $newGenericList) 66 | 67 | Gets the difference between two GenericList. 68 | 69 | * Visibility: **public** 70 | 71 | #### Arguments 72 | * $newGenericList **\PHPCollections\Collections\GenericList** 73 | 74 | #### Throws 75 | * **\PHPCollections\Exceptions\InvalidOperationException** 76 | 77 | ### equals 78 | 79 | boolean PHPCollections\Collections\GenericList::equals(GenericList $collection) 80 | 81 | Determines if two GenericList objects are equal. 82 | 83 | * Visibility: **public** 84 | 85 | #### Arguments 86 | * $collection **\PHPCollections\Collections\GenericList** 87 | 88 | #### Throws 89 | * **\PHPCollections\Exceptions\InvalidOperationException** 90 | 91 | ### filter 92 | 93 | ?GenericList PHPCollections\Collections\GenericList::filter(callable $callback) 94 | 95 | Returns all the coincidences found 96 | for the given callback or null. 97 | 98 | * Visibility: **public** 99 | 100 | #### Arguments 101 | * $callback **callable** 102 | 103 | ### forEach 104 | 105 | void PHPCollections\Collections\GenericList::forEach(callable $callback) 106 | 107 | Iterates over every element of the collection. 108 | 109 | * Visibility: **public** 110 | 111 | #### Arguments 112 | * $callback **callable** 113 | 114 | ### get 115 | 116 | ?object PHPCollections\Collections\GenericList::get(int $offset) 117 | 118 | Returns the object at the specified index 119 | or null if it's not defined. 120 | 121 | * Visibility: **public** 122 | 123 | #### Arguments 124 | * $offset **int** 125 | 126 | #### Throws 127 | * **\OutOfRangeException** 128 | 129 | ### map 130 | 131 | ?GenericList PHPCollections\Collections\GenericList::map(callable $callback) 132 | 133 | Updates elements in the collection by 134 | applying a given callback function. 135 | 136 | * Visibility: **public** 137 | 138 | #### Arguments 139 | * $callback **callable** 140 | 141 | ### merge 142 | 143 | GenericList PHPCollections\Collections\GenericList::merge(GenericList $newGenericList) 144 | 145 | Merges two GenericList into a new one. 146 | 147 | * Visibility: **public** 148 | 149 | #### Arguments 150 | * $data **\PHPCollections\Collections\GenericList** 151 | 152 | #### Throws 153 | * **\InvalidArgumentException** 154 | 155 | ### rand 156 | 157 | mixed PHPCollections\Collections\GenericList::rand() 158 | 159 | Returns a random element from 160 | the collection. 161 | 162 | * Visibility: **public** 163 | 164 | ### remove 165 | 166 | bool PHPCollections\Collections\GenericList::remove(int $offset) 167 | 168 | Removes an item from the collection 169 | and repopulate the data container. 170 | 171 | * Visibility: **public** 172 | 173 | #### Arguments 174 | * $offset **int** 175 | 176 | #### Throws 177 | * **\OutOfRangeException** 178 | 179 | ### repopulate 180 | 181 | void PHPCollections\Collections\GenericList::repopulate() 182 | 183 | Repopulates the data container. 184 | 185 | * Visibility: **private** 186 | 187 | ### reverse 188 | 189 | GenericList PHPCollections\Collections\GenericList::reverse() 190 | 191 | Returns a new collection with the 192 | reversed values. 193 | 194 | * Visibility: **public** 195 | 196 | #### Throws 197 | * **\PHPCollections\Exceptions\InvalidOperationException** 198 | 199 | ### slice 200 | 201 | ?GenericList PHPCollections\Collections\GenericList::slice(int $offset, ?int $length = null) 202 | 203 | Returns a portion of the GenericList. 204 | 205 | * Visibility: **public** 206 | 207 | #### Arguments 208 | * $offset **int** 209 | * $length **int** 210 | 211 | ### sort 212 | 213 | ?GenericList PHPCollections\Collections\GenericList::sort(callable $callback) 214 | 215 | Returns a new GenericList with the values ordered by a given callback if couldn't sort returns null. 216 | 217 | * Visibility: **public** 218 | 219 | #### Arguments 220 | * $callback **callable** 221 | 222 | ### update 223 | 224 | bool PHPCollections\Collections\GenericList::update(integer $index, mixed $value) 225 | 226 | Updates the value of the element 227 | at the given index. 228 | 229 | * Visibility: **public** 230 | 231 | #### Arguments 232 | * $index **integer** 233 | * $value **mixed** 234 | 235 | #### Throws 236 | * **\PHPCollections\Exceptions\InvalidOperationException** 237 | * **\InvalidArgumentException** 238 | -------------------------------------------------------------------------------- /docs/PHPCollections-Collections-Pair.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Collections\Pair 2 | =============== 3 | 4 | A simple key / value pair 5 | object representation. 6 | 7 | * Class name: Pair 8 | * Namespace: PHPCollections\Collections 9 | 10 | Properties 11 | ---------- 12 | 13 | ### $key 14 | 15 | private mixed $key 16 | 17 | The key for the Pair object. 18 | 19 | * Visibility: **private** 20 | 21 | ### $value 22 | 23 | private mixed $value 24 | 25 | The value for the Pair object. 26 | 27 | * Visibility: **private** 28 | 29 | Methods 30 | ------- 31 | 32 | ### __construct 33 | 34 | void PHPCollections\Collections\Pair::__construct(mixed $key, mixed $value) 35 | 36 | Initializes class properties. 37 | 38 | * Visibility: **public** 39 | 40 | #### Arguments 41 | * $key **mixed** 42 | * $value **mixed** 43 | 44 | ### __get 45 | 46 | mixed PHPCollections\Collections\Pair::__get(string $name) 47 | 48 | Allows access to the key 49 | property by its value. 50 | 51 | * Visibility: **public** 52 | 53 | #### Arguments 54 | * $name **string** 55 | 56 | ### getKey 57 | 58 | mixed PHPCollections\Collections\Pair::getKey() 59 | 60 | Returns the key property. 61 | 62 | * Visibility: **public** 63 | 64 | ### getValue 65 | 66 | mixed PHPCollections\Collections\Pair::getValue() 67 | 68 | Returns the value property. 69 | 70 | * Visibility: **public** 71 | 72 | ### setValue 73 | 74 | void PHPCollections\Collections\Pair::setValue(mixed $value) 75 | 76 | Sets the value of the value property. 77 | 78 | * Visibility: **public** 79 | 80 | #### Arguments 81 | * $value **mixed** 82 | -------------------------------------------------------------------------------- /docs/PHPCollections-Collections-Stack.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Collections\Stack 2 | =============== 3 | 4 | A generic LIFO Stack. 5 | 6 | * Class name: Stack 7 | * Namespace: PHPCollections\Collections 8 | * This class implements: Countable 9 | 10 | Properties 11 | ---------- 12 | 13 | ### $data 14 | 15 | private array $data 16 | 17 | The data container. 18 | 19 | * Visibility: **private** 20 | 21 | ### $type 22 | 23 | private mixed $type 24 | 25 | The type of the values 26 | for this Stack. 27 | 28 | * Visibility: **private** 29 | 30 | Methods 31 | ------- 32 | 33 | ### __construct 34 | 35 | void PHPCollections\Collections\Stack::__construct(string $type) 36 | 37 | Creates a new Stack. 38 | 39 | * Visibility: **public** 40 | 41 | #### Arguments 42 | * $type **string** 43 | 44 | ### clear 45 | 46 | void PHPCollections\Collections\Stack::clear() 47 | 48 | Clears the data values. 49 | 50 | * Visibility: **public** 51 | 52 | ### count 53 | 54 | int PHPCollections\Collections\Stack::count() 55 | 56 | Returns the length of the Stack. 57 | 58 | * Visibility: **public** 59 | 60 | ### isEmpty 61 | 62 | bool PHPCollections\Collections\Stack::isEmpty() 63 | 64 | Checks if the stack is empty. 65 | 66 | * Visibility: **public** 67 | 68 | ### peek 69 | 70 | mixed PHPCollections\Collections\Stack::peek() 71 | 72 | Gets the element at 73 | the end of the Stack. 74 | 75 | * Visibility: **public** 76 | 77 | ### pop 78 | 79 | mixed PHPCollections\Collections\Stack::pop() 80 | 81 | Pops the element at 82 | the end of the stack. 83 | 84 | * Visibility: **public** 85 | 86 | ### push 87 | 88 | mixed PHPCollections\Collections\Stack::push(mixed $value) 89 | 90 | Adds a new element at 91 | the end of the Stack. 92 | 93 | * Visibility: **public** 94 | 95 | #### Arguments 96 | * $value **mixed** 97 | 98 | #### Throws 99 | * **\InvalidArgumentException** 100 | -------------------------------------------------------------------------------- /docs/PHPCollections-DataHolder.md: -------------------------------------------------------------------------------- 1 | PHPCollections\DataHolder 2 | =============== 3 | 4 | A class for storing and managing data. 5 | 6 | * Class name: DataHolder 7 | * Namespace: PHPCollections 8 | * This class implements: ArrayAccess, IteratorAggregate 9 | 10 | Properties 11 | ---------- 12 | 13 | ### $container 14 | 15 | private array $container 16 | 17 | The array for storing data. 18 | 19 | * Visibility: **private** 20 | 21 | Methods 22 | ------- 23 | 24 | ### __construct 25 | 26 | void PHPCollections\DataHolder::__construct(array $data) 27 | 28 | Initializes the container property. 29 | 30 | * Visibility: **public** 31 | 32 | #### Arguments 33 | * $data **array** 34 | 35 | ### getContainer 36 | 37 | array PHPCollections\DataHolder::getContainer() 38 | 39 | Returns the container array. 40 | 41 | * Visibility: **public** 42 | 43 | ### getIterator 44 | 45 | \ArrayIterator PHPCollections\DataHolder::getIterator() 46 | 47 | Returns an array iterator for 48 | the container property. 49 | 50 | * Visibility: **public** 51 | 52 | ### offsetExists 53 | 54 | boolean PHPCollections\DataHolder::offsetExists(mixed $offset) 55 | 56 | Checks if an offset exists in the container. 57 | 58 | * Visibility: **public** 59 | 60 | #### Arguments 61 | * $offset **mixed** 62 | 63 | ### offsetGet 64 | 65 | ?mixed PHPCollections\DataHolder::offsetGet(mixed $offset) 66 | 67 | Gets a value from the container. 68 | 69 | * Visibility: **public** 70 | 71 | #### Arguments 72 | * $offset **mixed** 73 | 74 | ### offsetSet 75 | 76 | void PHPCollections\DataHolder::offsetSet(mixed $offset, mixed $value) 77 | 78 | Sets a value into the container. 79 | 80 | * Visibility: **public** 81 | 82 | #### Arguments 83 | * $offset **mixed** 84 | * $value **mixed** 85 | 86 | ### offsetUnset 87 | 88 | void PHPCollections\DataHolder::offsetUnset(mixed $offset) 89 | 90 | Unsets an offset from the container. 91 | 92 | * Visibility: **public** 93 | 94 | #### Arguments 95 | * $offset **mixed** 96 | 97 | ### setContainer 98 | 99 | void PHPCollections\DataHolder::setContainer(array $data) 100 | 101 | Sets the container array. 102 | 103 | * Visibility: **public** 104 | 105 | #### Arguments 106 | * $data **array** 107 | -------------------------------------------------------------------------------- /docs/PHPCollections-Exceptions-InvalidOperationException.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Exceptions\InvalidOperationException 2 | =============== 3 | 4 | An Exception for representing 5 | invalid operations with collections. 6 | 7 | * Class name: InvalidOperationException 8 | * Namespace: PHPCollections\Exceptions 9 | * Parent class: Exception 10 | 11 | Methods 12 | ------- 13 | 14 | ### __toString 15 | 16 | string PHPCollections\Exceptions\InvalidOperationException::__toString() 17 | 18 | Returns the string representation 19 | of the Exception. 20 | 21 | * Visibility: **public** 22 | -------------------------------------------------------------------------------- /docs/PHPCollections-Interfaces-CollectionInterface.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Interfaces\CollectionInterface 2 | =============== 3 | 4 | * Interface name: CollectionInterface 5 | * Namespace: PHPCollections\Interfaces 6 | * This is an **interface** 7 | 8 | Methods 9 | ------- 10 | 11 | ### add 12 | 13 | void PHPCollections\Interfaces\CollectionInterface::add(mixed $value) 14 | 15 | * Visibility: **public** 16 | 17 | #### Arguments 18 | * $value **mixed** 19 | 20 | 21 | 22 | ### get 23 | 24 | mixed PHPCollections\Interfaces\CollectionInterface::get(int $offset) 25 | 26 | * Visibility: **public** 27 | 28 | #### Arguments 29 | * $offset **int** 30 | 31 | ### remove 32 | 33 | void PHPCollections\Interfaces\CollectionInterface::remove(int $offset) 34 | 35 | * Visibility: **public** 36 | 37 | #### Arguments 38 | * $offset **int** 39 | 40 | ### update 41 | 42 | bool PHPCollections\Interfaces\CollectionInterface::update(int $offset, mixed $value) 43 | 44 | * Visibility: **public** 45 | 46 | #### Arguments 47 | * $offset **int** 48 | * $value **mixed** 49 | -------------------------------------------------------------------------------- /docs/PHPCollections-Interfaces-DictionaryInterface.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Interfaces\DictionaryInterface 2 | =============== 3 | 4 | * Interface name: DictionaryInterface 5 | * Namespace: PHPCollections\Interfaces 6 | * This is an **interface** 7 | 8 | Methods 9 | ------- 10 | 11 | ### add 12 | 13 | void PHPCollections\Interfaces\DictionaryInterface::add($key, $value) 14 | 15 | * Visibility: **public** 16 | 17 | #### Arguments 18 | * $key **mixed** 19 | * $value **mixed** 20 | 21 | ### get 22 | 23 | mixed PHPCollections\Interfaces\DictionaryInterface::get($key) 24 | 25 | * Visibility: **public** 26 | 27 | #### Arguments 28 | * $key **mixed** 29 | 30 | ### remove 31 | 32 | bool PHPCollections\Interfaces\DictionaryInterface::remove($key) 33 | 34 | * Visibility: **public** 35 | 36 | #### Arguments 37 | * $key **mixed** 38 | 39 | ### update 40 | 41 | bool PHPCollections\Interfaces\DictionaryInterface::update($key, $value) 42 | 43 | * Visibility: **public** 44 | 45 | #### Arguments 46 | * $key **mixed** 47 | * $value **mixed** 48 | -------------------------------------------------------------------------------- /docs/PHPCollections-Interfaces-MergeableInterface.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Interfaces\MergeableInterface 2 | =============== 3 | 4 | * Interface name: MergeableInterface 5 | * Namespace: PHPCollections\Interfaces 6 | * This is an **interface** 7 | 8 | Methods 9 | ------- 10 | 11 | ### merge 12 | 13 | BaseCollection PHPCollections\Interfaces\MergeableInterface::merge(BaseCollection $collection) 14 | 15 | * Visibility: **public** 16 | 17 | #### Arguments 18 | * $collection **PHPCollections\Collections\BaseCollection** 19 | -------------------------------------------------------------------------------- /docs/PHPCollections-Interfaces-ObjectCollectionInterface.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Interfaces\ObjectCollectionInterface 2 | =============== 3 | 4 | * Interface name: ObjectCollectionInterface 5 | * Namespace: PHPCollections\Interfaces 6 | * This is an **interface** 7 | 8 | Methods 9 | ------- 10 | 11 | ### add 12 | 13 | void PHPCollections\Interfaces\ObjectCollectionInterface::add(object $value) 14 | 15 | * Visibility: **public** 16 | 17 | #### Arguments 18 | * $value **object** 19 | 20 | 21 | 22 | ### get 23 | 24 | object PHPCollections\Interfaces\ObjectCollectionInterface::get(int $offset) 25 | 26 | * Visibility: **public** 27 | 28 | #### Arguments 29 | * $offset **int** 30 | 31 | ### remove 32 | 33 | void PHPCollections\Interfaces\ObjectCollectionInterface::remove(int $offset) 34 | 35 | * Visibility: **public** 36 | 37 | #### Arguments 38 | * $offset **int** 39 | 40 | ### update 41 | 42 | bool PHPCollections\Interfaces\ObjectCollectionInterface::update(int $offset, object $value) 43 | 44 | * Visibility: **public** 45 | 46 | #### Arguments 47 | * $offset **int** 48 | * $value **object** 49 | -------------------------------------------------------------------------------- /docs/PHPCollections-Interfaces-SortableInterface.md: -------------------------------------------------------------------------------- 1 | PHPCollections\Interfaces\SortableInterface 2 | =============== 3 | 4 | * Interface name: SortableInterface 5 | * Namespace: PHPCollections\Interfaces 6 | * This is an **interface** 7 | 8 | Methods 9 | ------- 10 | 11 | ### sort 12 | 13 | bool PHPCollections\Interfaces\SortableInterface::sort(callable $callback) 14 | 15 | * Visibility: **public** 16 | 17 | #### Arguments 18 | * $callback **callable** 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | Package Index 2 | ========= 3 | 4 | * PHPCollections 5 | * PHPCollections\Exceptions 6 | * [InvalidOperationException](PHPCollections-Exceptions-InvalidOperationException.md) 7 | * PHPCollections\Interfaces 8 | * [CollectionInterface](PHPCollections-Interfaces-CollectionInterface.md) 9 | * [DictionaryInterface](PHPCollections-Interfaces-DictionaryInterface.md) 10 | * [MergeableInterface](PHPCollections-Interfaces-MergeableInterface.md) 11 | * [ObjectCollectionInterface](PHPCollections-Interfaces-ObjectCollectionInterface.md) 12 | * [SortableInterface](PHPCollections-Interfaces-SortableInterface.md) 13 | * PHPCollections\Collections 14 | * [ArrayList](PHPCollections-Collections-ArrayList.md) 15 | * [BaseCollection](PHPCollections-Collections-BaseCollection.md) 16 | * [Dictionary](PHPCollections-Collections-Dictionary.md) 17 | * [GenericList](PHPCollections-Collections-GenericList.md) 18 | * [Pair](PHPCollections-Collections-Pair.md) 19 | * [Stack](PHPCollections-Collections-Stack.md) 20 | * [Checker](PHPCollections-Checker.md) 21 | * [DataHolder](PHPCollections-DataHolder.md) 22 | 23 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/Unit 14 | 15 | 16 | 17 | 18 | ./src 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Checker.php: -------------------------------------------------------------------------------- 1 | toArray(); 29 | 30 | array_push($data, $value); 31 | $this->dataHolder->setContainer($data); 32 | } 33 | 34 | /** 35 | * Gets the difference between two ArrayList. 36 | * 37 | * @param \PHPCollections\Collections\ArrayList $newArrayList 38 | * 39 | * @throws \PHPCollections\Exceptions\InvalidOperationException 40 | * 41 | * @return \PHPCollections\Collections\ArrayList 42 | */ 43 | public function diff(BaseCollection $newArrayList): BaseCollection 44 | { 45 | if (!$newArrayList instanceof self) { 46 | throw new InvalidOperationException('You should only compare an ArrayList against another ArrayList'); 47 | } 48 | 49 | $diffValues = array_udiff($this->toArray(), $newArrayList->toArray(), function ($firstValue, $secondValue) { 50 | if (gettype($firstValue) !== gettype($secondValue)) { 51 | return -1; 52 | } 53 | 54 | return $firstValue <=> $secondValue; 55 | }); 56 | 57 | return new self($diffValues); 58 | } 59 | 60 | /** 61 | * Determines if two ArrayList objects are equal. 62 | * 63 | * @param \PHPCollections\Collections\ArrayList $newArrayList 64 | * 65 | * @return \PHPCollections\Collections\ArrayList 66 | */ 67 | public function equals(BaseCollection $newArrayList): bool 68 | { 69 | if (!$newArrayList instanceof self) { 70 | throw new InvalidOperationException('You should only compare an ArrayList against another ArrayList'); 71 | } 72 | 73 | return $this->toArray() == $newArrayList->toArray(); 74 | } 75 | 76 | /** 77 | * Returns all the coincidences found 78 | * for the given callback or null. 79 | * 80 | * @param callable $callback 81 | * 82 | * @return \PHPCollections\Collections\ArrayList|null 83 | */ 84 | public function filter(callable $callback): ?self 85 | { 86 | $matcheds = []; 87 | 88 | foreach ($this->dataHolder as $value) { 89 | if (call_user_func($callback, $value) === true) { 90 | $matcheds[] = $value; 91 | } 92 | } 93 | 94 | return count($matcheds) > 0 ? new $this(array_values($matcheds)) : null; 95 | } 96 | 97 | /** 98 | * Iterates over every element of the collection. 99 | * 100 | * @param callable $callback 101 | * 102 | * @return void 103 | */ 104 | public function forEach(callable $callback): void 105 | { 106 | $data = $this->toArray(); 107 | 108 | array_walk($data, $callback); 109 | $this->dataHolder->setContainer($data); 110 | } 111 | 112 | /** 113 | * Gets the element specified 114 | * at the given index. 115 | * 116 | * @param int $offset 117 | * 118 | * @return mixed 119 | */ 120 | public function get(int $offset) 121 | { 122 | return $this->dataHolder->offsetGet($offset); 123 | } 124 | 125 | /** 126 | * Updates elements in the collection by 127 | * applying a given callback function. 128 | * 129 | * @param callable $callback 130 | * 131 | * @return \PHPCollections\Collections\ArrayList|null 132 | */ 133 | public function map(callable $callback): ?self 134 | { 135 | $matcheds = array_map($callback, $this->toArray()); 136 | 137 | return count($matcheds) > 0 ? new $this(array_values($matcheds)) : null; 138 | } 139 | 140 | /** 141 | * Merges two ArrayList into a new one. 142 | * 143 | * @param \PHPCollections\Collections\ArrayList $newArrayList 144 | * 145 | * @return \PHPCollections\Collections\ArrayList 146 | */ 147 | public function merge(BaseCollection $newArrayList): BaseCollection 148 | { 149 | return new $this(array_merge($this->toArray(), $newArrayList->toArray())); 150 | } 151 | 152 | /** 153 | * Returns a random element of 154 | * the collection. 155 | * 156 | * @throws \PHPCollections\Exceptions\InvalidOperationException 157 | * 158 | * @return mixed 159 | */ 160 | public function rand() 161 | { 162 | if ($this->isEmpty()) { 163 | throw new InvalidOperationException('You cannot get a random element from an empty collection'); 164 | } 165 | 166 | $randomIndex = array_rand($this->toArray()); 167 | 168 | return $this->get($randomIndex); 169 | } 170 | 171 | /** 172 | * Removes an item from the collection 173 | * and repopulates the data array. 174 | * 175 | * @param int $offset 176 | * 177 | * @throws \OutOfRangeException 178 | * 179 | * @return void 180 | */ 181 | public function remove(int $offset): void 182 | { 183 | if ($this->isEmpty()) { 184 | throw new OutOfRangeException('You\'re trying to remove data from an empty collection'); 185 | } 186 | 187 | if (!$this->dataHolder->offsetExists($offset)) { 188 | throw new OutOfRangeException(sprintf('The %d index does not exists for this collection', $offset)); 189 | } 190 | 191 | $this->dataHolder->offsetUnset($offset); 192 | } 193 | 194 | /** 195 | * Returns a new collection with the 196 | * reversed values. 197 | * 198 | * @throws \PHPCollections\Exceptions\InvalidOperationException 199 | * 200 | * @return \PHPCollections\Collections\ArrayList 201 | */ 202 | public function reverse(): self 203 | { 204 | if ($this->isEmpty()) { 205 | throw new InvalidOperationException('You cannot reverse an empty collection'); 206 | } 207 | 208 | return new $this(array_reverse($this->toArray())); 209 | } 210 | 211 | /** 212 | * Returns a portion of the ArrayList. 213 | * 214 | * @param int $offset 215 | * @param int|null $length 216 | * 217 | * @return \PHPCollections\Collections\ArrayList|null 218 | */ 219 | public function slice(int $offset, ?int $length = null): ?BaseCollection 220 | { 221 | $newData = array_slice($this->toArray(), $offset, $length); 222 | 223 | return count($newData) > 0 ? new self($newData) : null; 224 | } 225 | 226 | /** 227 | * Returns a new ArrayList with the 228 | * values ordered by a given callback 229 | * if couldn't sort returns null. 230 | * 231 | * @param callable $callback 232 | * 233 | * @return \PHPCollections\Collections\ArrayList|null 234 | */ 235 | public function sort(callable $callback): ?BaseCollection 236 | { 237 | $data = $this->toArray(); 238 | 239 | return usort($data, $callback) ? new $this($data) : null; 240 | } 241 | 242 | /** 243 | * Updates the value of the element 244 | * at the given index. 245 | * 246 | * @param int $index 247 | * @param mixed $value 248 | * 249 | * @return bool 250 | */ 251 | public function update(int $index, $value): bool 252 | { 253 | if (!$this->exists($index)) { 254 | throw new InvalidOperationException('You cannot update a non-existent value'); 255 | } 256 | 257 | $this->dataHolder->offsetSet($index, $value); 258 | 259 | return $this->dataHolder->offsetGet($index) === $value; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/Collections/BaseCollection.php: -------------------------------------------------------------------------------- 1 | dataHolder = new DataHolder($data); 34 | } 35 | 36 | /** 37 | * Reinitializes the dataHolder property. 38 | * 39 | * @return void 40 | */ 41 | public function clear(): void 42 | { 43 | $this->dataHolder = new DataHolder(); 44 | } 45 | 46 | /** 47 | * Checks if the collection 48 | * contains a given value. 49 | * 50 | * @param mixed $needle 51 | * 52 | * @return bool 53 | */ 54 | public function contains($needle): bool 55 | { 56 | return in_array($needle, $this->toArray()); 57 | } 58 | 59 | /** 60 | * Returns the length of the collection. 61 | * 62 | * @return int 63 | */ 64 | public function count(): int 65 | { 66 | return count($this->toArray()); 67 | } 68 | 69 | /** 70 | * Gets the difference between two collections. 71 | * 72 | * @param \PHPCollections\Collections\BaseCollection $collection 73 | * 74 | * @return \PHPCollections\Collections\BaseCollection 75 | */ 76 | abstract public function diff(self $collection): self; 77 | 78 | /** 79 | * Checks if the given index 80 | * exists in the collection. 81 | * 82 | * @param mixed $offset 83 | * 84 | * @return bool 85 | */ 86 | public function exists($offset): bool 87 | { 88 | return $this->dataHolder->offsetExists($offset); 89 | } 90 | 91 | /** 92 | * Determines if two collections are equal. 93 | * 94 | * @param \PHPCollections\Collections\BaseCollection $collection 95 | * 96 | * @return bool 97 | */ 98 | abstract public function equals(self $collection): bool; 99 | 100 | /** 101 | * Fills the collection with a set of data. 102 | * 103 | * @param array $data 104 | * 105 | * @return void 106 | */ 107 | public function fill(array $data): void 108 | { 109 | foreach ($data as $entry) { 110 | $this->add($entry); 111 | } 112 | } 113 | 114 | /** 115 | * Gets the first element in the collection. 116 | * 117 | * @throws \OutOfRangeException 118 | * 119 | * @return mixed 120 | */ 121 | public function first() 122 | { 123 | if ($this->isEmpty()) { 124 | throw new OutOfRangeException('You\'re trying to get data from an empty collection'); 125 | } 126 | 127 | return array_values($this->toArray())[0]; 128 | } 129 | 130 | /** 131 | * Checks if the collection is empty. 132 | * 133 | * @return bool 134 | */ 135 | public function isEmpty(): bool 136 | { 137 | return $this->count() === 0; 138 | } 139 | 140 | /** 141 | * Defines the behavior of the collection 142 | * when json_encode is called. 143 | * 144 | * @return array 145 | */ 146 | public function jsonSerialize(): array 147 | { 148 | return $this->toArray(); 149 | } 150 | 151 | /** 152 | * Gets the last element of the collection. 153 | * 154 | * @throws \OutOfRangeException 155 | * 156 | * @return mixed 157 | */ 158 | public function last() 159 | { 160 | if ($this->isEmpty()) { 161 | throw new OutOfRangeException('You\'re trying to get data from an empty collection'); 162 | } 163 | 164 | return array_values($this->toArray())[$this->count() - 1]; 165 | } 166 | 167 | /** 168 | * Returns a portion of the collection. 169 | * 170 | * @param int $offset 171 | * @param int|null $lenght 172 | * 173 | * @return \PHPCollections\Collections\BaseCollection 174 | */ 175 | abstract public function slice(int $offset, ?int $lenght): ?self; 176 | 177 | /** 178 | * Returns the sum of a set of values. 179 | * 180 | * @param callable $callback 181 | * 182 | * @throws \PHPCollections\Exceptions\InvalidOperationException 183 | * 184 | * @return float 185 | */ 186 | public function sum(callable $callback): float 187 | { 188 | $sum = 0; 189 | 190 | foreach ($this->dataHolder as $value) { 191 | if (!is_numeric($result = call_user_func($callback, $value))) { 192 | throw new InvalidOperationException('You cannot sum non-numeric values'); 193 | } 194 | 195 | $sum += $result; 196 | } 197 | 198 | return $sum; 199 | } 200 | 201 | /** 202 | * Returns a plain array with 203 | * your dictionary data. 204 | * 205 | * @return array 206 | */ 207 | public function toArray(): array 208 | { 209 | return $this->dataHolder->getContainer(); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/Collections/Dictionary.php: -------------------------------------------------------------------------------- 1 | keyType = $keyType; 49 | $this->valueType = $valueType; 50 | 51 | foreach ($data as $key => $value) { 52 | $this->validateEntry($key, $value); 53 | } 54 | 55 | parent::__construct($data); 56 | $this->initializePairs($data); 57 | } 58 | 59 | /** 60 | * Adds a new value to the dictionary. 61 | * 62 | * @param mixed $key 63 | * @param mixed $value 64 | * 65 | * @throws \InvalidArgumentException 66 | * 67 | * @return void 68 | */ 69 | public function add($key, $value): void 70 | { 71 | $this->validateEntry($key, $value); 72 | $this->dataHolder->offsetSet($key, new Pair($key, $value)); 73 | } 74 | 75 | /** 76 | * Gets the difference between two Dictionary. 77 | * 78 | * @param \PHPCollections\Collections\Dictionary $newDictionary 79 | * 80 | * @throws \PHPCollections\Exceptions\InvalidOperationException 81 | * 82 | * @return \PHPCollections\Collections\Dictionary 83 | */ 84 | public function diff(BaseCollection $newDictionary): BaseCollection 85 | { 86 | if (!$newDictionary instanceof self) { 87 | throw new InvalidOperationException('You should only compare a Dictionary against another Dictionary'); 88 | } 89 | 90 | if ($this->keyType !== $newDictionary->getKeyType()) { 91 | throw new InvalidOperationException(sprintf('The key type for this Dictionary is %s, you cannot pass a Dictionary with %s as key type', $this->keyType, $newDictionary->getKeyType())); 92 | } 93 | 94 | if ($this->valueType !== $newDictionary->getValueType()) { 95 | throw new InvalidOperationException(sprintf('The value type for this Dictionary is %s, you cannot pass a Dictionary with %s as value types', $this->valueType, $newDictionary->getValueType())); 96 | } 97 | 98 | $diffValues = array_udiff_uassoc($this->toArray(), $newDictionary->toArray(), function ($firstValue, $secondValue) { 99 | return $firstValue <=> $secondValue; 100 | }, function ($firstKey, $secondKey) { 101 | return $firstKey <=> $secondKey; 102 | }); 103 | 104 | return new self($this->keyType, $this->valueType, $diffValues); 105 | } 106 | 107 | /** 108 | * Determines if two Dictionary objects are equal. 109 | * 110 | * @param \PHPCollections\Collections\Dictionary $newDictionary 111 | * 112 | * @return \PHPCollections\Collections\Dictionary 113 | */ 114 | public function equals(BaseCollection $newDictionary): bool 115 | { 116 | if (!$newDictionary instanceof self) { 117 | throw new InvalidOperationException('You should only compare an Dictionary against another Dictionary'); 118 | } 119 | 120 | return $this->toArray() == $newDictionary->toArray(); 121 | } 122 | 123 | /** 124 | * Fills the dictionary with data. 125 | * 126 | * @param array $data 127 | * 128 | * @return void 129 | */ 130 | public function fill(array $data): void 131 | { 132 | foreach ($data as $key => $entry) { 133 | $this->add($key, $entry); 134 | } 135 | } 136 | 137 | /** 138 | * Filters the collection applying 139 | * a given callback. 140 | * 141 | * @param callable $callback 142 | * 143 | * @return \PHPCollections\Collections\Dictionary|null 144 | */ 145 | public function filter(callable $callback): ?self 146 | { 147 | $matcheds = []; 148 | 149 | foreach ($this->dataHolder as $key => $value) { 150 | if (call_user_func($callback, $value->getKey(), $value->getValue()) === true) { 151 | $matcheds[$value->getKey()] = $value->getValue(); 152 | } 153 | } 154 | 155 | return count($matcheds) > 0 ? new $this($this->keyType, $this->valueType, $matcheds) : null; 156 | } 157 | 158 | /** 159 | * Iterates over every element of the collection. 160 | * 161 | * @param callable $callback 162 | * 163 | * @return void 164 | */ 165 | public function forEach(callable $callback): void 166 | { 167 | $data = $this->toArray(); 168 | 169 | array_walk($data, $callback); 170 | $this->initializePairs($data); 171 | } 172 | 173 | /** 174 | * Returns the value for the specified 175 | * key or null if it's not defined. 176 | * 177 | * @param mixed $key 178 | * 179 | * @return mixed|null 180 | */ 181 | public function get($key) 182 | { 183 | return $this->dataHolder->offsetExists($key) ? 184 | $this->dataHolder->offsetGet($key)->getValue() : 185 | null; 186 | } 187 | 188 | /** 189 | * Returns the key type for this collection. 190 | * 191 | * @return mixed 192 | */ 193 | public function getKeyType() 194 | { 195 | return $this->keyType; 196 | } 197 | 198 | /** 199 | * Returns the key value for this collection. 200 | * 201 | * @return mixed 202 | */ 203 | public function getValueType() 204 | { 205 | return $this->valueType; 206 | } 207 | 208 | /** 209 | * Populates the container with Pair objects. 210 | * 211 | * @param array $data 212 | * 213 | * @return void 214 | */ 215 | private function initializePairs(array $data): void 216 | { 217 | foreach ($data as $key => $value) { 218 | $this->dataHolder[$key] = new Pair($key, $value); 219 | } 220 | } 221 | 222 | /** 223 | * Updates elements in the collection by 224 | * applying a given callback function. 225 | * 226 | * @param callable $callback 227 | * 228 | * @return \PHPCollections\Collections\Dictionary|null 229 | */ 230 | public function map(callable $callback): ?self 231 | { 232 | $matcheds = array_map($callback, $this->toArray()); 233 | 234 | return count($matcheds) > 0 ? new $this($this->keyType, $this->valueType, $this->toArray()) : null; 235 | } 236 | 237 | /** 238 | * Merges two dictionaries into a new one. 239 | * 240 | * @param \PHPCollections\Collections\Dictionary $newDictionary 241 | * 242 | * @throws \InvalidArgumentException 243 | * 244 | * @return \PHPCollections\Collections\Dictionary 245 | */ 246 | public function merge(BaseCollection $newDictionary): BaseCollection 247 | { 248 | Checker::isEqual( 249 | $newDictionary->getKeyType(), $this->getKeyType(), 250 | sprintf('The new Dictionary key should be of type %s', $this->getKeyType()) 251 | ); 252 | Checker::isEqual( 253 | $newDictionary->getValueType(), $this->getValueType(), 254 | sprintf('The new Dictionary value type should be of type %s', $this->getValueType()) 255 | ); 256 | 257 | return new $this( 258 | $this->keyType, 259 | $this->valueType, 260 | array_merge($this->toArray(), $newDictionary->toArray()) 261 | ); 262 | } 263 | 264 | /** 265 | * Removes a value from the dictionary. 266 | * 267 | * @param mixed $key 268 | * 269 | * @throws \OutOfRangeException 270 | * 271 | * @return bool 272 | */ 273 | public function remove($key): void 274 | { 275 | if ($this->isEmpty()) { 276 | throw new OutOfRangeException('You\'re trying to remove data from an empty collection'); 277 | } 278 | 279 | if (!$this->dataHolder->offsetExists($key)) { 280 | throw new OutOfRangeException(sprintf('The %s key does not exists for this collection', $key)); 281 | } 282 | 283 | $this->dataHolder->offsetUnset($key); 284 | } 285 | 286 | /** 287 | * Returns a portion of the Dictionary. 288 | * 289 | * @param int $offset 290 | * @param int|null $length 291 | * 292 | * @return \PHPCollections\Collections\Dictionary|null 293 | */ 294 | public function slice(int $offset, ?int $length = null): ?BaseCollection 295 | { 296 | $newData = array_slice($this->toArray(), $offset, $length, true); 297 | 298 | return count($newData) > 0 ? new self($this->keyType, $this->valueType, $newData) : null; 299 | } 300 | 301 | /** 302 | * Returns a new Dictionary with the 303 | * values ordered by a given callback 304 | * if couldn't sort returns null. 305 | * 306 | * @param callable $callback 307 | * 308 | * @return \PHPCollections\Collections\Dictionary|null 309 | */ 310 | public function sort(callable $callback): ?BaseCollection 311 | { 312 | $data = $this->toArray(); 313 | 314 | return uasort($data, $callback) ? new $this($this->keyType, $this->valueType, $data) : null; 315 | } 316 | 317 | /** 318 | * Returns an array representation 319 | * of your dictionary data. 320 | * 321 | * @return array 322 | */ 323 | public function toArray(): array 324 | { 325 | $array = []; 326 | 327 | foreach ($this->dataHolder as $pair) { 328 | $array[$pair->getKey()] = $pair->getValue(); 329 | } 330 | 331 | return $array; 332 | } 333 | 334 | /** 335 | * Returns a JSON representation 336 | * of your dictionary data. 337 | * 338 | * @return string 339 | */ 340 | public function toJson(): string 341 | { 342 | return json_encode($this->dataHolder); 343 | } 344 | 345 | /** 346 | * Updates the value of one Pair 347 | * in the collection. 348 | * 349 | * @param mixed $key 350 | * @param mixed $value 351 | * 352 | * @throws \InvalidArgumentException 353 | * @throws \PHPCollections\Exceptions\InvalidOperationException 354 | * 355 | * @return bool 356 | */ 357 | public function update($key, $value): bool 358 | { 359 | $this->validateEntry($key, $value); 360 | 361 | if (!$this->dataHolder->offsetExists($key)) { 362 | throw new InvalidOperationException('You cannot update a non-existent value'); 363 | } 364 | 365 | $this->dataHolder[$key]->setValue($value); 366 | 367 | return $this->dataHolder[$key]->getValue() === $value; 368 | } 369 | 370 | /** 371 | * Validates that a key and value are of the 372 | * specified types in the class. 373 | * 374 | * @param mixed $key 375 | * @param mixed $value 376 | * 377 | * @throws \InvalidArgumentException 378 | * 379 | * @return bool 380 | */ 381 | private function validateEntry($key, $value): bool 382 | { 383 | Checker::valueIsOfType( 384 | $key, $this->keyType, 385 | sprintf( 386 | 'The %s type specified for this dictionary is %s, you cannot pass %s %s', 387 | 'key', $this->keyType, getArticle(gettype($key)), gettype($key) 388 | ) 389 | ); 390 | Checker::valueIsOfType( 391 | $value, $this->valueType, 392 | sprintf( 393 | 'The %s type specified for this dictionary is %s, you cannot pass %s %s', 394 | 'value', $this->valueType, getArticle(gettype($value)), gettype($value) 395 | ) 396 | ); 397 | 398 | return true; 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /src/Collections/GenericList.php: -------------------------------------------------------------------------------- 1 | type = $type; 49 | $this->error = "The type specified for this collection is {$type}, you cannot pass an object of type %s"; 50 | 51 | foreach ($data as $value) { 52 | Checker::objectIsOfType($value, $this->type, sprintf($this->error, get_class($value))); 53 | } 54 | 55 | parent::__construct($data); 56 | } 57 | 58 | /** 59 | * Adds a new object to the collection. 60 | * 61 | * @param object $value 62 | * 63 | * @throws \InvalidArgumentException 64 | * 65 | * @return void 66 | */ 67 | public function add(object $value): void 68 | { 69 | Checker::objectIsOfType($value, $this->type, sprintf($this->error, get_class($value))); 70 | 71 | $data = $this->toArray(); 72 | 73 | array_push($data, $value); 74 | $this->dataHolder->setContainer($data); 75 | } 76 | 77 | /** 78 | * Gets the difference between two GenericList. 79 | * 80 | * @param \PHPCollections\Collections\GenericList $newGenericList 81 | * 82 | * @throws \PHPCollections\Exceptions\InvalidOperationException 83 | * 84 | * @return \PHPCollections\Collections\GenericList 85 | */ 86 | public function diff(BaseCollection $newGenericList): BaseCollection 87 | { 88 | if (!$newGenericList instanceof self) { 89 | throw new InvalidOperationException('You should only compare a GenericList against another GenericList'); 90 | } 91 | 92 | if ($this->type !== $newGenericList->getType()) { 93 | throw new InvalidOperationException("This is a collection of {$this->type} objects, you cannot pass a collection of {$newGenericList->getType()} objects"); 94 | } 95 | 96 | $diffValues = array_udiff($this->toArray(), $newGenericList->toArray(), function ($firstValue, $secondValue) { 97 | return $firstValue <=> $secondValue; 98 | }); 99 | 100 | return new self($this->type, ...$diffValues); 101 | } 102 | 103 | /** 104 | * Determines if two GenericList objects are equal. 105 | * 106 | * @param \PHPCollections\Collections\GenericList $newGenericList 107 | * 108 | * @return bool 109 | */ 110 | public function equals(BaseCollection $newGenericList): bool 111 | { 112 | if (!$newGenericList instanceof self) { 113 | throw new InvalidOperationException('You should only compare an GenericList against another GenericList'); 114 | } 115 | 116 | return $this->toArray() == $newGenericList->toArray(); 117 | } 118 | 119 | /** 120 | * Returns all the coincidences found 121 | * for the given callback or null. 122 | * 123 | * @param callable $callback 124 | * 125 | * @return \PHPCollections\Collections\GenericList|null 126 | */ 127 | public function filter(callable $callback): ?self 128 | { 129 | $matcheds = []; 130 | 131 | foreach ($this->dataHolder as $key => $value) { 132 | if (call_user_func($callback, $key, $value) === true) { 133 | $matcheds[] = $value; 134 | } 135 | } 136 | 137 | return count($matcheds) > 0 ? new $this($this->type, ...array_values($matcheds)) : null; 138 | } 139 | 140 | /** 141 | * Iterates over every element of the collection. 142 | * 143 | * @param callable $callback 144 | * 145 | * @return void 146 | */ 147 | public function forEach(callable $callback): void 148 | { 149 | $data = $this->toArray(); 150 | 151 | array_walk($data, $callback); 152 | $this->dataHolder->setContainer($data); 153 | } 154 | 155 | /** 156 | * Returns the object at the specified index 157 | * or null if it's not defined. 158 | * 159 | * @param int $offset 160 | * 161 | * @throws \OutOfRangeException 162 | * 163 | * @return object 164 | */ 165 | public function get(int $offset): object 166 | { 167 | if ($this->isEmpty()) { 168 | throw new OutOfRangeException('You\'re trying to get data from an empty collection.'); 169 | } 170 | 171 | if (!$this->dataHolder->offsetExists($offset)) { 172 | throw new OutOfRangeException(sprintf('The %d index do not exits for this collection.', $offset)); 173 | } 174 | 175 | return $this->dataHolder->offsetGet($offset); 176 | } 177 | 178 | /** 179 | * Returns the type property. 180 | * 181 | * @return string 182 | */ 183 | private function getType(): string 184 | { 185 | return $this->type; 186 | } 187 | 188 | /** 189 | * Updates elements in the collection by 190 | * applying a given callback function. 191 | * 192 | * @param callable $callback 193 | * 194 | * @return \PHPCollections\Collections\GenericList|null 195 | */ 196 | public function map(callable $callback): ?self 197 | { 198 | $matcheds = array_map($callback, $this->toArray()); 199 | 200 | return count($matcheds) > 0 ? new $this($this->type, ...array_values($matcheds)) : null; 201 | } 202 | 203 | /** 204 | * Merges two GenericList into a new one. 205 | * 206 | * @param array $data 207 | * 208 | * @throws \InvalidArgumentException 209 | * 210 | * @return \PHPCollections\Collections\GenericList 211 | */ 212 | public function merge(BaseCollection $newGenericList): BaseCollection 213 | { 214 | $newGenericList->forEach(function ($value) { 215 | Checker::objectIsOfType($value, $this->type, sprintf($this->error, get_class($value))); 216 | }); 217 | 218 | return new $this($this->type, ...array_merge($this->toArray(), $newGenericList->toArray())); 219 | } 220 | 221 | /** 222 | * Returns a random element from 223 | * the collection. 224 | * 225 | * @throws \PHPCollections\Exceptions\InvalidOperationException 226 | * 227 | * @return mixed 228 | */ 229 | public function rand() 230 | { 231 | if ($this->isEmpty()) { 232 | throw new InvalidOperationException('You cannot get a random element from an empty collection.'); 233 | } 234 | 235 | $randomIndex = array_rand($this->toArray()); 236 | 237 | return $this->get($randomIndex); 238 | } 239 | 240 | /** 241 | * Removes an item from the collection 242 | * and repopulate the data container. 243 | * 244 | * @param int $offset 245 | * 246 | * @throws \OutOfRangeException 247 | * 248 | * @return void 249 | */ 250 | public function remove(int $offset): void 251 | { 252 | if ($this->isEmpty()) { 253 | throw new OutOfRangeException('You\'re trying to remove data into a empty collection.'); 254 | } 255 | 256 | if (!$this->dataHolder->offsetExists($offset)) { 257 | throw new OutOfRangeException(sprintf('The %d index do not exits for this collection.', $offset)); 258 | } 259 | 260 | $this->dataHolder->offsetUnset($offset); 261 | $this->repopulate(); 262 | } 263 | 264 | /** 265 | * Repopulates the data container. 266 | * 267 | * @return void 268 | */ 269 | private function repopulate(): void 270 | { 271 | $oldData = array_values($this->toArray()); 272 | $this->dataHolder->setContainer($oldData); 273 | } 274 | 275 | /** 276 | * Returns a new collection with the 277 | * reversed values. 278 | * 279 | * @throws \PHPCollections\Exceptions\InvalidOperationException 280 | * 281 | * @return \PHPCollections\Collections\GenericList 282 | */ 283 | public function reverse(): self 284 | { 285 | if ($this->isEmpty()) { 286 | throw new InvalidOperationException('You cannot reverse an empty collection.'); 287 | } 288 | 289 | return new $this($this->type, ...array_reverse($this->toArray())); 290 | } 291 | 292 | /** 293 | * Returns a portion of the GenericList. 294 | * 295 | * @param int $offset 296 | * @param int|null $length 297 | * 298 | * @return \PHPCollections\Collections\GenericList|null 299 | */ 300 | public function slice(int $offset, ?int $length = null): ?BaseCollection 301 | { 302 | $newData = array_slice($this->toArray(), $offset, $length); 303 | 304 | return count($newData) > 0 ? new self($this->type, ...$newData) : null; 305 | } 306 | 307 | /** 308 | * Returns a new GenericList with the 309 | * values ordered by a given callback 310 | * if couldn't sort returns null. 311 | * 312 | * 313 | * @param callable $callback 314 | * 315 | * @return \PHPCollections\Collections\GenericList|null 316 | */ 317 | public function sort(callable $callback): ?BaseCollection 318 | { 319 | $data = $this->toArray(); 320 | 321 | return usort($data, $callback) ? new $this($this->type, ...$data) : null; 322 | } 323 | 324 | /** 325 | * Updates the value of the element 326 | * at the given index. 327 | * 328 | * @param int $index 329 | * @param mixed $value 330 | * 331 | * @throws \InvalidArgumentException 332 | * @throws \PHPCollections\Exceptions\InvalidOperationException 333 | * 334 | * @return bool 335 | */ 336 | public function update(int $index, object $value): bool 337 | { 338 | Checker::objectIsOfType($value, $this->type, sprintf($this->error, get_class($value))); 339 | 340 | if (!$this->exists($index)) { 341 | throw new InvalidOperationException('You cannot update a non-existent value'); 342 | } 343 | 344 | $this->dataHolder[$index] = $value; 345 | 346 | return $this->dataHolder[$index] === $value; 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /src/Collections/Pair.php: -------------------------------------------------------------------------------- 1 | key = $key; 36 | $this->value = $value; 37 | } 38 | 39 | /** 40 | * Allows access to the key 41 | * property by its value. 42 | * 43 | * @param string $name 44 | * 45 | * @return mixed 46 | */ 47 | public function __get(string $name) 48 | { 49 | if ($name === $this->key) { 50 | return $this->value; 51 | } 52 | } 53 | 54 | /** 55 | * Returns the key property. 56 | * 57 | * @return mixed 58 | */ 59 | public function getKey() 60 | { 61 | return $this->key; 62 | } 63 | 64 | /** 65 | * Returns the value property. 66 | * 67 | * @return mixed 68 | */ 69 | public function getValue() 70 | { 71 | return $this->value; 72 | } 73 | 74 | /** 75 | * Sets the value of the value property. 76 | * 77 | * @param mixed $value 78 | * 79 | * @return void 80 | */ 81 | public function setValue($value): void 82 | { 83 | $this->value = $value; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Collections/Stack.php: -------------------------------------------------------------------------------- 1 | data = []; 38 | $this->type = $type; 39 | } 40 | 41 | /** 42 | * Clears the data values. 43 | * 44 | * @return void 45 | */ 46 | public function clear(): void 47 | { 48 | $this->data = []; 49 | } 50 | 51 | /** 52 | * Returns the length of the Stack. 53 | * 54 | * @return int 55 | */ 56 | public function count(): int 57 | { 58 | return count($this->data); 59 | } 60 | 61 | /** 62 | * Checks if the stack is empty. 63 | * 64 | * @return bool 65 | */ 66 | public function isEmpty(): bool 67 | { 68 | return $this->count() === 0; 69 | } 70 | 71 | /** 72 | * Gets the element at 73 | * the end of the Stack. 74 | * 75 | * @return mixed 76 | */ 77 | public function peek() 78 | { 79 | return $this->data[$this->count() - 1]; 80 | } 81 | 82 | /** 83 | * Pops the element at 84 | * the end of the stack. 85 | * 86 | * @return mixed 87 | */ 88 | public function pop() 89 | { 90 | return array_pop($this->data); 91 | } 92 | 93 | /** 94 | * Adds a new element at 95 | * the end of the Stack. 96 | * 97 | * @param mixed $value 98 | * 99 | * @throws \InvalidArgumentException 100 | * 101 | * @return mixed 102 | */ 103 | public function push($value) 104 | { 105 | $message = sprintf( 106 | 'The type specified for this collection is %s, you cannot pass a value of type %s', 107 | $this->type, gettype($value) 108 | ); 109 | 110 | Checker::valueIsOfType($value, $this->type, $message); 111 | 112 | $this->data[] = $value; 113 | 114 | return $value; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/DataHolder.php: -------------------------------------------------------------------------------- 1 | container = $data; 31 | } 32 | 33 | /** 34 | * Returns the container array. 35 | * 36 | * @return array 37 | */ 38 | public function getContainer(): array 39 | { 40 | return $this->container; 41 | } 42 | 43 | /** 44 | * Returns an array iterator for 45 | * the container property. 46 | * 47 | * @return \ArrayIterator 48 | */ 49 | public function getIterator(): ArrayIterator 50 | { 51 | return new ArrayIterator($this->container); 52 | } 53 | 54 | /** 55 | * Checks if an offset exists in the container. 56 | * 57 | * @param mixed $offset 58 | * 59 | * @return bool 60 | */ 61 | public function offsetExists($offset): bool 62 | { 63 | return isset($this->container[$offset]); 64 | } 65 | 66 | /** 67 | * Gets a value from the container. 68 | * 69 | * @param mixed $offset 70 | * 71 | * @return mixed|null 72 | */ 73 | public function offsetGet($offset) 74 | { 75 | return $this->container[$offset] ?? null; 76 | } 77 | 78 | /** 79 | * Sets a value into the container. 80 | * 81 | * @param mixed $offset 82 | * @param mixed $value 83 | * 84 | * @return void 85 | */ 86 | public function offsetSet($offset, $value): void 87 | { 88 | $this->container[$offset] = $value; 89 | } 90 | 91 | /** 92 | * Unsets an offset from the container. 93 | * 94 | * @param mixed $offset 95 | * 96 | * @return void 97 | */ 98 | public function offsetUnset($offset): void 99 | { 100 | unset($this->container[$offset]); 101 | } 102 | 103 | /** 104 | * Sets the container array. 105 | * 106 | * @param array $data 107 | * 108 | * @return void 109 | */ 110 | public function setContainer(array $data): void 111 | { 112 | $this->container = $data; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidOperationException.php: -------------------------------------------------------------------------------- 1 | code, $this->message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Interfaces/CollectionInterface.php: -------------------------------------------------------------------------------- 1 | arrayList = new ArrayList(); 17 | $this->arrayList->add('Max'); 18 | $this->arrayList->add(5); 19 | $this->arrayList->add(false); 20 | $this->arrayList->add(new StdClass()); 21 | $this->arrayList->add(null); 22 | } 23 | 24 | /** @test */ 25 | public function canAddElements() 26 | { 27 | $this->arrayList->add('last index'); 28 | 29 | $lastIndex = $this->arrayList->count() - 1; 30 | 31 | $this->assertEquals('last index', $this->arrayList->get($lastIndex)); 32 | } 33 | 34 | /** @test */ 35 | public function canClearData() 36 | { 37 | $this->arrayList->clear(); 38 | $this->assertEmpty($this->arrayList); 39 | } 40 | 41 | /** @test */ 42 | public function canCheckIfIndexExists() 43 | { 44 | $this->assertTrue($this->arrayList->exists(0)); 45 | } 46 | 47 | /** @test */ 48 | public function canFilterByValue() 49 | { 50 | $newArrayList = $this->arrayList->filter(function ($value) { 51 | return is_string($value); 52 | }); 53 | 54 | $this->assertNotNull($newArrayList); 55 | $this->assertCount(1, $newArrayList); 56 | $this->assertEquals('Max', $newArrayList->get(0)); 57 | } 58 | 59 | /** @test */ 60 | public function canCheckIfAValueIsContained() 61 | { 62 | $isContained = $this->arrayList->contains(null); 63 | 64 | $this->assertTrue($isContained); 65 | } 66 | 67 | /** @test */ 68 | public function canGetFirstElement() 69 | { 70 | $firstElement = $this->arrayList->first(); 71 | 72 | $this->assertEquals('Max', $firstElement); 73 | } 74 | 75 | /** @test */ 76 | public function canGetLastElement() 77 | { 78 | $lastElement = $this->arrayList->last(); 79 | 80 | $this->assertNull($lastElement); 81 | } 82 | 83 | /** @test */ 84 | public function canUpdateTheElementsByMapping() 85 | { 86 | $newArrayList = $this->arrayList->map(function ($val) { 87 | if ($val == false) { 88 | return 'Empty value'; 89 | } else { 90 | return $val; 91 | } 92 | }); 93 | 94 | $this->assertContains('Empty value', $newArrayList->toArray()); 95 | } 96 | 97 | /** @test */ 98 | public function canMergeNewDataIntoNewArrayList() 99 | { 100 | $numbers = new ArrayList([1, 2, 3, 4, 5]); 101 | $newArrayList = $numbers->merge(new ArrayList([6, 7, 8, 9, 10])); 102 | 103 | $this->assertCount(10, $newArrayList); 104 | $this->assertEquals(1, $newArrayList->first()); 105 | $this->assertEquals(10, $newArrayList->last()); 106 | } 107 | 108 | /** 109 | * @test 110 | * @expectedException PHPCollections\Exceptions\InvalidOperationException 111 | */ 112 | public function cannotGetARandomValueFromEmptyArrayList() 113 | { 114 | $newArrayList = new ArrayList(); 115 | $newArrayList->rand(); // Here an InvalidOperationException is thrown! 116 | } 117 | 118 | /** @test */ 119 | public function canReverse() 120 | { 121 | $reversedList = $this->arrayList->reverse(); 122 | $this->assertEquals(null, $reversedList->first()); 123 | $this->assertEquals('Max', $reversedList->last()); 124 | } 125 | 126 | /** 127 | * @test 128 | * @expectedException PHPCollections\Exceptions\InvalidOperationException 129 | */ 130 | public function cannotReverseAnEmptyArrayList() 131 | { 132 | $newArrayList = new ArrayList(); 133 | $reversedList = $newArrayList->reverse(); // Here an InvalidOperationException is thrown! 134 | } 135 | 136 | /** @test */ 137 | public function canUpdateAValue() 138 | { 139 | $this->arrayList->update(0, 'John'); 140 | $this->assertEquals('John', $this->arrayList->get(0)); 141 | } 142 | 143 | /** 144 | * @test 145 | * @expectedException PHPCollections\Exceptions\InvalidOperationException 146 | */ 147 | public function cannotUpdateAnNonExistingValue() 148 | { 149 | $newArrayList = new ArrayList(); 150 | $newArrayList->update(0, 'Some value'); // Here an InvalidOperationException is thrown! 151 | } 152 | 153 | /** @test */ 154 | public function canIterateOverEachElement() 155 | { 156 | $this->arrayList->forEach(function (&$value, $key) { 157 | if (!is_object($value) && $value) { 158 | $value = $value.'x'; 159 | } 160 | }); 161 | 162 | $this->assertEquals('Maxx', $this->arrayList->get(0)); 163 | $this->assertEquals('5x', $this->arrayList->get(1)); 164 | } 165 | 166 | /** 167 | * @test 168 | * @expectedException \OutOfRangeException 169 | */ 170 | public function canRemoveElementByIndex() 171 | { 172 | $this->assertEquals('Max', $this->arrayList->get(0)); 173 | $this->arrayList->remove(0); 174 | 175 | $this->assertFalse($this->arrayList->contains('Max')); 176 | $this->arrayList->remove(0); // Here an OutOfRangeException is thrown! 177 | } 178 | 179 | /** @test */ 180 | public function canCompareTwoArrayList() 181 | { 182 | $newList = new ArrayList(['Max', 5, false]); 183 | $diffList = $this->arrayList->diff($newList); 184 | 185 | $this->assertInstanceOf(ArrayList::class, $diffList); 186 | $this->assertTrue($diffList->contains(null)); 187 | $this->assertCount(2, $diffList); 188 | } 189 | 190 | /** @test */ 191 | public function canNotCompareAnArrayListAgainstAnotherTypeOfCollection() 192 | { 193 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 194 | $this->expectExceptionMessage('You should only compare an ArrayList against another ArrayList'); 195 | 196 | $newList = new GenericList( 197 | StdClass::class, 198 | new StdClass(['name' => 'John']), 199 | new StdClass(['name' => 'Carter']) 200 | ); 201 | 202 | $diffList = $this->arrayList->diff($newList); // Here an InvalidOperationException is thrown! 203 | } 204 | 205 | /** @test */ 206 | public function canSliceAnArrayList() 207 | { 208 | $this->assertCount(3, $this->arrayList->slice(2)); 209 | $this->assertCount(3, $this->arrayList->slice(2, null)); 210 | $this->assertCount(3, $this->arrayList->slice(2, 3)); 211 | $this->assertNull((new ArrayList())->slice(2)); 212 | } 213 | 214 | /** @test */ 215 | public function canCheckIfTwoArrayListAreEqual() 216 | { 217 | $newArrayList = new ArrayList(['Max', 5, false, new StdClass(), null]); 218 | 219 | $this->assertTrue($this->arrayList->equals($newArrayList)); 220 | $this->assertFalse($this->arrayList->equals(new ArrayList(['Max', 5, false]))); 221 | } 222 | 223 | /** @test */ 224 | public function canNotCheckIfAnArrayListIsEqualToAnotherTypeOfCollection() 225 | { 226 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 227 | $this->expectExceptionMessage('You should only compare an ArrayList against another ArrayList'); 228 | $this->arrayList->equals(new GenericList(StdClass::class)); 229 | } 230 | 231 | /** @test */ 232 | public function canSumANumericFieldOfTheArrayList() 233 | { 234 | $newList = new ArrayList([18, 12, 23, 16, 14]); 235 | $totalPoints = $newList->sum(function ($points) { 236 | return $points; 237 | }); 238 | 239 | $this->assertEquals(83, $totalPoints); 240 | } 241 | 242 | /** @test */ 243 | public function canNotSumANonNumericFieldOfTheArrayList() 244 | { 245 | $newList = new ArrayList(['Kyle Lowry', 'Danny Green', 'Kawhi Leonard', 'Paskal Siakam', 'Serge Ibaka']); 246 | 247 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 248 | $this->expectExceptionMessage('You cannot sum non-numeric values'); 249 | $newList->sum(function ($name) { 250 | return $name; 251 | }); // Here an InvalidOperationException is thrown! 252 | } 253 | 254 | /** @test */ 255 | public function itCanFillAnArrayListWithData() 256 | { 257 | $this->arrayList->fill([ 258 | 'first_value', 259 | 'second_value', 260 | ]); 261 | 262 | $this->assertCount(7, $this->arrayList); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /tests/Unit/CheckerTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($isChecked); 17 | } 18 | 19 | /** 20 | * @test 21 | * @expectedException InvalidArgumentException 22 | * @expectedExceptionMessage You're not passing a stdClass object 23 | */ 24 | public function it_throws_an_exception_when_object_is_not_of_certain_type() 25 | { 26 | Checker::objectIsOfType(new StdClass(), 'ArrayObject', 'You\'re not passing a stdClass object'); 27 | } 28 | 29 | /** @test */ 30 | public function it_can_check_a_value_is_an_object() 31 | { 32 | $isObject = Checker::isObject(new StdClass(), 'You\'re not passing an object'); 33 | 34 | $this->assertTrue($isObject); 35 | } 36 | 37 | /** 38 | * @test 39 | * @expectedException InvalidArgumentException 40 | * @expectedExceptionMessage You're not passing an object 41 | */ 42 | public function it_throws_an_exception_when_you_treat_a_primitive_like_an_object() 43 | { 44 | Checker::isObject('hello world', 'You\'re not passing an object'); 45 | } 46 | 47 | /** @test */ 48 | public function it_can_check_dictionary_value_is_of_certain_type() 49 | { 50 | $isChecked = Checker::valueIsOfType('hello world', 'string', 'You\'re not passing a string'); 51 | 52 | $this->assertTrue($isChecked); 53 | } 54 | 55 | /** 56 | * @test 57 | * @expectedException InvalidArgumentException 58 | * @expectedExceptionMessage You're not passing a string 59 | */ 60 | public function it_throws_an_exception_when_dictionary_value_is_not_of_certain_type() 61 | { 62 | Checker::valueIsOfType(500, 'string', 'You\'re not passing a string'); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/Unit/DataHolderTest.php: -------------------------------------------------------------------------------- 1 | dataHolder = new DataHolder([ 15 | 'name' => 'Max', 16 | 'age' => '24', 17 | ]); 18 | } 19 | 20 | /** @test */ 21 | public function it_can_add_elements() 22 | { 23 | $this->dataHolder->offsetSet('job', 'Programmer'); 24 | $this->assertEquals('Programmer', $this->dataHolder->offsetGet('job')); 25 | } 26 | 27 | /** @test */ 28 | public function it_can_remove_elements() 29 | { 30 | $this->dataHolder->offsetUnset('name'); 31 | $this->assertArrayNotHasKey('name', $this->dataHolder); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Unit/DictionaryTest.php: -------------------------------------------------------------------------------- 1 | dictionary = new Dictionary('string', 'string'); 18 | $this->dictionary->add('name', 'Max'); 19 | $this->dictionary->add('job', 'programmer'); 20 | $this->dictionary->add('drink', 'no'); 21 | $this->dictionary->add('smoke', 'no'); 22 | $this->dictionary->add('dance', 'a little bit'); 23 | $this->dictionary->add('drugs', 'no'); 24 | $this->dictionary->add('age', '23'); 25 | } 26 | 27 | /** 28 | * @test 29 | * @expectedException InvalidArgumentException 30 | */ 31 | public function canAddValuesOfTheSpecifiedTypes() 32 | { 33 | $this->dictionary->add('nickname', 'maxalmonte14'); 34 | $this->assertArrayHasKey('nickname', $this->dictionary->toArray()); 35 | $this->dictionary->add('movies', new ArrayObject(['Plan 9', 'The creature of the black lagoon', 'Nigth of the living dead'])); 36 | } 37 | 38 | /** @test */ 39 | public function canCheckIfContainsAValue() 40 | { 41 | $this->assertTrue($this->dictionary->exists('drink')); 42 | } 43 | 44 | /** @test */ 45 | public function canClearData() 46 | { 47 | $this->dictionary->clear(); 48 | $this->assertCount(0, $this->dictionary); 49 | } 50 | 51 | /** @test */ 52 | public function canGetAnElementByIndex() 53 | { 54 | $job = $this->dictionary->get('job'); 55 | $this->assertEquals('programmer', $job); 56 | 57 | $nullPointer = $this->dictionary->get('posts'); 58 | 59 | $this->assertNull($nullPointer); 60 | } 61 | 62 | /** @test */ 63 | public function canUpdateDataByMapping() 64 | { 65 | $newDictionary = $this->dictionary->map(function ($value) { 66 | return $value = 'no'; 67 | }); 68 | 69 | $this->assertInstanceOf(Dictionary::class, $newDictionary); 70 | $this->assertEquals('no', $newDictionary->get('smoke')); 71 | } 72 | 73 | /** @test */ 74 | public function canConvertDictionaryToArray() 75 | { 76 | $array = $this->dictionary->toArray(); 77 | 78 | $this->assertArrayHasKey('job', $array); 79 | $this->assertEquals('programmer', $array['job']); 80 | } 81 | 82 | /** @test */ 83 | public function canRemoveDataByIndex() 84 | { 85 | $this->dictionary->add('post', 'Lorem ipsum dolor sit amet...'); 86 | $this->dictionary->remove('post'); 87 | $this->assertArrayNotHasKey('post', $this->dictionary->toArray()); 88 | } 89 | 90 | /** @test */ 91 | public function canFilterDataByKeyAndValue() 92 | { 93 | $dictionary = new Dictionary('string', 'array'); 94 | $dictionary->add('books', ['Code smart', 'JS the good parts', 'Laravel up and running']); 95 | $dictionary->add('videogames', ['Assasin Creed', 'God of war', 'Need for speed']); 96 | 97 | $newDictionary = $dictionary->filter(function ($key, $value) { 98 | return $key === 'videogames'; 99 | }); 100 | 101 | $this->assertNotNull($newDictionary); 102 | $this->assertArrayHasKey('videogames', $newDictionary->toArray()); 103 | } 104 | 105 | /** 106 | * @test 107 | * @expectedException \OutOfRangeException 108 | * @expectedExceptionMessage You're trying to get data from an empty collection 109 | */ 110 | public function canGetFirstElement() 111 | { 112 | $this->assertEquals('Max', $this->dictionary->first()); 113 | 114 | $newDictionary = new Dictionary('string', 'int'); 115 | 116 | $newDictionary->first(); // Here an InvalidOperationException is thrown! 117 | } 118 | 119 | /** 120 | * @test 121 | * @expectedException \OutOfRangeException 122 | * @expectedExceptionMessage You're trying to get data from an empty collection 123 | */ 124 | public function canGetLastElement() 125 | { 126 | $this->assertEquals('23', $this->dictionary->last()); 127 | $newDictionary = new Dictionary('string', 'int'); 128 | 129 | $newDictionary->last(); // Here an InvalidOperationException is thrown! 130 | } 131 | 132 | /** 133 | * @test 134 | * @expectedException PHPCollections\Exceptions\InvalidOperationException 135 | */ 136 | public function canUpdateElementByIndex() 137 | { 138 | $isUpdated = $this->dictionary->update('job', 'PHP developer'); 139 | 140 | $this->assertTrue($isUpdated); 141 | $this->assertEquals('PHP developer', $this->dictionary->get('job')); 142 | $this->dictionary->update('height', '2.80'); // Here an InvalidOperationException is thrown! 143 | } 144 | 145 | /** 146 | * @test 147 | * @expectedException InvalidArgumentException 148 | */ 149 | public function canMergeNewDataIntoNewDictionary() 150 | { 151 | $dictionary1 = new Dictionary('string', 'array'); 152 | $dictionary1->add('english-spanish', ['one' => 'uno', 'two' => 'dos']); 153 | 154 | $translations = $dictionary1->merge( 155 | new Dictionary('string', 'array', ['english-japanese' => ['one' => 'ichi', 'two' => 'ni']]) 156 | ); 157 | 158 | $this->assertNotNull($translations); 159 | $this->assertCount(2, $translations); 160 | $this->assertArrayHasKey('english-spanish', $translations->toArray()); 161 | $this->assertArrayHasKey('english-japanese', $translations->toArray()); 162 | 163 | $dictionary2 = new Dictionary('string', 'string'); 164 | $dictionary2->merge( 165 | new Dictionary('string', 'integer', ['one' => 1, 'two' => 2]) 166 | ); // Here a InvalidOperationException is thrown! 167 | } 168 | 169 | /** @test */ 170 | public function canGetKeyType() 171 | { 172 | $key = $this->dictionary->getKeyType(); 173 | 174 | $this->assertInternalType('string', $key); 175 | } 176 | 177 | /** @test */ 178 | public function canGetValueType() 179 | { 180 | $value = $this->dictionary->getValueType(); 181 | 182 | $this->assertInternalType('string', $value); 183 | } 184 | 185 | /** @test */ 186 | public function canSortByGivenRules() 187 | { 188 | $sortedDictionary = $this->dictionary->sort(function ($x, $y) { 189 | return strlen($x) <=> strlen($y); 190 | }); 191 | 192 | $this->assertEquals('a little bit', $sortedDictionary->last()); 193 | } 194 | 195 | /** @test */ 196 | public function canIterateOverEachElement() 197 | { 198 | $this->dictionary->forEach(function (&$value, $key) { 199 | $value = $value.'x'; 200 | }); 201 | 202 | $this->assertEquals('Maxx', $this->dictionary->get('name')); 203 | $this->assertEquals('programmerx', $this->dictionary->get('job')); 204 | } 205 | 206 | /** @test */ 207 | public function canCompareTwoDictionary() 208 | { 209 | $newDictionary = new Dictionary('string', 'string', [ 210 | 'drink' => 'no', 211 | 'smoke' => 'no', 212 | 'dance' => 'a little bit', 213 | ]); 214 | 215 | $diffDictionary = $this->dictionary->diff($newDictionary); 216 | 217 | $this->assertInstanceOf(Dictionary::class, $diffDictionary); 218 | $this->assertEquals($diffDictionary->get('job'), 'programmer'); 219 | $this->assertCount(4, $diffDictionary); 220 | } 221 | 222 | /** @test */ 223 | public function canNotCompareTwoDictionaryOfDifferentKeyTypes() 224 | { 225 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 226 | $this->expectExceptionMessage('The key type for this Dictionary is string, you cannot pass a Dictionary with integer as key type'); 227 | 228 | $newDictionary = new Dictionary( 229 | 'integer', 'string', [1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five'] 230 | ); 231 | 232 | $diffDictionary = $this->dictionary->diff($newDictionary); // Here an InvalidOperationException is thrown! 233 | } 234 | 235 | /** @test */ 236 | public function canNotCompareTwoDictionaryOfDifferentValueTypes() 237 | { 238 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 239 | $this->expectExceptionMessage('The value type for this Dictionary is string, you cannot pass a Dictionary with integer as value type'); 240 | 241 | $newDictionary = new Dictionary( 242 | 'string', 'integer', ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' => 5] 243 | ); 244 | 245 | $diffDictionary = $this->dictionary->diff($newDictionary); // Here an InvalidOperationException is thrown! 246 | } 247 | 248 | /** @test */ 249 | public function canNotCompareADictionaryAgainstAnotherTypeOfCollection() 250 | { 251 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 252 | $this->expectExceptionMessage('You should only compare a Dictionary against another Dictionary'); 253 | 254 | $newDictionary = new GenericList( 255 | StdClass::class, 256 | new StdClass(['name' => 'John']), 257 | new StdClass(['name' => 'Carter']) 258 | ); 259 | 260 | $diffDictionary = $this->dictionary->diff($newDictionary); // Here an InvalidOperationException is thrown! 261 | } 262 | 263 | /** @test */ 264 | public function canSliceADictionary() 265 | { 266 | $this->assertCount(5, $this->dictionary->slice(2)); 267 | $this->assertCount(5, $this->dictionary->slice(2, null)); 268 | $this->assertCount(4, $this->dictionary->slice(2, 4)); 269 | $this->assertNull((new Dictionary('string', 'string'))->slice(2)); 270 | } 271 | 272 | /** @test */ 273 | public function canCheckIfTheDictionaryContainsAGivenValue() 274 | { 275 | $this->assertTrue($this->dictionary->contains('Max')); 276 | $this->assertFalse($this->dictionary->contains('Almonte')); 277 | } 278 | 279 | /** @test */ 280 | public function canCheckIfTwoDictionaryObjectsAreEqual() 281 | { 282 | $newDictionary = new Dictionary('string', 'string', [ 283 | 'name' => 'Max', 284 | 'job' => 'programmer', 285 | 'drink' => 'no', 286 | 'smoke' => 'no', 287 | 'dance' => 'a little bit', 288 | 'drugs' => 'no', 289 | 'age' => '23', 290 | ]); 291 | 292 | $this->assertTrue($this->dictionary->equals($newDictionary)); 293 | $this->assertFalse($this->dictionary->equals(new Dictionary('string', 'string'))); 294 | } 295 | 296 | /** @test */ 297 | public function canNotCheckIfAnDictionaryIsEqualToAnotherTypeOfCollection() 298 | { 299 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 300 | $this->expectExceptionMessage('You should only compare an Dictionary against another Dictionary'); 301 | $this->dictionary->equals(new GenericList(StdClass::class)); 302 | } 303 | 304 | /** @test */ 305 | public function canSumANumericFieldOfTheDictionary() 306 | { 307 | $newList = new Dictionary( 308 | 'string', 'integer', 309 | [ 310 | 'Kyle Lowry' => 18, 311 | 'Danny Green' => 12, 312 | 'Kawhi Leonard'=> 23, 313 | 'Paskal Siakam'=> 16, 314 | 'Serge Ibaka' => 14, 315 | ] 316 | ); 317 | $totalPoints = $newList->sum(function ($pair) { 318 | return $pair->getValue(); 319 | }); 320 | 321 | $this->assertEquals(83, $totalPoints); 322 | } 323 | 324 | /** @test */ 325 | public function canNotSumANonNumericFieldOfTheDictionary() 326 | { 327 | $newList = new Dictionary( 328 | 'string', 'integer', 329 | [ 330 | 'Kyle Lowry' => 18, 331 | 'Danny Green' => 12, 332 | 'Kawhi Leonard'=> 23, 333 | 'Paskal Siakam'=> 16, 334 | 'Serge Ibaka' => 14, 335 | ] 336 | ); 337 | 338 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 339 | $this->expectExceptionMessage('You cannot sum non-numeric values'); 340 | $newList->sum(function ($pair) { 341 | return $pair->getKey(); 342 | }); // Here an InvalidOperationException is thrown! 343 | } 344 | 345 | /** @test */ 346 | public function itCanFillADictionarytWithData() 347 | { 348 | $this->dictionary->fill([ 349 | 'first_key' => 'first_value', 350 | 'second_key' => 'second_value', 351 | ]); 352 | 353 | $this->assertCount(9, $this->dictionary); 354 | $this->expectException('\InvalidArgumentException'); 355 | $this->expectExceptionMessage('The key type specified for this dictionary is string, you cannot pass an integer'); 356 | $this->dictionary->fill([0 => true]); 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /tests/Unit/GenericListTest.php: -------------------------------------------------------------------------------- 1 | list = new GenericList(ArrayObject::class); 18 | $this->list->add(new ArrayObject(['name' => 'John'])); 19 | $this->list->add(new ArrayObject(['name' => 'Finch'])); 20 | $this->list->add(new ArrayObject(['name' => 'Shaw'])); 21 | $this->list->add(new ArrayObject(['name' => 'Carter'])); 22 | $this->list->add(new ArrayObject(['name' => 'Kara'])); 23 | $this->list->add(new ArrayObject(['name' => 'Snow'])); 24 | $this->list->add(new ArrayObject(['name' => 'Zoey'])); 25 | $this->list->add(new ArrayObject(['name' => 'Cal'])); 26 | $this->list->add(new ArrayObject(['name' => 'Lionel'])); 27 | } 28 | 29 | /** @test */ 30 | public function canCreateACollectionWithMultipleParameters() 31 | { 32 | $this->list = null; 33 | $this->list = new GenericList( 34 | ArrayObject::class, 35 | new ArrayObject(['name' => 'John']), 36 | new ArrayObject(['name' => 'Finch']), 37 | new ArrayObject(['name' => 'Shaw']), 38 | new ArrayObject(['name' => 'Carter']) 39 | ); 40 | 41 | $this->assertInstanceOf(GenericList::class, $this->list); 42 | $this->assertCount(4, $this->list); 43 | } 44 | 45 | /** 46 | * @test 47 | */ 48 | public function canAddAnElementToList() 49 | { 50 | $this->assertCount(9, $this->list); 51 | $this->list->add(new ArrayObject(['name' => 'Samaritan'])); 52 | } 53 | 54 | /** 55 | * @test 56 | * @expectedException InvalidArgumentException 57 | * @expectedExceptionMessage The type specified for this collection is 58 | * ArrayObject, you cannot pass an object of type stdClass 59 | */ 60 | public function canNotAddAnElementOfDifferentTypeToList() 61 | { 62 | $this->list->add(new StdClass()); // Here an InvalidArgumentException is thrown! 63 | } 64 | 65 | /** @test */ 66 | public function canClearData() 67 | { 68 | $this->list->clear(); 69 | $this->assertCount(0, $this->list); 70 | } 71 | 72 | /** 73 | * @test 74 | * @expectedException OutOfRangeException 75 | */ 76 | public function canGetAnElementOfTheList() 77 | { 78 | $arrayObject = $this->list->get(2); 79 | $this->assertEquals('Shaw', $arrayObject->offsetGet('name')); 80 | $this->list->get(9); // Here an OutOfRangeException is thrown! 81 | } 82 | 83 | /** 84 | * @test 85 | * @expectedException OutOfRangeException 86 | */ 87 | public function canRemoveAnElementOfTheList() 88 | { 89 | $this->list->remove(0); 90 | $this->assertCount(8, $this->list); 91 | $arrayObject = $this->list->get(0); 92 | $this->assertNotEquals('John', $arrayObject->offsetGet('name')); 93 | $this->list->remove(9); // Here an OutOfRangeException is thrown! 94 | } 95 | 96 | /** @test */ 97 | public function canFilterElementsOfTheList() 98 | { 99 | $newList = $this->list->filter(function ($value, $key) { 100 | return strlen($value['name']) <= 4; 101 | }); 102 | 103 | $this->assertEquals('John', $newList->get(0)->offsetGet('name')); 104 | $this->assertEquals('Finch', $newList->get(1)->offsetGet('name')); 105 | 106 | $anotherList = $this->list->filter(function ($value, $key) { 107 | return strlen($value['name']) > 10; 108 | }); 109 | 110 | $this->assertNull($anotherList); 111 | } 112 | 113 | /** @test */ 114 | public function canUpdateElementsOfTheListByMapping() 115 | { 116 | $newList = $this->list->map(function ($value) { 117 | $value['name'] = sprintf('%s %s', 'Sr.', $value['name']); 118 | 119 | return $value; 120 | }); 121 | $this->assertEquals('Sr. John', $newList->get(0)->offsetGet('name')); 122 | } 123 | 124 | /** @test */ 125 | public function canSortTheList() 126 | { 127 | $newList = $this->list->sort(function ($a, $b) { 128 | return $a->offsetGet('name') <=> $b->offsetGet('name'); 129 | }); 130 | 131 | $this->assertEquals('Cal', $newList->get(0)->offsetGet('name')); 132 | } 133 | 134 | /** 135 | * @test 136 | * @expectedException PHPCollections\Exceptions\InvalidOperationException 137 | */ 138 | public function canGetReversedOrderList() 139 | { 140 | $reversedList = $this->list->reverse(); 141 | $this->assertEquals('Lionel', $reversedList->get(0)->offsetGet('name')); 142 | 143 | $newList = new GenericList(ArrayObject::class); 144 | $newReversedList = $newList->reverse(); // Here an InvalidOperationException is thrown! 145 | } 146 | 147 | /** 148 | * @test 149 | * @expectedException PHPCollections\Exceptions\InvalidOperationException 150 | */ 151 | public function canGetARandomValue() 152 | { 153 | $randElement = $this->list->rand(); 154 | $this->assertArrayHasKey('name', $randElement); 155 | 156 | $newList = new GenericList(ArrayObject::class); 157 | $newList->rand(); // Here an InvalidOperationException is thrown! 158 | } 159 | 160 | /** @test */ 161 | public function canCheckIfIndexExists() 162 | { 163 | $this->assertTrue($this->list->exists(0)); 164 | $this->assertFalse($this->list->exists(20)); 165 | } 166 | 167 | /** @test */ 168 | public function canMergeNewDataIntoNewList() 169 | { 170 | $newList = $this->list->merge( 171 | new GenericList( 172 | ArrayObject::class, 173 | new ArrayObject(['name' => 'Max']), 174 | new ArrayObject(['name' => 'Alex']) 175 | ) 176 | ); 177 | $this->assertCount(11, $newList); 178 | $this->assertEquals('Max', $newList->get(9)->offsetGet('name')); 179 | } 180 | 181 | /** @test */ 182 | public function canGetFirstElementOfList() 183 | { 184 | $arrayObject = $this->list->first(); 185 | $this->assertEquals('John', $arrayObject->offsetGet('name')); 186 | } 187 | 188 | /** @test */ 189 | public function canGetLastElementOfList() 190 | { 191 | $arrayObject = $this->list->last(); 192 | $this->assertEquals('Lionel', $arrayObject->offsetGet('name')); 193 | } 194 | 195 | /** 196 | * @test 197 | */ 198 | public function canUpdateAnElement() 199 | { 200 | $isUpdated = $this->list->update(0, new ArrayObject(['name' => 'Elliot'])); 201 | $this->assertTrue($isUpdated); 202 | $this->assertEquals('Elliot', $this->list->get(0)->offsetGet('name')); 203 | } 204 | 205 | /** @test */ 206 | public function canIterateOverEachElement() 207 | { 208 | $this->list->forEach(function ($value, $key) { 209 | $value->offsetSet('name', $value->offsetGet('name').'x'); 210 | }); 211 | 212 | $this->assertEquals('Johnx', $this->list->get(0)->offsetGet('name')); 213 | } 214 | 215 | /** @test */ 216 | public function canCompareTwoGenericListOfTheSameType() 217 | { 218 | $newList = new GenericList( 219 | ArrayObject::class, 220 | new ArrayObject(['name' => 'John']), 221 | new ArrayObject(['name' => 'Finch']), 222 | new ArrayObject(['name' => 'Shaw']), 223 | new ArrayObject(['name' => 'Carter']) 224 | ); 225 | 226 | $diffList = $this->list->diff($newList); 227 | 228 | $this->assertInstanceOf(GenericList::class, $diffList); 229 | $this->assertEquals('Kara', $diffList->first()['name']); 230 | $this->assertEquals('Lionel', $diffList->last()['name']); 231 | $this->assertCount(5, $diffList); 232 | } 233 | 234 | /** @test */ 235 | public function canNotCompareTwoGenericListOfDifferentTypes() 236 | { 237 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 238 | $this->expectExceptionMessage('This is a collection of ArrayObject objects, you cannot pass a collection of StdClass objects'); 239 | 240 | $newList = new GenericList( 241 | StdClass::class, 242 | new StdClass(['name' => 'John']), 243 | new StdClass(['name' => 'Finch']), 244 | new StdClass(['name' => 'Shaw']), 245 | new StdClass(['name' => 'Carter']) 246 | ); 247 | 248 | $diffList = $this->list->diff($newList); // Here an InvalidOperationException is thrown! 249 | } 250 | 251 | /** @test */ 252 | public function canNotCompareAGenericListAgainstAnotherTypeOfCollection() 253 | { 254 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 255 | $this->expectExceptionMessage('You should only compare a GenericList against another GenericList'); 256 | 257 | $newList = new ArrayList([ 258 | new StdClass(['name' => 'John']), 259 | new StdClass(['name' => 'Finch']), 260 | new StdClass(['name' => 'Shaw']), 261 | new StdClass(['name' => 'Carter']), 262 | ]); 263 | 264 | $diffList = $this->list->diff($newList); // Here an InvalidOperationException is thrown! 265 | } 266 | 267 | /** @test */ 268 | public function canSliceAGenericList() 269 | { 270 | $this->assertCount(7, $this->list->slice(2)); 271 | $this->assertCount(7, $this->list->slice(2, null)); 272 | $this->assertCount(5, $this->list->slice(2, 5)); 273 | $this->assertNull((new GenericList(\StdClass::class))->slice(2)); 274 | } 275 | 276 | /** @test */ 277 | public function canCheckIfTheGenericListContainsAGivenValue() 278 | { 279 | $this->assertTrue($this->list->contains(new ArrayObject(['name' => 'John']))); 280 | $this->assertFalse($this->list->contains(new ArrayObject(['name' => 'Max']))); 281 | } 282 | 283 | /** @test */ 284 | public function canCheckIfTwoGenericListAreEqual() 285 | { 286 | $newList = new GenericList( 287 | ArrayObject::class, 288 | new ArrayObject(['name' => 'John']), 289 | new ArrayObject(['name' => 'Finch']), 290 | new ArrayObject(['name' => 'Shaw']), 291 | new ArrayObject(['name' => 'Carter']), 292 | new ArrayObject(['name' => 'Kara']), 293 | new ArrayObject(['name' => 'Snow']), 294 | new ArrayObject(['name' => 'Zoey']), 295 | new ArrayObject(['name' => 'Cal']), 296 | new ArrayObject(['name' => 'Lionel']) 297 | ); 298 | 299 | $this->assertTrue($this->list->equals($newList)); 300 | $this->assertFalse( 301 | $this->list->equals(new GenericList(ArrayObject::class, new ArrayObject(['name' => 'Max']))) 302 | ); 303 | } 304 | 305 | /** @test */ 306 | public function canNotCheckIfAGenericListIsEqualToAnotherTypeOfCollection() 307 | { 308 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 309 | $this->expectExceptionMessage('You should only compare an GenericList against another GenericList'); 310 | $this->list->equals(new ArrayList(['first', 'second', 'third'])); // Here an InvalidOperationException is thrown! 311 | } 312 | 313 | /** @test */ 314 | public function canSumANumericFieldOfTheGenericList() 315 | { 316 | $newList = new GenericList( 317 | ArrayObject::class, 318 | new ArrayObject(['name' => 'Kyle Lowry', 'points' => 18]), 319 | new ArrayObject(['name' => 'Danny Green', 'points' => 12]), 320 | new ArrayObject(['name' => 'Kawhi Leonard', 'points' => 23]), 321 | new ArrayObject(['name' => 'Paskal Siakam', 'points' => 16]), 322 | new ArrayObject(['name' => 'Serge Ibaka', 'points' => 14]) 323 | ); 324 | $totalPoints = $newList->sum(function ($arrayObject) { 325 | return $arrayObject->offsetGet('points'); 326 | }); 327 | 328 | $this->assertEquals(83, $totalPoints); 329 | } 330 | 331 | /** @test */ 332 | public function canNotSumANonNumericFieldOfTheGenericList() 333 | { 334 | $newList = new GenericList( 335 | ArrayObject::class, 336 | new ArrayObject(['name' => 'Kyle Lowry', 'points' => 18]), 337 | new ArrayObject(['name' => 'Danny Green', 'points' => 12]), 338 | new ArrayObject(['name' => 'Kawhi Leonard', 'points' => 23]), 339 | new ArrayObject(['name' => 'Paskal Siakam', 'points' => 16]), 340 | new ArrayObject(['name' => 'Serge Ibaka', 'points' => 14]) 341 | ); 342 | 343 | $this->expectException('\PHPCollections\Exceptions\InvalidOperationException'); 344 | $this->expectExceptionMessage('You cannot sum non-numeric values'); 345 | $newList->sum(function ($arrayObject) { 346 | return $arrayObject->offsetGet('name'); 347 | }); // Here an InvalidOperationException is thrown! 348 | } 349 | 350 | /** @test */ 351 | public function itCanFillAGenericListWithData() 352 | { 353 | $this->list->fill([ 354 | new ArrayObject(['name' => 'Max']), 355 | new ArrayObject(['name' => 'John']), 356 | ]); 357 | 358 | $this->assertCount(11, $this->list); 359 | $this->expectException('\InvalidArgumentException'); 360 | $this->expectExceptionMessage('The type specified for this collection is ArrayObject, you cannot pass an object of type stdClass'); 361 | $this->list->fill([new StdClass()]); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /tests/Unit/InvalidOperationExceptionTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('The Exception is catchable!', $e->getMessage()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Unit/StackTest.php: -------------------------------------------------------------------------------- 1 | stack = new Stack('string'); 15 | $this->stack->push('John'); 16 | $this->stack->push('Harold'); 17 | $this->stack->push('Sameen'); 18 | $this->stack->push('Joss'); 19 | $this->stack->push('Cal'); 20 | $this->stack->push('Peter'); 21 | $this->stack->push('Samantha'); 22 | } 23 | 24 | /** 25 | * @test 26 | * @expectedException InvalidArgumentException 27 | */ 28 | public function cannotPushUncompatibleValueToStack() 29 | { 30 | $this->stack->push(['color' => 'green']); 31 | } 32 | 33 | /** @test */ 34 | public function canPushAnElement() 35 | { 36 | $newElement = $this->stack->push('Zoey'); 37 | $this->assertEquals($newElement, $this->stack->peek()); 38 | } 39 | 40 | /** @test */ 41 | public function canPeekLastElement() 42 | { 43 | $lastElement = $this->stack->peek(); 44 | $this->assertEquals('Samantha', $lastElement); 45 | } 46 | 47 | /** @test */ 48 | public function canPopLastElement() 49 | { 50 | $lastElement = $this->stack->pop(); 51 | $this->assertEquals('Samantha', $lastElement); 52 | $this->assertEquals('Peter', $this->stack->peek()); 53 | } 54 | 55 | /** @test */ 56 | public function canCountTheElements() 57 | { 58 | $this->assertCount(7, $this->stack); 59 | } 60 | 61 | /** @test */ 62 | public function canCheckIfTheStackIsEmpty() 63 | { 64 | $newStack = new Stack('string'); 65 | $this->assertTrue($newStack->isEmpty()); 66 | $this->assertFalse($this->stack->isEmpty()); 67 | } 68 | 69 | /** @test */ 70 | public function canClearStack() 71 | { 72 | $this->stack->clear(); 73 | $this->assertTrue($this->stack->isEmpty()); 74 | } 75 | } 76 | --------------------------------------------------------------------------------