├── .circleci └── config.yml ├── .php_cs.dist.php ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json └── src ├── Contracts ├── Arrayable.php ├── Breakable.php ├── HasLooper.php ├── Indexable.php ├── Jsonable.php ├── LoopCallback.php ├── Looper.php └── Workable.php ├── Exceptions ├── AsyncIsNotSupportedException.php └── NotWorkedException.php ├── Index.php ├── Loop.php ├── Workers ├── AsyncWorker.php └── DefaultWorker.php └── helpers.php /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # PHP CircleCI 2.0 configuration file 2 | # See: https://circleci.com/docs/2.0/language-php/ 3 | version: 2 4 | 5 | # Define a job to be invoked later in a workflow. 6 | # See: https://circleci.com/docs/2.0/configuration-reference/#jobs 7 | jobs: 8 | build: 9 | # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. 10 | # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor 11 | docker: 12 | # Specify the version you desire here 13 | - image: circleci/php:8.0-cli 14 | 15 | # Specify service dependencies here if necessary 16 | # CircleCI maintains a library of pre-built images 17 | # documented at https://circleci.com/docs/2.0/circleci-images/ 18 | # Using the RAM variation mitigates I/O contention 19 | # for database intensive operations. 20 | # - image: circleci/mysql:5.7-ram 21 | # 22 | # - image: redis:2.8.19 23 | 24 | # Add steps to the job 25 | # See: https://circleci.com/docs/2.0/configuration-reference/#steps 26 | steps: 27 | - checkout 28 | 29 | - run: 30 | name: Prepare 31 | command: | 32 | sudo apt update 33 | sudo docker-php-ext-install zip 34 | sudo composer self-update 35 | composer install -n --prefer-dist 36 | composer dump-autoload --optimize 37 | - run: 38 | name: Run tests 39 | command: | 40 | composer run test -------------------------------------------------------------------------------- /.php_cs.dist.php: -------------------------------------------------------------------------------- 1 | in([ 5 | __DIR__ . '/src', 6 | __DIR__ . '/tests', 7 | ]) 8 | ->name('*.php') 9 | ->notName('*.blade.php') 10 | ->ignoreDotFiles(true) 11 | ->ignoreVCS(true); 12 | 13 | return (new PhpCsFixer\Config()) 14 | ->setRules([ 15 | '@PSR12' => true, 16 | 'array_syntax' => ['syntax' => 'short'], 17 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 18 | 'no_unused_imports' => true, 19 | 'not_operator_with_successor_space' => true, 20 | 'trailing_comma_in_multiline' => true, 21 | 'phpdoc_scalar' => true, 22 | 'unary_operator_spaces' => true, 23 | 'binary_operator_spaces' => true, 24 | 'blank_line_before_statement' => [ 25 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 26 | ], 27 | 'phpdoc_single_line_var_spacing' => true, 28 | 'phpdoc_var_without_name' => true, 29 | 'class_attributes_separation' => [ 30 | 'elements' => [ 31 | 'method' => 'one', 32 | ], 33 | ], 34 | 'method_argument_space' => [ 35 | 'on_multiline' => 'ensure_fully_multiline', 36 | 'keep_multiple_spaces_after_comma' => true, 37 | ], 38 | 'single_trait_insert_per_statement' => true, 39 | ]) 40 | ->setFinder($finder); 41 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `loops` will be documented in this file. 4 | 5 | ## v3.0 - 2022-01-01 6 | 7 | - removed ``stop()`` method from ``Loop`` class 8 | - added ``symfony/var-dumper`` to dev requirements 9 | - added interfaces 10 | - add chain methods 11 | - async support 12 | 13 | ## v2.2 - 2022-01-01 14 | 15 | - updated index model 16 | - added NotWorkedException 17 | - updated index model 18 | 19 | ## v2.0 - 2022-01-01 20 | 21 | - replace object to model in loop callback argument 22 | - fix iteration number 23 | - add break() method in loop class 24 | - rename test variables 25 | - callback is now can set nullable 26 | - deprecated stop() method 27 | - added LoopCallback interface 28 | - added seed parameter to loop_random helper 29 | 30 | ## 1.0.0 - 2021-09-30 31 | 32 | - initial release 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) İsa Eken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 11 | Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 14 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Loops 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/isaeken/loops.svg?style=flat-square)](https://packagist.org/packages/isaeken/loops) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/isaeken/loops/run-tests?label=tests)](https://github.com/isaeken/loops/actions?query=workflow%3Arun-tests+branch%3Amain) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/isaeken/loops/Check%20&%20fix%20styling?label=code%20style)](https://github.com/isaeken/loops/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/isaeken/loops.svg?style=flat-square)](https://packagist.org/packages/isaeken/loops) 7 | 8 | ## Installation 9 | 10 | You can install the package via composer: 11 | 12 | ```bash 13 | composer require isaeken/loops 14 | ``` 15 | 16 | ## Usage 17 | 18 | ### Basic Usage 19 | 20 | ````php 21 | loop(5, function (\IsaEken\Loops\Index $index) { 22 | return $index->odd; 23 | }); // [false, true, false, true, false] 24 | ```` 25 | 26 | ### Async Usage 27 | 28 | ````php 29 | $loop = async_loop(5, function (\IsaEken\Loops\Index $index) { 30 | return $index->even; 31 | }); 32 | 33 | // ... 34 | 35 | await($loop); // [true, false, true, false, true] 36 | ```` 37 | 38 | ### Using with class method 39 | 40 | ```php 41 | $callback = new class implements \IsaEken\Loops\Contracts\LoopCallback { 42 | public function __invoke(Index $index, Loop $loop = null): int 43 | { 44 | return $index->index; 45 | } 46 | }; 47 | 48 | $loop = new Loop(2, $callback); 49 | $loop->run(); 50 | $loop->results(); // [0, 1] 51 | ``` 52 | 53 | ### Get current loop 54 | 55 | ````php 56 | loop(2 ,function (\IsaEken\Loops\Index $index, \IsaEken\Loops\Loop $loop) { 57 | return [ 58 | 'iteration' => $index->iteration, 59 | 'index' => $index->index, 60 | 'remaining' => $index->remaining, 61 | 'count' => $index->count, 62 | 'first' => $index->first, 63 | 'last' => $index->last, 64 | 'odd' => $index->odd, 65 | 'even' => $index->even, 66 | ]; 67 | }); 68 | // [ 69 | // [ 70 | // 'iteration' => 1, 71 | // 'index' => 0, 72 | // 'remaining' => 1, 73 | // 'count' => 2, 74 | // 'first' => true, 75 | // 'last' => false, 76 | // 'odd' => false, 77 | // 'even' => true, 78 | // ], 79 | // [ 80 | // 'iteration' => 2, 81 | // 'index' => 1, 82 | // 'remaining' => 0, 83 | // 'count' => 2, 84 | // 'first' => false, 85 | // 'last' => true, 86 | // 'odd' => true, 87 | // 'even' => false, 88 | // ] 89 | // ] 90 | ```` 91 | 92 | ### Break the loop 93 | 94 | ````php 95 | loop(3, function (\IsaEken\Loops\Index $index, \IsaEken\Loops\Loop $loop) { 96 | if ($index->index > 1) { 97 | $loop->break(); 98 | } 99 | 100 | return $index->index; 101 | }); // [0, 1] 102 | ```` 103 | 104 | ### Loop random times 105 | 106 | ````php 107 | loop_random(function (\IsaEken\Loops\Index $index, \IsaEken\Loops\Loop $loop) { 108 | return $index->index; 109 | }); // executed random times. 110 | 111 | $min = 5; 112 | $max = 10; 113 | 114 | loop_random(function (\IsaEken\Loops\Index $index, \IsaEken\Loops\Loop $loop) { 115 | return $index->index; 116 | }, $min, $max); 117 | ```` 118 | 119 | ### Loop random with seed 120 | 121 | ```php 122 | loop_random(function (\IsaEken\Loops\Index $index) { 123 | return $index->even; 124 | }, seed: 123456789); 125 | ``` 126 | 127 | ## Changelog 128 | 129 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 130 | 131 | ## Contributing 132 | 133 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 134 | 135 | ## Security Vulnerabilities 136 | 137 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 138 | 139 | ## Credits 140 | 141 | - [Isa Eken](https://github.com/isaeken) 142 | - [All Contributors](../../contributors) 143 | 144 | ## License 145 | 146 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 147 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isaeken/loops", 3 | "version": "v3.1.3", 4 | "description": "Basic loops library", 5 | "keywords": [ 6 | "loops", 7 | "library", 8 | "isaeken" 9 | ], 10 | "homepage": "https://github.com/isaeken/loops", 11 | "type": "library", 12 | "license": "MIT", 13 | "minimum-stability": "dev", 14 | "prefer-stable": true, 15 | "authors": [ 16 | { 17 | "name": "İsa Eken", 18 | "email": "hello@isaeken.com.tr", 19 | "role": "Founder", 20 | "homepage": "https://www.isaeken.com.tr" 21 | } 22 | ], 23 | "require": { 24 | "php": "^8.0", 25 | "illuminate/collections": "^8.77|^9.0", 26 | "illuminate/support": "^8.77|^9.0" 27 | }, 28 | "require-dev": { 29 | "pestphp/pest": "^1.20" 30 | }, 31 | "suggest": { 32 | "spatie/async": "For async loop" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "IsaEken\\Loops\\": "src" 37 | }, 38 | "files": [ 39 | "src/helpers.php" 40 | ] 41 | }, 42 | "autoload-dev": { 43 | "psr-4": { 44 | "IsaEken\\Loops\\Tests\\": "tests" 45 | } 46 | }, 47 | "scripts": { 48 | "test": "./vendor/bin/pest --no-coverage", 49 | "test-coverage": "./vendor/bin/phpunit --coverage-html coverage" 50 | }, 51 | "config": { 52 | "sort-packages": true, 53 | "allow-plugins": { 54 | "pestphp/pest-plugin": true 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Contracts/Arrayable.php: -------------------------------------------------------------------------------- 1 | attributes[$name] = $value; 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * Get attribute value. 44 | * 45 | * @param string $name 46 | * @param mixed $default 47 | * @return mixed 48 | */ 49 | public function getAttribute(string $name, mixed $default = null): mixed 50 | { 51 | if (! array_key_exists($name, $this->attributes)) { 52 | return $default; 53 | } 54 | 55 | return $this->attributes[$name]; 56 | } 57 | 58 | /** 59 | * Fill attributes from array. 60 | * 61 | * @param array $attributes 62 | * @return void 63 | */ 64 | public function fill(array $attributes): self 65 | { 66 | foreach ($attributes as $key => $value) { 67 | $this->setAttribute($key, $value); 68 | } 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Create the Index instance. 75 | * 76 | * @param array $attributes 77 | */ 78 | public function __construct(array $attributes = []) 79 | { 80 | $this->fill($attributes); 81 | } 82 | 83 | public function __set(string $name, $value): void 84 | { 85 | $this->setAttribute($name, $value); 86 | } 87 | 88 | public function __get(string $name) 89 | { 90 | return $this->getAttribute($name); 91 | } 92 | 93 | /** 94 | * @inheritDoc 95 | */ 96 | public function toArray(): array 97 | { 98 | return $this->attributes; 99 | } 100 | 101 | /** 102 | * @inheritDoc 103 | */ 104 | public function toJson(): string 105 | { 106 | return json_encode($this->toArray()); 107 | } 108 | 109 | /** 110 | * @inheritDoc 111 | */ 112 | public function __toString() 113 | { 114 | return $this->toJson(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Loop.php: -------------------------------------------------------------------------------- 1 | setLength($length); 41 | $this->setCallback($callback); 42 | 43 | if ($this->worker === null) { 44 | $this->setWorker(new DefaultWorker()); 45 | } 46 | } 47 | 48 | /** 49 | * @inheritDoc 50 | */ 51 | public function getLength(): int 52 | { 53 | return $this->length; 54 | } 55 | 56 | /** 57 | * @inheritDoc 58 | */ 59 | public function setLength(int $length): self 60 | { 61 | $this->length = $length; 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * @inheritDoc 68 | */ 69 | public function getCallback(): LoopCallback|Closure|SerializableClosure|null 70 | { 71 | return $this->callback; 72 | } 73 | 74 | /** 75 | * @inheritDoc 76 | */ 77 | public function setCallback(Closure|LoopCallback|SerializableClosure|null $callback = null): self 78 | { 79 | $this->callback = $callback; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * @inheritDoc 86 | */ 87 | public function getWorker(): Workable 88 | { 89 | return $this->worker; 90 | } 91 | 92 | /** 93 | * @inheritDoc 94 | */ 95 | public function setWorker(Workable|string $worker): self 96 | { 97 | if ($worker instanceof Workable) { 98 | $this->worker = $worker; 99 | } else { 100 | $this->worker = new $worker(); 101 | } 102 | 103 | $this->worker->setLooper($this); 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * @inheritDoc 110 | */ 111 | public function run(): self 112 | { 113 | $this->worker->work($this->callback); 114 | 115 | return $this; 116 | } 117 | 118 | /** 119 | * @inheritDoc 120 | */ 121 | public function results(): array 122 | { 123 | return $this->worker->results(); 124 | } 125 | 126 | /** 127 | * @inheritDoc 128 | */ 129 | public function break(): self 130 | { 131 | $this->worker->break(); 132 | 133 | return $this; 134 | } 135 | 136 | /** 137 | * @inheritDoc 138 | */ 139 | public function toArray(): array 140 | { 141 | return $this->worker->toArray(); 142 | } 143 | 144 | /** 145 | * @inheritDoc 146 | */ 147 | public function toJson(): string 148 | { 149 | return $this->worker->toJson(); 150 | } 151 | 152 | /** 153 | * @inheritDoc 154 | */ 155 | public function __toString() 156 | { 157 | return $this->worker->__toString(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Workers/AsyncWorker.php: -------------------------------------------------------------------------------- 1 | looper; 61 | } 62 | 63 | /** 64 | * @inheritDoc 65 | */ 66 | public function setLooper(Looper $looper): self 67 | { 68 | $this->looper = $looper; 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * @inheritDoc 75 | */ 76 | public function work(Closure|LoopCallback|SerializableClosure|null $callback = null): Pool 77 | { 78 | $pool = new Pool(); 79 | $results = collect(); 80 | 81 | for ($index = 0; $index < $this->getLooper()->getLength(); $index++) { 82 | $pool->add(function () use ($callback, $results, $pool) { 83 | if ($callback === null) { 84 | $result = null; 85 | } elseif ($callback instanceof LoopCallback) { 86 | $result = call_user_func($callback, clone $this->getIndex(), $this->getLooper()); 87 | } elseif ($callback instanceof SerializableClosure) { 88 | $result = $callback->getClosure()->call($this->getLooper(), clone $this->getIndex(), $this->getLooper()); 89 | } else { 90 | $result = $callback->call($this->getLooper(), clone $this->getIndex(), $this->getLooper()); 91 | } 92 | 93 | $results->add($result); 94 | $this->increment(); 95 | 96 | if ($this->breaked) { 97 | $pool->stop(); 98 | } 99 | 100 | return $result; 101 | })->then(function () use ($results) { 102 | $this->results = $results->toArray(); 103 | $this->worked = true; 104 | }); 105 | } 106 | 107 | return $pool; 108 | } 109 | 110 | /** 111 | * @inheritDoc 112 | */ 113 | public function break(): self 114 | { 115 | $this->breaked = true; 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * @inheritDoc 122 | */ 123 | public function results(): array 124 | { 125 | if (! $this->worked) { 126 | throw new NotWorkedException(); 127 | } 128 | 129 | return $this->results; 130 | } 131 | 132 | /** 133 | * @inheritDoc 134 | */ 135 | public function getIndex(): Index 136 | { 137 | if ($this->index === null) { 138 | $this->index = new Index([ 139 | 'iteration' => 1, 140 | 'index' => 0, 141 | 'remaining' => $this->getLooper()->getLength() - 1 ?? 0, 142 | 'count' => $this->getLooper()->getLength(), 143 | 'first' => true, 144 | 'last' => $this->getLooper()->getLength() === 1, 145 | 'even' => true, 146 | 'odd' => false, 147 | ]); 148 | } 149 | 150 | return $this->index; 151 | } 152 | 153 | /** 154 | * @inheritDoc 155 | */ 156 | public function setIndex(Index|array $index): self 157 | { 158 | $attributes = $index instanceof Index ? $index->toArray() : $index; 159 | if ($this->index instanceof Index) { 160 | $this->index->fill($attributes); 161 | } else { 162 | $this->index = new Index($attributes); 163 | } 164 | 165 | return $this; 166 | } 167 | 168 | /** 169 | * @inheritDoc 170 | */ 171 | public function increment(int $count = 1): self 172 | { 173 | for ($i = $count; $i > 0; $i--) { 174 | $this->index->iteration += 1; 175 | $this->index->index += 1; 176 | $this->index->remaining -= 1; 177 | $this->index->first = $this->index->index === 0; 178 | $this->index->last = $this->index->iteration === $this->index->count; 179 | $this->index->even = $this->index->index % 2 == 0; 180 | $this->index->odd = ! $this->index->even; 181 | } 182 | 183 | return $this; 184 | } 185 | 186 | /** 187 | * @inheritDoc 188 | */ 189 | public function toArray(): array 190 | { 191 | return $this->results(); 192 | } 193 | 194 | /** 195 | * @inheritDoc 196 | */ 197 | public function toJson(): string 198 | { 199 | return json_encode($this->toArray()); 200 | } 201 | 202 | /** 203 | * @inheritDoc 204 | */ 205 | public function __toString() 206 | { 207 | return $this->toJson(); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/Workers/DefaultWorker.php: -------------------------------------------------------------------------------- 1 | looper; 60 | } 61 | 62 | /** 63 | * @inheritDoc 64 | */ 65 | public function setLooper(Looper $looper): self 66 | { 67 | $this->looper = $looper; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * @inheritDoc 74 | */ 75 | public function work(Closure|LoopCallback|SerializableClosure|null $callback = null): self 76 | { 77 | $this->worked = false; 78 | $this->results = []; 79 | 80 | for ($index = 0; $index < $this->getLooper()->getLength(); $index++) { 81 | if ($callback === null) { 82 | $this->results[] = null; 83 | } elseif ($callback instanceof LoopCallback) { 84 | $this->results[] = call_user_func($callback, clone $this->getIndex(), $this->getLooper()); 85 | } elseif ($callback instanceof SerializableClosure) { 86 | $this->results[] = $callback->getClosure()->call($this->getLooper(), clone $this->getIndex(), $this->getLooper()); 87 | } else { 88 | $this->results[] = $callback->call($this->getLooper(), clone $this->getIndex(), $this->getLooper()); 89 | } 90 | 91 | $this->increment(); 92 | 93 | if ($this->breaked) { 94 | break; 95 | } 96 | } 97 | 98 | $this->worked = true; 99 | 100 | return $this; 101 | } 102 | 103 | /** 104 | * @inheritDoc 105 | */ 106 | public function break(): self 107 | { 108 | $this->breaked = true; 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * @inheritDoc 115 | */ 116 | public function results(): array 117 | { 118 | if (! $this->worked) { 119 | throw new NotWorkedException(); 120 | } 121 | 122 | return $this->results; 123 | } 124 | 125 | /** 126 | * @inheritDoc 127 | */ 128 | public function getIndex(): Index 129 | { 130 | if ($this->index === null) { 131 | $this->index = new Index([ 132 | 'iteration' => 1, 133 | 'index' => 0, 134 | 'remaining' => $this->getLooper()->getLength() - 1 ?? 0, 135 | 'count' => $this->getLooper()->getLength(), 136 | 'first' => true, 137 | 'last' => $this->getLooper()->getLength() === 1, 138 | 'even' => true, 139 | 'odd' => false, 140 | ]); 141 | } 142 | 143 | return $this->index; 144 | } 145 | 146 | /** 147 | * @inheritDoc 148 | */ 149 | public function setIndex(Index|array $index): self 150 | { 151 | $attributes = $index instanceof Index ? $index->toArray() : $index; 152 | if ($this->index instanceof Index) { 153 | $this->index->fill($attributes); 154 | } else { 155 | $this->index = new Index($attributes); 156 | } 157 | 158 | return $this; 159 | } 160 | 161 | /** 162 | * @inheritDoc 163 | */ 164 | public function increment(int $count = 1): self 165 | { 166 | for ($i = $count; $i > 0; $i--) { 167 | $this->index->iteration += 1; 168 | $this->index->index += 1; 169 | $this->index->remaining -= 1; 170 | $this->index->first = $this->index->index === 0; 171 | $this->index->last = $this->index->iteration === $this->index->count; 172 | $this->index->even = $this->index->index % 2 == 0; 173 | $this->index->odd = ! $this->index->even; 174 | } 175 | 176 | return $this; 177 | } 178 | 179 | /** 180 | * @inheritDoc 181 | */ 182 | public function toArray(): array 183 | { 184 | return $this->results(); 185 | } 186 | 187 | /** 188 | * @inheritDoc 189 | */ 190 | public function toJson(): string 191 | { 192 | return json_encode($this->toArray()); 193 | } 194 | 195 | /** 196 | * @inheritDoc 197 | */ 198 | public function __toString() 199 | { 200 | return $this->toJson(); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/helpers.php: -------------------------------------------------------------------------------- 1 | run(); 21 | 22 | return $loop->results(); 23 | } 24 | } 25 | 26 | if (! function_exists('loop_random')) { 27 | /** 28 | * Call the loop function random times. 29 | * 30 | * @param LoopCallback|Closure|SerializableClosure|null $callback 31 | * @param int|null $min 32 | * @param int|null $max 33 | * @param int|null $seed 34 | * @return array 35 | */ 36 | function loop_random(LoopCallback|Closure|SerializableClosure|null $callback, int|null $min = null, int|null $max = null, int|null $seed = null): array 37 | { 38 | if ($seed === null) { 39 | $seed = time(); 40 | } 41 | 42 | srand($seed); 43 | 44 | if ($min === null) { 45 | $min = 0; 46 | } 47 | 48 | if ($max === null) { 49 | $max = rand($min, $min + 99); 50 | } 51 | 52 | return loop(rand($min, $max), $callback); 53 | } 54 | } 55 | 56 | if (! function_exists('async_loop')) { 57 | function async_loop(int $length, LoopCallback|Closure|SerializableClosure|null $callback): \Spatie\Async\Pool 58 | { 59 | $loop = new Loop($length, $callback); 60 | $loop->setWorker(AsyncWorker::class); 61 | 62 | return $loop->getWorker()->work($loop->getCallback()); 63 | } 64 | } 65 | 66 | if (! function_exists('async_loop_random')) { 67 | function async_loop_random(LoopCallback|Closure|SerializableClosure|null $callback, int|null $min = null, int|null $max = null, int|null $seed = null): \Spatie\Async\Pool 68 | { 69 | if ($seed === null) { 70 | $seed = time(); 71 | } 72 | 73 | srand($seed); 74 | 75 | if ($min === null) { 76 | $min = 0; 77 | } 78 | 79 | if ($max === null) { 80 | $max = rand($min, $min + 99); 81 | } 82 | 83 | return async_loop(rand($min, $max), $callback); 84 | } 85 | } 86 | --------------------------------------------------------------------------------