From 90ba3ec059f5cd6f9b1df26b12bae0cee4d44fec Mon Sep 17 00:00:00 2001 From: Dusan Kasan Date: Fri, 17 Apr 2020 23:52:50 +0200 Subject: [PATCH] psalm type annotations, implemented, support for 7.1 and older dropped --- composer.json | 16 +- composer.lock | 1853 ++++++++++++++++++++++++++------- phpspec.yml | 3 - psalm.xml | 16 + src/Collection.php | 59 +- src/CollectionInterface.php | 186 ++-- src/CollectionTrait.php | 438 ++++---- src/RewindableIterable.php | 42 + src/collection_functions.php | 1056 +++++++++++-------- src/utility_functions.php | 23 + tests/spec/CollectionSpec.php | 12 +- 11 files changed, 2546 insertions(+), 1158 deletions(-) create mode 100644 psalm.xml create mode 100644 src/RewindableIterable.php diff --git a/composer.json b/composer.json index 951fc70..e04c69d 100644 --- a/composer.json +++ b/composer.json @@ -14,16 +14,16 @@ } ], "require-dev": { - "phpspec/phpspec": "^3.4", - "henrikbjorn/phpspec-code-coverage": "^3.0", - "squizlabs/php_codesniffer": "^3.4", - "phpmd/phpmd" : "^2.0", - "ciaranmcnulty/phpspec-typehintedmethods": "^2.0", - "phpunit/phpunit": "^5.7", - "symfony/console": "^2.7" + "phpspec/phpspec": "^6.1", + "friends-of-phpspec/phpspec-code-coverage": "^4.3", + "squizlabs/php_codesniffer": "^3.5", + "phpmd/phpmd" : "^2.8", + "phpunit/phpunit": "^8.5", + "symfony/console": "^5.0", + "vimeo/psalm": "^3.11" }, "require": { - "php": ">=5.6.0" + "php": ">=7.2" }, "autoload": { "files": [ diff --git a/composer.lock b/composer.lock index e6c9bce..e517c0b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,35 +4,125 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a344b2e43e6ad7d5efbd6d9e76622eee", + "content-hash": "13717daf9a9bb7617e5e29715e7c2d4e", "packages": [], "packages-dev": [ { - "name": "ciaranmcnulty/phpspec-typehintedmethods", - "version": "2.0.0", + "name": "amphp/amp", + "version": "v2.4.2", "source": { "type": "git", - "url": "https://github.com/ciaranmcnulty/phpspec-typehintedmethods.git", - "reference": "3b0ae89c7717d7809516af4bb6c1faaf61f667e3" + "url": "https://github.com/amphp/amp.git", + "reference": "feca077369a47263b22156b3c6389e55f3809f24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ciaranmcnulty/phpspec-typehintedmethods/zipball/3b0ae89c7717d7809516af4bb6c1faaf61f667e3", - "reference": "3b0ae89c7717d7809516af4bb6c1faaf61f667e3", + "url": "https://api.github.com/repos/amphp/amp/zipball/feca077369a47263b22156b3c6389e55f3809f24", + "reference": "feca077369a47263b22156b3c6389e55f3809f24", "shasum": "" }, "require": { - "phpspec/phpspec": "~3.0" + "php": ">=7" }, "require-dev": { - "behat/behat": "~3.0", - "symfony/filesystem": "~3.0" + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6.0.9 | ^7", + "react/promise": "^2", + "vimeo/psalm": "^3.9@dev" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, "autoload": { "psr-4": { - "Cjm\\PhpSpec\\": "src/" + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "time": "2020-04-04T15:05:26+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.7.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "b867505edb79dda8f253ca3c3a2bbadae4b16592" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/b867505edb79dda8f253ca3c3a2bbadae4b16592", + "reference": "b867505edb79dda8f253ca3c3a2bbadae4b16592", + "shasum": "" + }, + "require": { + "amphp/amp": "^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "vimeo/psalm": "^3.9@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -40,20 +130,86 @@ ], "authors": [ { - "name": "Ciaran McNulty", - "email": "mail@ciaranmcnulty.com", - "homepage": "http://ciaranmcnulty.com", - "role": "Developer" + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" } ], - "description": "Extension for phpspec to enhance generated methods", - "homepage": "http://github.com/ciaranmcnulty/phpspec-typehintedmethods", + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", "keywords": [ - "BDD", - "TDD", - "phpspec" + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "time": "2020-04-04T16:56:54+00:00" + }, + { + "name": "composer/semver", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5 || ^5.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "time": "2016-08-12T14:21:22+00:00" + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "time": "2020-01-13T12:06:48+00:00" }, { "name": "composer/xdebug-handler", @@ -156,47 +312,174 @@ "time": "2019-10-21T16:45:58+00:00" }, { - "name": "henrikbjorn/phpspec-code-coverage", - "version": "3.0.1", + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.1.1", "source": { "type": "git", - "url": "https://github.com/henrikbjorn/PhpSpecCodeCoverageExtension.git", - "reference": "4e878b81c0d28494882ecb7e9403ac5cbaa6cc1b" + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/henrikbjorn/PhpSpecCodeCoverageExtension/zipball/4e878b81c0d28494882ecb7e9403ac5cbaa6cc1b", - "reference": "4e878b81c0d28494882ecb7e9403ac5cbaa6cc1b", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40", + "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40", "shasum": "" }, "require": { - "php": "^5.5|^5.6|^7.0", - "phpspec/phpspec": "^3.0", - "phpunit/php-code-coverage": "^4.0" + "netresearch/jsonmapper": "^1.0 || ^2.0", + "php": ">=7.0", + "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" }, "require-dev": { - "bossa/phpspec2-expect": "dev-master" + "phpunit/phpunit": "^6.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "time": "2020-03-11T15:21:41+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpstan/phpstan": "*", + "phpunit/phpunit": "^6.3", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "time": "2019-06-23T21:03:50+00:00" + }, + { + "name": "friends-of-phpspec/phpspec-code-coverage", + "version": "v4.3.2", + "source": { + "type": "git", + "url": "https://github.com/friends-of-phpspec/phpspec-code-coverage.git", + "reference": "9a54302573094cc1b3bdca3cc78c58582130b254" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/friends-of-phpspec/phpspec-code-coverage/zipball/9a54302573094cc1b3bdca3cc78c58582130b254", + "reference": "9a54302573094cc1b3bdca3cc78c58582130b254", + "shasum": "" + }, + "require": { + "php": "^7.1", + "phpspec/phpspec": "^4.2 || ^5.0 || ^6.0", + "phpunit/php-code-coverage": "^5.0 || ^6.0 || ^7.0" + }, + "require-dev": { + "drupol/php-conventions": "^1", + "scrutinizer/ocular": "^1" }, "suggest": { - "ext-xdebug": "To allow coverage generation when not using a recent version of phpdbg" + "ext-pcov": "Install PCov extension to generate code coverage.", + "ext-xdebug": "Install Xdebug to generate phpspec code coverage." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.x-dev" } }, "autoload": { "psr-4": { - "PhpSpecCodeCoverage\\": "src/" - } + "FriendsOfPhpSpec\\PhpSpec\\CodeCoverage\\": "src/" + }, + "files": [ + "src/bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Integrates CodeCoverage with PhpSpec", - "time": "2016-08-02T06:07:43+00:00" + "authors": [ + { + "name": "ek9", + "email": "dev@ek9.co", + "homepage": "https://ek9.co" + }, + { + "name": "Henrik Bjornskov" + }, + { + "name": "Stéphane Hulard", + "email": "s.hulard@chstudio.fr", + "homepage": "https://chstudio.fr" + }, + { + "name": "Pol Dellaiera", + "email": "pol.dellaiera@protonmail.com", + "homepage": "https://not-a-number.io/" + }, + { + "name": "Jay Linski", + "homepage": "https://twitter.com/jay_linski" + } + ], + "description": "Generate Code Coverage reports for PhpSpec tests", + "homepage": "https://github.com/friends-of-phpspec/phpspec-code-coverage", + "keywords": [ + "code-coverage", + "coverage", + "phpspec", + "report", + "spec", + "test", + "tests" + ], + "time": "2019-11-12T10:27:45+00:00" }, { "name": "myclabs/deep-copy", @@ -246,6 +529,204 @@ ], "time": "2020-01-17T21:11:47+00:00" }, + { + "name": "netresearch/jsonmapper", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "e245890383c3ed38b6d202ee373c23ccfebc0f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e245890383c3ed38b6d202ee373c23ccfebc0f54", + "reference": "e245890383c3ed38b6d202ee373c23ccfebc0f54", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "time": "2020-03-04T17:23:33+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "reference": "bd43ec7152eaaab3bd8c6d0aa95ceeb1df8ee120", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2020-04-10T16:34:50+00:00" + }, + { + "name": "ocramius/package-versions", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "421679846270a5772534828013a93be709fb13df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/421679846270a5772534828013a93be709fb13df", + "reference": "421679846270a5772534828013a93be709fb13df", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7.4.0" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "doctrine/coding-standard": "^7.0.2", + "ext-zip": "^1.15.0", + "infection/infection": "^0.15.3", + "phpunit/phpunit": "^9.0.1", + "vimeo/psalm": "^3.9.3" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.99.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2020-04-06T17:43:35+00:00" + }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "time": "2019-03-29T20:06:56+00:00" + }, { "name": "pdepend/pdepend", "version": "2.7.1", @@ -285,13 +766,115 @@ "psr-4": { "PDepend\\": "src/main/php/PDepend" } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Official version of pdepend to be handled with Composer", + "time": "2020-02-08T12:06:13+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2018-07-08T19:23:20+00:00" + }, + { + "name": "phar-io/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } ], - "description": "Official version of pdepend to be handled with Composer", - "time": "2020-02-08T12:06:13+00:00" + "description": "Library for handling version information and constraints", + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -554,36 +1137,38 @@ }, { "name": "phpspec/phpspec", - "version": "3.4.3", + "version": "6.1.1", "source": { "type": "git", "url": "https://github.com/phpspec/phpspec.git", - "reference": "8e72ed3576f6e26baebb2c214a8dba344508e3bd" + "reference": "486aaa736e9e24f3e22a6545f6affb88f98e2602" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/phpspec/zipball/8e72ed3576f6e26baebb2c214a8dba344508e3bd", - "reference": "8e72ed3576f6e26baebb2c214a8dba344508e3bd", + "url": "https://api.github.com/repos/phpspec/phpspec/zipball/486aaa736e9e24f3e22a6545f6affb88f98e2602", + "reference": "486aaa736e9e24f3e22a6545f6affb88f98e2602", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.1", + "doctrine/instantiator": "^1.0.5", "ext-tokenizer": "*", - "php": "^5.6 || ^7.0", + "php": "^7.2, <7.5", "phpspec/php-diff": "^1.0.0", - "phpspec/prophecy": "^1.5", + "phpspec/prophecy": "^1.9", "sebastian/exporter": "^1.0 || ^2.0 || ^3.0", - "symfony/console": "^2.7 || ^3.0", - "symfony/event-dispatcher": "^2.7 || ^3.0", - "symfony/finder": "^2.7 || ^3.0", - "symfony/process": "^2.7 || ^3.0", - "symfony/yaml": "^2.7 || ^3.0" + "symfony/console": "^3.4 || ^4.0 || ^5.0", + "symfony/event-dispatcher": "^3.4 || ^4.0 || ^5.0", + "symfony/finder": "^3.4 || ^4.0 || ^5.0", + "symfony/process": "^3.4 || ^4.0 || ^5.0", + "symfony/yaml": "^3.4 || ^4.0 || ^5.0" + }, + "conflict": { + "sebastian/comparator": "<1.2.4" }, "require-dev": { "behat/behat": "^3.3", - "ciaranmcnulty/versionbasedtestskipper": "^0.2.1", - "phpunit/phpunit": "^5.5|^6.0", - "symfony/filesystem": "^3.0" + "phpunit/phpunit": "^7.0", + "symfony/filesystem": "^3.4 || ^4.0 || ^5.0" }, "suggest": { "phpspec/nyan-formatters": "Adds Nyan formatters" @@ -594,7 +1179,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "6.1.x-dev" } }, "autoload": { @@ -621,7 +1206,7 @@ "homepage": "https://ciaranmcnulty.com/" } ], - "description": "Specification-oriented BDD framework for PHP 5.6+", + "description": "Specification-oriented BDD framework for PHP 7.1+", "homepage": "http://phpspec.net/", "keywords": [ "BDD", @@ -632,20 +1217,20 @@ "testing", "tests" ], - "time": "2017-12-06T09:12:11+00:00" + "time": "2019-12-17T10:23:12+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.10.2", + "version": "v1.10.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" + "reference": "451c3cd1418cf640de218914901e51b064abb093" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", - "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", "shasum": "" }, "require": { @@ -695,44 +1280,44 @@ "spy", "stub" ], - "time": "2020-01-20T15:57:02+00:00" + "time": "2020-03-05T15:02:03+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "4.0.8", + "version": "7.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "^1.3", - "phpunit/php-text-template": "^1.2", - "phpunit/php-token-stream": "^1.4.2 || ^2.0", - "sebastian/code-unit-reverse-lookup": "^1.0", - "sebastian/environment": "^1.3.2 || ^2.0", - "sebastian/version": "^1.0 || ^2.0" + "php": "^7.2", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.1.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^4.2.2", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "ext-xdebug": "^2.1.4", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.5.1" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -747,7 +1332,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -758,29 +1343,32 @@ "testing", "xunit" ], - "time": "2017-04-02T07:44:40+00:00" + "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -795,7 +1383,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -805,7 +1393,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", @@ -850,28 +1438,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.9", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -886,7 +1474,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -895,33 +1483,33 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.2", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -944,55 +1532,56 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T05:48:46+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "5.7.27", + "version": "8.5.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" + "reference": "67750516bc02f300e2742fed2f50177f8f37bedf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", - "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/67750516bc02f300e2742fed2f50177f8f37bedf", + "reference": "67750516bc02f300e2742fed2f50177f8f37bedf", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.6.2", - "phpunit/php-code-coverage": "^4.0.4", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "^3.2", - "sebastian/comparator": "^1.2.4", - "sebastian/diff": "^1.4.3", - "sebastian/environment": "^1.3.4 || ^2.0", - "sebastian/exporter": "~2.0", - "sebastian/global-state": "^1.1", - "sebastian/object-enumerator": "~2.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "^1.0.6|^2.0.1", - "symfony/yaml": "~2.1|~3.0|~4.0" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.2", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.1", + "sebastian/global-state": "^3.0.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", + "sebastian/version": "^2.0.1" }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "~1.1" + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -1000,7 +1589,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.7.x-dev" + "dev-master": "8.5-dev" } }, "autoload": { @@ -1026,83 +1615,73 @@ "testing", "xunit" ], - "time": "2018-02-01T05:50:59+00:00" + "time": "2020-03-31T08:52:04+00:00" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "3.4.4", + "name": "psr/container", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" - }, - "conflict": { - "phpunit/phpunit": "<5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-soap": "*" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Psr\\Container\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", "keywords": [ - "mock", - "xunit" + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" ], - "time": "2017-06-30T09:13:00+00:00" + "time": "2017-02-14T16:28:37+00:00" }, { - "name": "psr/container", + "name": "psr/event-dispatcher", "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.2.0" }, "type": "library", "extra": { @@ -1112,7 +1691,7 @@ }, "autoload": { "psr-4": { - "Psr\\Container\\": "src/" + "Psr\\EventDispatcher\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1125,29 +1704,26 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", + "description": "Standard interfaces for event handling.", "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" + "events", + "psr", + "psr-14" ], - "time": "2017-02-14T16:28:37+00:00" + "time": "2019-01-08T18:20:26+00:00" }, { "name": "psr/log", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", + "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", "shasum": "" }, "require": { @@ -1181,7 +1757,7 @@ "psr", "psr-3" ], - "time": "2019-11-01T11:05:21+00:00" + "time": "2020-03-23T09:12:05+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1230,30 +1806,30 @@ }, { "name": "sebastian/comparator", - "version": "1.2.4", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1284,38 +1860,39 @@ } ], "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", "equality" ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "1.4.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1340,34 +1917,40 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", - "version": "2.0.0", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^5.0" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -1392,34 +1975,34 @@ "environment", "hhvm" ], - "time": "2016-11-26T07:53:53+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", - "version": "2.0.0", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~2.0" + "php": "^7.0", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -1432,6 +2015,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1440,17 +2027,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -1459,27 +2042,30 @@ "export", "exporter" ], - "time": "2016-11-19T08:54:04+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", - "version": "1.1.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "ext-dom": "*", + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -1487,7 +2073,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1510,33 +2096,34 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", - "version": "2.0.1", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", "shasum": "" }, "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~2.0" + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~5" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1556,32 +2143,77 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/recursion-context", - "version": "2.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -1609,29 +2241,29 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1651,7 +2283,53 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" }, { "name": "sebastian/version", @@ -1749,32 +2427,32 @@ }, { "name": "symfony/config", - "version": "v4.4.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9" + "reference": "3e633c31a34738f7f4ed7a225c43fc45ca74c986" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", - "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", + "url": "https://api.github.com/repos/symfony/config/zipball/3e633c31a34738f7f4ed7a225c43fc45ca74c986", + "reference": "3e633c31a34738f7f4ed7a225c43fc45ca74c986", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/filesystem": "^3.4|^4.0|^5.0", + "php": "^7.2.5", + "symfony/filesystem": "^4.4|^5.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<3.4" + "symfony/finder": "<4.4" }, "require-dev": { - "symfony/event-dispatcher": "^3.4|^4.0|^5.0", - "symfony/finder": "^3.4|^4.0|^5.0", - "symfony/messenger": "^4.1|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/finder": "^4.4|^5.0", + "symfony/messenger": "^4.4|^5.0", "symfony/service-contracts": "^1.1|^2", - "symfony/yaml": "^3.4|^4.0|^5.0" + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -1782,7 +2460,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1809,41 +2487,56 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2020-02-04T09:32:40+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/console", - "version": "v2.8.52", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12" + "reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12", - "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12", + "url": "https://api.github.com/repos/symfony/console/zipball/5fa1caadc8cdaa17bcfb25219f3b53fe294a9935", + "reference": "5fa1caadc8cdaa17bcfb25219f3b53fe294a9935", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/debug": "^2.7.2|~3.0.0", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1|~3.0.0", - "symfony/process": "~2.1|~3.0.0" + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" }, "suggest": { - "psr/log-implementation": "For using the console logger", + "psr/log": "For using the console logger", "symfony/event-dispatcher": "", + "symfony/lock": "", "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1870,42 +2563,58 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-11-20T15:55:20+00:00" + "time": "2020-03-30T11:42:42+00:00" }, { - "name": "symfony/debug", - "version": "v3.0.9", + "name": "symfony/dependency-injection", + "version": "v5.0.7", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "4e48dc44680d8efa357410c78093a04753196981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", - "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4e48dc44680d8efa357410c78093a04753196981", + "reference": "4e48dc44680d8efa357410c78093a04753196981", "shasum": "" }, "require": { - "php": ">=5.5.9", - "psr/log": "~1.0" + "php": "^7.2.5", + "psr/container": "^1.0", + "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/config": "<5.0", + "symfony/finder": "<4.4", + "symfony/proxy-manager-bridge": "<4.4", + "symfony/yaml": "<4.4" + }, + "provide": { + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0" }, "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" + "symfony/config": "^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/yaml": "^4.4|^5.0" + }, + "suggest": { + "symfony/config": "", + "symfony/expression-language": "For using expressions in service container configuration", + "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Symfony\\Component\\DependencyInjection\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1925,57 +2634,57 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-07-30T07:22:48+00:00" + "time": "2020-03-30T11:42:42+00:00" }, { - "name": "symfony/dependency-injection", - "version": "v3.3.18", + "name": "symfony/event-dispatcher", + "version": "v5.0.7", "source": { "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "24f40d95385774ed5c71dbf014edd047e2f2f3dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54243abc4e1a1a15e274e391bd6f7090b44711f1", - "reference": "54243abc4e1a1a15e274e391bd6f7090b44711f1", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/24f40d95385774ed5c71dbf014edd047e2f2f3dc", + "reference": "24f40d95385774ed5c71dbf014edd047e2f2f3dc", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": "^7.2.5", + "symfony/event-dispatcher-contracts": "^2" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", - "symfony/yaml": "<3.3" + "symfony/dependency-injection": "<4.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" }, "require-dev": { - "symfony/config": "~3.3", - "symfony/expression-language": "~2.8|~3.0", - "symfony/yaml": "~3.3" + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/expression-language": "^4.4|^5.0", + "symfony/http-foundation": "^4.4|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^4.4|^5.0" }, "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "5.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1995,54 +2704,41 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DependencyInjection Component", + "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-01-29T09:02:23+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.38", + "name": "symfony/event-dispatcher-contracts", + "version": "v2.0.1", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "2f67a869aef3eecf42e7f8be4a8b86c92308686c" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "af23c2584d4577d54661c434446fb8fbed6025dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2f67a869aef3eecf42e7f8be4a8b86c92308686c", - "reference": "2f67a869aef3eecf42e7f8be4a8b86c92308686c", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/af23c2584d4577d54661c434446fb8fbed6025dd", + "reference": "af23c2584d4577d54661c434446fb8fbed6025dd", "shasum": "" }, - "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, + "require": { + "php": "^7.2.5", + "psr/event-dispatcher": "^1" + }, "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "2.0-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2050,30 +2746,38 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", - "time": "2020-02-04T08:04:52+00:00" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" }, { "name": "symfony/filesystem", - "version": "v5.0.5", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c" + "reference": "ca3b87dd09fff9b771731637f5379965fbfab420" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3afadc0f57cd74f86379d073e694b0f2cda2a88c", - "reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ca3b87dd09fff9b771731637f5379965fbfab420", + "reference": "ca3b87dd09fff9b771731637f5379965fbfab420", "shasum": "" }, "require": { @@ -2110,29 +2814,29 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2020-01-21T08:40:24+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/finder", - "version": "v3.4.38", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200" + "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/5ec813ccafa8164ef21757e8c725d3a57da59200", - "reference": "5ec813ccafa8164ef21757e8c725d3a57da59200", + "url": "https://api.github.com/repos/symfony/finder/zipball/600a52c29afc0d1caa74acbec8d3095ca7e9910d", + "reference": "600a52c29afc0d1caa74acbec8d3095ca7e9910d", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.2.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2159,20 +2863,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2020-02-14T07:34:21+00:00" + "time": "2020-03-27T16:56:45+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", - "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/4719fa9c18b0464d399f1a63bf624b42b6fa8d14", + "reference": "4719fa9c18b0464d399f1a63bf624b42b6fa8d14", "shasum": "" }, "require": { @@ -2184,7 +2888,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -2217,20 +2921,20 @@ "polyfill", "portable" ], - "time": "2020-01-13T11:15:53+00:00" + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", - "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", "shasum": "" }, "require": { @@ -2242,7 +2946,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.14-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -2276,29 +2980,87 @@ "portable", "shim" ], - "time": "2020-01-13T11:15:53+00:00" + "time": "2020-03-09T19:04:49+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.15.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "reference": "0f27e9f464ea3da33cbe7ca3bdf4eb66def9d0f7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.15-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-02-27T09:26:54+00:00" }, { "name": "symfony/process", - "version": "v3.4.38", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "b03b02dcea26ba4c65c16a73bab4f00c186b13da" + "reference": "c5ca4a0fc16a0c888067d43fbcfe1f8a53d8e70e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/b03b02dcea26ba4c65c16a73bab4f00c186b13da", - "reference": "b03b02dcea26ba4c65c16a73bab4f00c186b13da", + "url": "https://api.github.com/repos/symfony/process/zipball/c5ca4a0fc16a0c888067d43fbcfe1f8a53d8e70e", + "reference": "c5ca4a0fc16a0c888067d43fbcfe1f8a53d8e70e", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.2.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2325,27 +3087,89 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2020-02-04T08:04:52+00:00" + "time": "2020-03-27T16:56:45+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" }, { "name": "symfony/yaml", - "version": "v3.3.18", + "version": "v5.0.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "af615970e265543a26ee712c958404eb9b7ac93d" + "reference": "ad5e9c83ade5bbb3a96a3f30588a0622708caefd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/af615970e265543a26ee712c958404eb9b7ac93d", - "reference": "af615970e265543a26ee712c958404eb9b7ac93d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ad5e9c83ade5bbb3a96a3f30588a0622708caefd", + "reference": "ad5e9c83ade5bbb3a96a3f30588a0622708caefd", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<4.4" }, "require-dev": { - "symfony/console": "~2.8|~3.0" + "symfony/console": "^4.4|^5.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -2353,7 +3177,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2380,7 +3204,145 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-01-20T15:04:53+00:00" + "time": "2020-03-30T11:42:42+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2019-06-13T22:48:21+00:00" + }, + { + "name": "vimeo/psalm", + "version": "3.11.1", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "8533b866ab1a46e5a69a4692ff57f10529dbfbeb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/8533b866ab1a46e5a69a4692ff57f10529dbfbeb", + "reference": "8533b866ab1a46e5a69a4692ff57f10529dbfbeb", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.1", + "amphp/byte-stream": "^1.5", + "composer/semver": "^1.4", + "composer/xdebug-handler": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.4", + "netresearch/jsonmapper": "^1.0 || ^2.0", + "nikic/php-parser": "^4.3", + "ocramius/package-versions": "^1.2", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1.3|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "webmozart/glob": "^4.1", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "amphp/amp": "^2.4.2", + "bamarni/composer-bin-plugin": "^1.2", + "brianium/paratest": "^4.0.0", + "ext-curl": "*", + "php-coveralls/php-coveralls": "^2.2", + "phpmyadmin/sql-parser": "5.1.0", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0", + "psalm/plugin-phpunit": "^0.10", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3" + }, + "suggest": { + "ext-igbinary": "^2.0.5" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psalm\\Plugin\\": "src/Psalm/Plugin", + "Psalm\\": "src/Psalm" + }, + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "time": "2020-04-13T02:19:49+00:00" }, { "name": "webmozart/assert", @@ -2429,6 +3391,99 @@ "validate" ], "time": "2020-02-14T12:15:55+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/glob.git", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1", + "symfony/filesystem": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "time": "2015-12-29T11:14:33+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "time": "2015-12-17T08:42:14+00:00" } ], "aliases": [], @@ -2437,7 +3492,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.6.0" + "php": ">=7.2" }, "platform-dev": [] } diff --git a/phpspec.yml b/phpspec.yml index 3e14869..af2c4c1 100644 --- a/phpspec.yml +++ b/phpspec.yml @@ -1,6 +1,3 @@ -extensions: - Cjm\PhpSpec\Extension\TypeHintedMethodsExtension: ~ - suites: default: spec_path: tests diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..d6c2a02 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/src/Collection.php b/src/Collection.php index 1c99d3c..25260ef 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -8,22 +8,31 @@ use IteratorAggregate; use Traversable; +/** + * @template TKey + * @template TVal + * @implements CollectionInterface + * @implements IteratorAggregate + */ class Collection implements IteratorAggregate, \Serializable, CollectionInterface { + /** + * @use CollectionTrait + */ use CollectionTrait; /** - * @var Traversable + * @var Traversable */ protected $input; /** - * @var callable + * @var callable():iterable|null */ - private $inputFactory; + private $inputFactory = null; /** - * @param callable|array|Traversable $input If callable is passed, it must return an array|Traversable. + * @param callable(): iterable|iterable $input */ public function __construct($input) { @@ -44,12 +53,14 @@ public function __construct($input) /** * Static alias of normal constructor. * - * @param callable|array|Traversable $input - * @return CollectionInterface + * @template CKey + * @template CVal + * @param callable():iterable|iterable $input + * @return static */ public static function from($input) { - return new self($input); + return new static($input); } /** @@ -58,24 +69,25 @@ public static function from($input) * end the collection by throwing a NoMoreItems exception. * * @param mixed $input - * @param callable $function - * @return CollectionInterface + * @param callable(mixed):mixed $function + * @return static */ public static function iterate($input, callable $function) { - return iterate($input, $function); + return static::from(iterate($input, $function)); } /** * Returns a lazy collection of $value repeated $times times. If $times is not provided the collection is infinite. * - * @param mixed $value + * @template TItem + * @param TItem $value * @param int $times - * @return CollectionInterface + * @return static */ - public static function repeat($value, $times = -1) + public static function repeat($value, int $times = -1) { - return repeat($value, $times); + return static::from(repeat($value, $times)); } /** @@ -84,16 +96,17 @@ public static function repeat($value, $times = -1) * @param int $start * @param int|null $end * @param int $step - * @return CollectionInterface + * @return static */ public static function range($start = 0, $end = null, $step = 1) { - return \DusanKasan\Knapsack\range($start, $end, $step); + return static::from(\DusanKasan\Knapsack\range($start, $end, $step)); } /** * {@inheritdoc} * @throws InvalidReturnValue + * @return Traversable */ public function getIterator() { @@ -123,7 +136,12 @@ public function serialize() toArray( map( $this->input, - function ($value, $key) { + /** + * @param mixed $value + * @param mixed $key + * @return array + */ + function ($value, $key): array { return [$key, $value]; } ) @@ -139,11 +157,12 @@ public function unserialize($serialized) $this->input = dereferenceKeyValue(unserialize($serialized)); } + /** - * @inheritDoc + * @return iterable */ - protected function buildFromCollection(Collection $collection) + protected function getItems(): iterable { - return $collection; + return $this; } } diff --git a/src/CollectionInterface.php b/src/CollectionInterface.php index fdb9882..636a01a 100644 --- a/src/CollectionInterface.php +++ b/src/CollectionInterface.php @@ -3,8 +3,13 @@ namespace DusanKasan\Knapsack; use DusanKasan\Knapsack\Exceptions\InvalidReturnValue; +use Traversable; -interface CollectionInterface +/** + * @template TKey + * @template TVal + */ +interface CollectionInterface extends Traversable { /** * Converts $collection to array. If there are multiple items with the same key, only the last will be preserved. @@ -16,31 +21,32 @@ public function toArray(); /** * Returns a lazy collection of items for which $function returned true. * - * @param callable|null $function ($value, $key) - * @return CollectionInterface + * @param callable(TVal, TKey): bool|null $function + * @return static */ public function filter(callable $function = null); /** * Returns a lazy collection of distinct items. The comparison is the same as in in_array. * - * @return CollectionInterface + * @return static */ public function distinct(); /** * Returns a lazy collection with items from all $collections passed as argument appended together * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static */ public function concat(...$collections); /** * Returns collection where each item is changed to the output of executing $function on each key/item. * - * @param callable $function - * @return CollectionInterface + * @template TRes + * @param callable(TVal, TKey):TRes $function + * @return static */ public function map(callable $function); @@ -48,7 +54,7 @@ public function map(callable $function); * Reduces the collection to single value by iterating over the collection and calling $function while * passing $startValue and current key/item as parameters. The output of $function is used as $startValue in * next iteration. The output of $function on last element is the return value of this function. If - * $convertToCollection is true and the return value is a collection (array|Traversable) an instance of Collection + * $convertToCollection is true and the return value is a collection (iterable) an instance of Collection * is returned. * * @param callable $function ($tmpValue, $value, $key) @@ -71,8 +77,8 @@ public function flatten($depth = -1); * Returns a non-lazy collection sorted using $function($item1, $item2, $key1, $key2 ). $function should * return true if first item is larger than the second and false otherwise. * - * @param callable $function ($value1, $value2, $key1, $key2) - * @return CollectionInterface + * @param callable(TVal, TVal, TKey, TKey): bool $function + * @return static */ public function sort(callable $function); @@ -81,32 +87,33 @@ public function sort(callable $function); * number $to. The items before $from are also iterated over, just not returned. * * @param int $from - * @param int $to If omitted, will slice until end - * @return CollectionInterface + * @param int $to -1 to slice until end + * @return static */ - public function slice($from, $to = -1); + public function slice(int $from, int $to = -1); /** * Returns collection which items are separated into groups indexed by the return value of $function. * - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TRes + * @param callable(TVal, TKey): TRes $function + * @return CollectionInterface> */ - public function groupBy(callable $function); + public function groupBy(callable $function): CollectionInterface; /** * Returns collection where items are separated into groups indexed by the value at given key. * * @param mixed $key - * @return CollectionInterface + * @return CollectionInterface */ - public function groupByKey($key); + public function groupByKey($key): CollectionInterface; /** * Returns a lazy collection in which $function is executed for each item. * - * @param callable $function ($value, $key) - * @return CollectionInterface + * @param callable(TVal, TKey): void $function + * @return static */ public function each(callable $function); @@ -119,7 +126,7 @@ public function size(); /** * Returns value at the key $key. If multiple values have this key, return first. If no value has this key, throw - * ItemNotFound. If $convertToCollection is true and the return value is a collection (array|Traversable) an + * ItemNotFound. If $convertToCollection is true and the return value is a collection (iterable) an * instance of Collection will be returned. * * @param mixed $key @@ -132,7 +139,7 @@ public function get($key, $convertToCollection = false); /** * Returns item at the key $key. If multiple items have this key, return first. If no item has this key, return * $ifNotFound. If no value has this key, throw ItemNotFound. If $convertToCollection is true and the return value - * is a collection (array|Traversable) an instance of Collection will be returned. + * is a collection (iterable) an instance of Collection will be returned. * * @param mixed $key * @param mixed $default @@ -144,12 +151,12 @@ public function getOrDefault($key, $default = null, $convertToCollection = false /** * Returns first value matched by $function. If no value matches, return $default. If $convertToCollection is true - * and the return value is a collection (array|Traversable) an instance of Collection will be returned. + * and the return value is a collection (iterable) an instance of Collection will be returned. * - * @param callable $function - * @param mixed|null $default + * @param callable(TVal, TKey): bool $function + * @param TVal|null $default * @param bool $convertToCollection - * @return mixed|Collection + * @return TVal|CollectionInterface */ public function find(callable $function, $default = null, $convertToCollection = false); @@ -157,24 +164,26 @@ public function find(callable $function, $default = null, $convertToCollection = * Returns a non-lazy collection of items whose keys are the return values of $function and values are the number of * items in this collection for which the $function returned this value. * - * @param callable $function - * @return CollectionInterface + * @template TRes + * @param callable(TVal, TKey): TRes $function + * @return CollectionInterface */ - public function countBy(callable $function); + public function countBy(callable $function): CollectionInterface; /** * Returns a lazy collection by changing keys of this collection for each item to the result of $function for * that item. * - * @param callable $function - * @return CollectionInterface + * @template TNewKey + * @param callable(TVal, TKey): TNewKey $function + * @return static */ public function indexBy(callable $function); /** * Returns true if $function returns true for every item in this collection, false otherwise. * - * @param callable $function + * @param callable(TVal, TKey): bool $function * @return bool */ public function every(callable $function); @@ -182,7 +191,7 @@ public function every(callable $function); /** * Returns true if $function returns true for at least one item in this collection, false otherwise. * - * @param callable $function + * @param callable(TVal, TKey): bool $function * @return bool */ public function some(callable $function); @@ -190,7 +199,7 @@ public function some(callable $function); /** * Returns true if $value is present in the collection. * - * @param mixed $value + * @param TVal $value * @return bool */ public function contains($value); @@ -198,18 +207,19 @@ public function contains($value); /** * Returns collection of items in this collection in reverse order. * - * @return CollectionInterface + * @return static */ public function reverse(); /** * Reduce the collection to single value. Walks from right to left. If $convertToCollection is true and the return - * value is a collection (array|Traversable) an instance of Collection is returned. + * value is a collection (iterable) an instance of Collection is returned. * - * @param callable $function Must take 2 arguments, intermediate value and item from the iterator. - * @param mixed $startValue + * @template TRes + * @param callable $function + * @param TRes $startValue * @param bool $convertToCollection - * @return mixed|Collection + * @return TRes|CollectionInterface */ public function reduceRight(callable $function, $startValue, $convertToCollection = false); @@ -217,45 +227,45 @@ public function reduceRight(callable $function, $startValue, $convertToCollectio * A form of slice that returns first $numberOfItems items. * * @param int $numberOfItems - * @return CollectionInterface + * @return static */ - public function take($numberOfItems); + public function take(int $numberOfItems); /** * A form of slice that returns all but first $numberOfItems items. * * @param int $numberOfItems - * @return CollectionInterface + * @return static */ - public function drop($numberOfItems); + public function drop(int $numberOfItems); /** * Returns collection of values from this collection but with keys being numerical from 0 upwards. * - * @return CollectionInterface + * @return static */ public function values(); /** * Returns a lazy collection without elements matched by $function. * - * @param callable $function - * @return CollectionInterface + * @param callable(TVal, TKey): bool $function + * @return static */ public function reject(callable $function); /** * Returns a lazy collection of the keys of this collection. * - * @return CollectionInterface + * @return CollectionInterface */ public function keys(); /** * Returns a lazy collection of items of this collection separated by $separator * - * @param mixed $separator - * @return CollectionInterface + * @param TVal $separator + * @return static */ public function interpose($separator); @@ -263,23 +273,23 @@ public function interpose($separator); * Returns a lazy collection with last $numberOfItems items skipped. These are still iterated over, just skipped. * * @param int $numberOfItems - * @return CollectionInterface + * @return static */ - public function dropLast($numberOfItems = 1); + public function dropLast(int $numberOfItems = 1); /** * Returns a lazy collection of first item from first collection, first item from second, second from first and * so on. Accepts any number of collections. * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static */ public function interleave(...$collections); /** * Returns an infinite lazy collection of items in this collection repeated infinitely. * - * @return CollectionInterface + * @return static */ public function cycle(); @@ -287,9 +297,9 @@ public function cycle(); * Returns a lazy collection of items of this collection with $value added as first element. If $key is not provided * it will be next integer index. * - * @param mixed $value - * @param mixed|null $key - * @return CollectionInterface + * @param TVal $value + * @param TKey|null $key + * @return static */ public function prepend($value, $key = null); @@ -297,9 +307,9 @@ public function prepend($value, $key = null); * Returns a lazy collection of items of this collection with $value added as last element. If $key is not provided * it will be next integer index. * - * @param mixed $value - * @param mixed $key - * @return CollectionInterface + * @param TVal $value + * @param TKey|null $key + * @return static */ public function append($value, $key = null); @@ -307,8 +317,8 @@ public function append($value, $key = null); * Returns a lazy collection by removing items from this collection until first item for which $function returns * false. * - * @param callable $function - * @return CollectionInterface + * @param callable(TVal, TKey): bool $function + * @return static */ public function dropWhile(callable $function); @@ -349,7 +359,7 @@ public function splitWith(callable $function); * Returns a lazy collection with items from this collection but values that are found in keys of $replacementMap * are replaced by their values. * - * @param array|\Traversable $replacementMap + * @param iterable $replacementMap * @return CollectionInterface */ public function replace($replacementMap); @@ -387,7 +397,7 @@ public function shuffle(); * * @param int $numberOfItems * @param int $step - * @param array|\Traversable $padding + * @param iterable $padding * @return CollectionInterface */ public function partition($numberOfItems, $step = 0, $padding = []); @@ -425,7 +435,7 @@ public function frequencies(); /** * Returns first item of this collection. If the collection is empty, throws ItemNotFound. If $convertToCollection - * is true and the return value is a collection (array|Traversable) an instance of Collection is returned. + * is true and the return value is a collection (iterable) an instance of Collection is returned. * * @param bool $convertToCollection * @return mixed|Collection @@ -435,7 +445,7 @@ public function first($convertToCollection = false); /** * Returns last item of this collection. If the collection is empty, throws ItemNotFound. If $convertToCollection - * is true and the return value is a collection (array|Traversable) it is converted to Collection. + * is true and the return value is a collection (iterable) it is converted to Collection. * * @param bool $convertToCollection * @return mixed|Collection @@ -452,7 +462,7 @@ public function realize(); /** * Returns the second item in this collection or throws ItemNotFound if the collection is empty or has 1 item. If - * $convertToCollection is true and the return value is a collection (array|Traversable) it is converted to + * $convertToCollection is true and the return value is a collection (iterable) it is converted to * Collection. * * @param bool $convertToCollection @@ -465,33 +475,33 @@ public function second($convertToCollection = false); * Combines the values of this collection as keys, with values of $collection as values. The resulting collection * has length equal to the size of smaller collection. * - * @param array|\Traversable $collection + * @param iterable $collection * @return CollectionInterface * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound */ - public function combine($collection); + public function combine(iterable $collection); /** * Returns a lazy collection without the items associated to any of the keys from $keys. * - * @param array|\Traversable $keys + * @param iterable $keys * @return CollectionInterface */ - public function except($keys); + public function except(iterable $keys); /** * Returns a lazy collection of items associated to any of the keys from $keys. * - * @param array|\Traversable $keys + * @param iterable $keys * @return CollectionInterface */ - public function only($keys); + public function only(iterable $keys); /** * Returns a lazy collection of items that are in $this but are not in any of the other arguments, indexed by the * keys from the first collection. Note that the ...$collections are iterated non-lazily. * - * @param array|\Traversable ...$collections + * @param iterable ...$collections * @return CollectionInterface */ public function diff(...$collections); @@ -515,10 +525,10 @@ public function has($key); * Returns a lazy collection of non-lazy collections of items from nth position from this collection and each * passed collection. Stops when any of the collections don't have an item at the nth position. * - * @param array|\Traversable ...$collections + * @param iterable ...$collections * @return CollectionInterface */ - public function zip(...$collections); + public function zip(iterable ...$collections); /** * Uses a $transformer callable that takes a Collection and returns Collection on itself. @@ -550,10 +560,10 @@ public function extract($keyPath); * Returns a lazy collection of items that are in $this and all the other arguments, indexed by the keys from * the first collection. Note that the ...$collections are iterated non-lazily. * - * @param array|\Traversable ...$collections + * @param iterable ...$collections * @return CollectionInterface */ - public function intersect(...$collections); + public function intersect(iterable ...$collections); /** * Checks whether this collection has exactly $size items. @@ -561,7 +571,7 @@ public function intersect(...$collections); * @param int $size * @return bool */ - public function sizeIs($size); + public function sizeIs(int $size): bool; /** * Checks whether this collection has less than $size items. @@ -569,7 +579,7 @@ public function sizeIs($size); * @param int $size * @return bool */ - public function sizeIsLessThan($size); + public function sizeIsLessThan(int $size): bool; /** * Checks whether this collection has more than $size items. @@ -577,7 +587,7 @@ public function sizeIsLessThan($size); * @param int $size * @return bool */ - public function sizeIsGreaterThan($size); + public function sizeIsGreaterThan(int $size): bool; /** * Checks whether this collection has between $fromSize to $toSize items. $toSize can be @@ -587,7 +597,7 @@ public function sizeIsGreaterThan($size); * @param int $toSize * @return bool */ - public function sizeIsBetween($fromSize, $toSize); + public function sizeIsBetween(int $fromSize, int $toSize): bool; /** * Returns a sum of all values in this collection. @@ -628,10 +638,10 @@ public function toString(); * Returns a lazy collection with items from $collection, but items with keys that are found in keys of * $replacementMap are replaced by their values. * - * @param array|\Traversable $replacementMap - * @return CollectionInterface + * @param iterable $replacementMap + * @return CollectionInterface */ - public function replaceByKeys($replacementMap); + public function replaceByKeys(iterable $replacementMap); /** * /** @@ -657,7 +667,7 @@ public function replaceByKeys($replacementMap); * @param int|null $maxDepth * @return array */ - public function dump($maxItemsPerCollection = null, $maxDepth = null); + public function dump(int $maxItemsPerCollection = null, int $maxDepth = null): array; /** * Calls dump on this collection and then prints it using the var_export. @@ -666,5 +676,5 @@ public function dump($maxItemsPerCollection = null, $maxDepth = null); * @param int|null $maxDepth * @return CollectionInterface */ - public function printDump($maxItemsPerCollection = null, $maxDepth = null); + public function printDump(int $maxItemsPerCollection = null, int $maxDepth = null); } \ No newline at end of file diff --git a/src/CollectionTrait.php b/src/CollectionTrait.php index b805358..b84c213 100644 --- a/src/CollectionTrait.php +++ b/src/CollectionTrait.php @@ -3,7 +3,13 @@ namespace DusanKasan\Knapsack; use DusanKasan\Knapsack\Exceptions\InvalidReturnValue; +use DusanKasan\Knapsack\Exceptions\ItemNotFound; +use Generator; +/** + * @template TKey + * @template TVal + */ trait CollectionTrait { /** @@ -19,87 +25,89 @@ public function toArray() /** * Returns a lazy collection of items for which $function returned true. * - * @param callable|null $function ($value, $key) - * @return CollectionInterface + * @param callable(TVal, TKey): bool|null $function + * @return static */ public function filter(callable $function = null) { - return $this->buildFromCollection(filter($this->getItems(), $function)); + return static::from(filter($this->getItems(), $function)); } /** * Returns a lazy collection of distinct items. The comparison is the same as in in_array. * - * @return CollectionInterface + * @return static */ public function distinct() { - return distinct($this->getItems()); + return static::from(distinct($this->getItems())); } /** * Returns a lazy collection with items from all $collections passed as argument appended together * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static */ public function concat(...$collections) { - return concat($this, ...$collections); + return static::from(concat($this, ...$collections)); } /** * Returns collection where each item is changed to the output of executing $function on each key/item. * - * @param callable $function - * @return CollectionInterface + * @template TRes + * @param callable(TVal, TKey):TRes $function + * @return static */ public function map(callable $function) { - return map($this->getItems(), $function); + return static::from(map($this->getItems(), $function)); } /** * Reduces the collection to single value by iterating over the collection and calling $function while * passing $startValue and current key/item as parameters. The output of $function is used as $startValue in * next iteration. The output of $function on last element is the return value of this function. If - * $convertToCollection is true and the return value is a collection (array|Traversable) an instance of Collection + * $convertToCollection is true and the return value is a collection (iterable) an instance of Collection * is returned. * - * @param callable $function ($tmpValue, $value, $key) - * @param mixed $startValue + * @template TRes + * @param callable $function + * @param TRes $startValue * @param bool $convertToCollection - * @return mixed|Collection + * @return TRes|CollectionInterface */ public function reduce(callable $function, $startValue, $convertToCollection = false) { $result = reduce($this->getItems(), $function, $startValue); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Returns a lazy collection with one or multiple levels of nesting flattened. Removes all nesting when no value * is passed. * - * @param int $depth How many levels should be flatten, default (-1) is infinite. - * @return CollectionInterface + * @param int $levelsToFlatten -1 to flatten everything + * @return CollectionInterface */ - public function flatten($depth = -1) + public function flatten($levelsToFlatten = -1) { - return flatten($this->getItems(), $depth); + return new Collection(flatten($this->getItems(), $levelsToFlatten)); } /** * Returns a non-lazy collection sorted using $function($item1, $item2, $key1, $key2 ). $function should * return true if first item is larger than the second and false otherwise. * - * @param callable $function ($value1, $value2, $key1, $key2) - * @return CollectionInterface + * @param callable(TVal, TVal, TKey, TKey): bool $function + * @return static */ public function sort(callable $function) { - return \DusanKasan\Knapsack\sort($this->getItems(), $function); + return static::from(\DusanKasan\Knapsack\sort($this->getItems(), $function)); } /** @@ -107,45 +115,54 @@ public function sort(callable $function) * number $to. The items before $from are also iterated over, just not returned. * * @param int $from - * @param int $to If omitted, will slice until end - * @return CollectionInterface + * @param int $to -1 to slice until end + * @return static */ - public function slice($from, $to = -1) + public function slice(int $from, int $to = -1) { - return slice($this->getItems(), $from, $to); + return static::from(slice($this->getItems(), $from, $to)); } /** * Returns collection which items are separated into groups indexed by the return value of $function. * - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TRes + * @param callable(TVal, TKey): TRes $function + * @return CollectionInterface> */ - public function groupBy(callable $function) + public function groupBy(callable $function): CollectionInterface { - return groupBy($this->getItems(), $function); + return new Collection(function () use ($function): iterable { + foreach (groupBy($this->getItems(), $function) as $k => $v) { + yield $k => static::from($v); + } + }); } /** * Returns collection where items are separated into groups indexed by the value at given key. * * @param mixed $key - * @return CollectionInterface + * @return CollectionInterface */ - public function groupByKey($key) + public function groupByKey($key): CollectionInterface { - return groupByKey($this->getItems(), $key); + return new Collection(function () use ($key): iterable { + foreach (groupByKey($this->getItems(), $key) as $k => $v) { + yield $k => static::from($v); + } + }); } /** * Returns a lazy collection in which $function is executed for each item. * - * @param callable $function ($value, $key) - * @return CollectionInterface + * @param callable(TVal, TKey): void $function + * @return static */ public function each(callable $function) { - return \DusanKasan\Knapsack\each($this->getItems(), $function); + return static::from(each($this->getItems(), $function)); } /** @@ -153,93 +170,94 @@ public function each(callable $function) * * @return int */ - public function size() + public function size(): int { return size($this->getItems()); } /** * Returns value at the key $key. If multiple values have this key, return first. If no value has this key, throw - * ItemNotFound. If $convertToCollection is true and the return value is a collection (array|Traversable) an + * ItemNotFound. If $convertToCollection is true and the return value is a collection (iterable) an * instance of Collection will be returned. * - * @param mixed $key + * @param TKey $key * @param bool $convertToCollection - * @return mixed|Collection - * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound + * @return TVal|CollectionInterface + * @throws ItemNotFound */ public function get($key, $convertToCollection = false) { $result = get($this->getItems(), $key); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Returns item at the key $key. If multiple items have this key, return first. If no item has this key, return * $ifNotFound. If no value has this key, throw ItemNotFound. If $convertToCollection is true and the return value - * is a collection (array|Traversable) an instance of Collection will be returned. + * is a collection (iterable) an instance of Collection will be returned. * - * @param mixed $key - * @param mixed $default + * @param TKey $key + * @param TVal $default * @param bool $convertToCollection - * @return mixed|Collection - * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound + * @return TVal|CollectionInterface */ public function getOrDefault($key, $default = null, $convertToCollection = false) { $result = getOrDefault($this->getItems(), $key, $default); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Returns first value matched by $function. If no value matches, return $default. If $convertToCollection is true - * and the return value is a collection (array|Traversable) an instance of Collection will be returned. + * and the return value is a collection (iterable) an instance of Collection will be returned. * - * @param callable $function - * @param mixed|null $default + * @param callable(TVal, TKey): bool $function + * @param TVal|null $default * @param bool $convertToCollection - * @return mixed|Collection + * @return TVal|CollectionInterface */ public function find(callable $function, $default = null, $convertToCollection = false) { $result = find($this->getItems(), $function, $default); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Returns a non-lazy collection of items whose keys are the return values of $function and values are the number of * items in this collection for which the $function returned this value. * - * @param callable $function - * @return CollectionInterface + * @template TRes + * @param callable(TVal, TKey): TRes $function + * @return CollectionInterface */ - public function countBy(callable $function) + public function countBy(callable $function): CollectionInterface { - return countBy($this->getItems(), $function); + return new Collection(countBy($this->getItems(), $function)); } /** * Returns a lazy collection by changing keys of this collection for each item to the result of $function for * that item. * - * @param callable $function - * @return CollectionInterface + * @template TNewKey + * @param callable(TVal, TKey): TNewKey $function + * @return static */ public function indexBy(callable $function) { - return indexBy($this->getItems(), $function); + return static::from(indexBy($this->getItems(), $function)); } /** * Returns true if $function returns true for every item in this collection, false otherwise. * - * @param callable $function + * @param callable(TVal, TKey): bool $function * @return bool */ - public function every(callable $function) + public function every(callable $function): bool { return every($this->getItems(), $function); } @@ -247,10 +265,10 @@ public function every(callable $function) /** * Returns true if $function returns true for at least one item in this collection, false otherwise. * - * @param callable $function + * @param callable(TVal, TKey): bool $function * @return bool */ - public function some(callable $function) + public function some(callable $function): bool { return some($this->getItems(), $function); } @@ -258,7 +276,7 @@ public function some(callable $function) /** * Returns true if $value is present in the collection. * - * @param mixed $value + * @param TVal $value * @return bool */ public function contains($value) @@ -269,173 +287,174 @@ public function contains($value) /** * Returns collection of items in this collection in reverse order. * - * @return CollectionInterface + * @return static */ public function reverse() { - return reverse($this->getItems()); + return static::from(reverse($this->getItems())); } /** * Reduce the collection to single value. Walks from right to left. If $convertToCollection is true and the return - * value is a collection (array|Traversable) an instance of Collection is returned. + * value is a collection (iterable) an instance of Collection is returned. * - * @param callable $function Must take 2 arguments, intermediate value and item from the iterator. - * @param mixed $startValue + * @template TRes + * @param callable $function + * @param TRes $startValue * @param bool $convertToCollection - * @return mixed|Collection + * @return TRes|CollectionInterface */ public function reduceRight(callable $function, $startValue, $convertToCollection = false) { $result = reduceRight($this->getItems(), $function, $startValue); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * A form of slice that returns first $numberOfItems items. * * @param int $numberOfItems - * @return CollectionInterface + * @return static */ - public function take($numberOfItems) + public function take(int $numberOfItems) { - return take($this->getItems(), $numberOfItems); + return static::from(take($this->getItems(), $numberOfItems)); } /** * A form of slice that returns all but first $numberOfItems items. * * @param int $numberOfItems - * @return CollectionInterface + * @return static */ - public function drop($numberOfItems) + public function drop(int $numberOfItems) { - return drop($this->getItems(), $numberOfItems); + return static::from(drop($this->getItems(), $numberOfItems)); } /** * Returns collection of values from this collection but with keys being numerical from 0 upwards. * - * @return CollectionInterface + * @return static */ public function values() { - return values($this->getItems()); + return static::from(values($this->getItems())); } /** * Returns a lazy collection without elements matched by $function. * - * @param callable $function - * @return CollectionInterface + * @param callable(TVal, TKey): bool $function + * @return static */ public function reject(callable $function) { - return reject($this->getItems(), $function); + return static::from(reject($this->getItems(), $function)); } /** * Returns a lazy collection of the keys of this collection. * - * @return CollectionInterface + * @return CollectionInterface */ public function keys() { - return keys($this->getItems()); + return new Collection(keys($this->getItems())); } /** * Returns a lazy collection of items of this collection separated by $separator * - * @param mixed $separator - * @return CollectionInterface + * @param TVal $separator + * @return static */ public function interpose($separator) { - return interpose($this->getItems(), $separator); + return static::from(interpose($this->getItems(), $separator)); } /** * Returns a lazy collection with last $numberOfItems items skipped. These are still iterated over, just skipped. * * @param int $numberOfItems - * @return CollectionInterface + * @return static */ - public function dropLast($numberOfItems = 1) + public function dropLast(int $numberOfItems = 1) { - return dropLast($this->getItems(), $numberOfItems); + return static::from(dropLast($this->getItems(), $numberOfItems)); } /** * Returns a lazy collection of first item from first collection, first item from second, second from first and * so on. Accepts any number of collections. * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static */ public function interleave(...$collections) { - return interleave($this->getItems(), ...$collections); + return static::from(interleave($this->getItems(), ...$collections)); } /** * Returns an infinite lazy collection of items in this collection repeated infinitely. * - * @return CollectionInterface + * @return static */ public function cycle() { - return cycle($this->getItems()); + return static::from(cycle($this->getItems())); } /** * Returns a lazy collection of items of this collection with $value added as first element. If $key is not provided * it will be next integer index. * - * @param mixed $value - * @param mixed|null $key - * @return CollectionInterface + * @param TVal $value + * @param TKey|null $key + * @return static */ public function prepend($value, $key = null) { - return prepend($this->getItems(), $value, $key); + return static::from(prepend($this->getItems(), $value, $key)); } /** * Returns a lazy collection of items of this collection with $value added as last element. If $key is not provided * it will be next integer index. * - * @param mixed $value - * @param mixed $key - * @return CollectionInterface + * @param TVal $value + * @param TKey|null $key + * @return static */ public function append($value, $key = null) { - return append($this->getItems(), $value, $key); + return static::from(append($this->getItems(), $value, $key)); } /** * Returns a lazy collection by removing items from this collection until first item for which $function returns * false. * - * @param callable $function - * @return CollectionInterface + * @param callable(TVal, TKey): bool $function + * @return static */ public function dropWhile(callable $function) { - return dropWhile($this->getItems(), $function); + return static::from(dropWhile($this->getItems(), $function)); } /** * Returns a lazy collection which is a result of calling map($function) and then flatten(1) * * @param callable $function - * @return CollectionInterface + * @return static */ public function mapcat(callable $function) { - return mapcat($this->getItems(), $function); + return static::from(mapcat($this->getItems(), $function)); } /** @@ -443,45 +462,53 @@ public function mapcat(callable $function) * returns false. * * @param callable $function - * @return CollectionInterface + * @return static */ public function takeWhile(callable $function) { - return takeWhile($this->getItems(), $function); + return static::from(takeWhile($this->getItems(), $function)); } /** * Returns a collection of [take($position), drop($position)] * * @param int $position - * @return CollectionInterface + * @return static */ public function splitAt($position) { - return splitAt($this->getItems(), $position); + return static::from(function () use ($position): Generator { + foreach (splitAt($this->getItems(), $position) as $k => $v) { + yield $k => static::from($v); + } + }); } /** * Returns a collection of [takeWhile($predicament), dropWhile($predicament] * * @param callable $function - * @return CollectionInterface + * @return static */ public function splitWith(callable $function) { - return splitWith($this->getItems(), $function); + return static::from(function () use ($function): Generator { + foreach (splitWith($this->getItems(), $function) as $k => $v) { + yield $k => static::from($v); + } + }); } /** * Returns a lazy collection with items from this collection but values that are found in keys of $replacementMap * are replaced by their values. * - * @param array|\Traversable $replacementMap - * @return CollectionInterface + * @param iterable $replacementMap + * @return static */ public function replace($replacementMap) { - return replace($this->getItems(), $replacementMap); + return static::from(replace($this->getItems(), $replacementMap)); } /** @@ -489,22 +516,22 @@ public function replace($replacementMap) * * @param callable $function * @param mixed $startValue - * @return CollectionInterface + * @return static */ public function reductions(callable $function, $startValue) { - return reductions($this->getItems(), $function, $startValue); + return static::from(reductions($this->getItems(), $function, $startValue)); } /** * Returns a lazy collection of every nth item in this collection * * @param int $step - * @return CollectionInterface + * @return static */ public function takeNth($step) { - return takeNth($this->getItems(), $step); + return static::from(takeNth($this->getItems(), $step)); } /** @@ -514,7 +541,7 @@ public function takeNth($step) */ public function shuffle() { - return \DusanKasan\Knapsack\shuffle($this->getItems()); + return static::from(\DusanKasan\Knapsack\shuffle($this->getItems())); } /** @@ -526,12 +553,17 @@ public function shuffle() * * @param int $numberOfItems * @param int $step - * @param array|\Traversable $padding - * @return CollectionInterface + * @param iterable $padding + * @return static */ public function partition($numberOfItems, $step = 0, $padding = []) { - return partition($this->getItems(), $numberOfItems, $step, $padding); + return static::from(function() use ($numberOfItems, $step, $padding) { + $c = partition($this->getItems(), $numberOfItems, $step, $padding); + foreach($c as $k => $v) { + yield $k => static::from($v); + } + }); } /** @@ -539,11 +571,16 @@ public function partition($numberOfItems, $step = 0, $padding = []) * return different result. * * @param callable $function - * @return CollectionInterface + * @return static */ public function partitionBy(callable $function) { - return partitionBy($this->getItems(), $function); + return static::from(function() use ($function) { + $c = partitionBy($this->getItems(), $function); + foreach($c as $k => $v) { + yield $k => static::from($v); + } + }); } /** @@ -570,124 +607,125 @@ public function isNotEmpty() * Returns a collection where keys are distinct items from this collection and their values are number of * occurrences of each value. * - * @return CollectionInterface + * @return static */ public function frequencies() { - return frequencies($this->getItems()); + return static::from(frequencies($this->getItems())); } /** * Returns first item of this collection. If the collection is empty, throws ItemNotFound. If $convertToCollection - * is true and the return value is a collection (array|Traversable) an instance of Collection is returned. + * is true and the return value is a collection (iterable) an instance of Collection is returned. * * @param bool $convertToCollection * @return mixed|Collection - * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound + * @throws ItemNotFound */ public function first($convertToCollection = false) { $result = first($this->getItems()); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Returns last item of this collection. If the collection is empty, throws ItemNotFound. If $convertToCollection - * is true and the return value is a collection (array|Traversable) it is converted to Collection. + * is true and the return value is a collection (iterable) it is converted to Collection. * * @param bool $convertToCollection * @return mixed|Collection - * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound + * @throws ItemNotFound */ public function last($convertToCollection = false) { $result = last($this->getItems()); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Realizes collection - turns lazy collection into non-lazy one by iterating over it and storing the key/values. * - * @return CollectionInterface + * @return static */ public function realize() { - return realize($this->getItems()); + return static::from(realize($this->getItems())); } /** * Returns the second item in this collection or throws ItemNotFound if the collection is empty or has 1 item. If - * $convertToCollection is true and the return value is a collection (array|Traversable) it is converted to + * $convertToCollection is true and the return value is a collection (iterable) it is converted to * Collection. * * @param bool $convertToCollection * @return mixed|Collection - * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound + * @throws ItemNotFound */ public function second($convertToCollection = false) { $result = second($this->getItems()); - return ($convertToCollection && isCollection($result)) ? new Collection($result) : $result; + return ($convertToCollection && is_iterable($result)) ? new Collection($result) : $result; } /** * Combines the values of this collection as keys, with values of $collection as values. The resulting collection * has length equal to the size of smaller collection. * - * @param array|\Traversable $collection - * @return CollectionInterface - * @throws \DusanKasan\Knapsack\Exceptions\ItemNotFound + * @template TNewVal + * @param iterable $collection + * @return static + * @throws ItemNotFound */ - public function combine($collection) + public function combine(iterable $collection) { - return combine($this->getItems(), $collection); + return static::from(combine($this->getItems(), $collection)); } /** * Returns a lazy collection without the items associated to any of the keys from $keys. * - * @param array|\Traversable $keys - * @return CollectionInterface + * @param iterable $keys + * @return static */ - public function except($keys) + public function except(iterable $keys) { - return except($this->getItems(), $keys); + return static::from(except($this->getItems(), $keys)); } /** * Returns a lazy collection of items associated to any of the keys from $keys. * - * @param array|\Traversable $keys - * @return CollectionInterface + * @param iterable $keys + * @return static */ - public function only($keys) + public function only(iterable $keys) { - return only($this->getItems(), $keys); + return static::from(only($this->getItems(), $keys)); } /** * Returns a lazy collection of items that are in $this but are not in any of the other arguments, indexed by the * keys from the first collection. Note that the ...$collections are iterated non-lazily. * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static */ public function diff(...$collections) { - return diff($this->getItems(), ...$collections); + return static::from(diff($this->getItems(), ...$collections)); } /** * Returns a lazy collection where keys and values are flipped. * - * @return CollectionInterface + * @return static */ public function flip() { - return flip($this->getItems()); + return static::from(flip($this->getItems())); } /** @@ -705,14 +743,13 @@ public function has($key) * Returns a lazy collection of non-lazy collections of items from nth position from this collection and each * passed collection. Stops when any of the collections don't have an item at the nth position. * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static> */ - public function zip(...$collections) + public function zip(iterable ...$collections) { array_unshift($collections, $this->getItems()); - - return zip(...$collections); + return static::from(zip(...$collections)); } /** @@ -739,11 +776,16 @@ public function transform(callable $transformer) * Transpose each item in a collection, interchanging the row and column indexes. * Can only transpose collections of collections. Otherwise an InvalidArgument is raised. * - * @return CollectionInterface + * @TODO: TVal must be iterable + * @return static */ public function transpose() { - return transpose($this->getItems()); + return static::from(function (): Generator { + foreach (transpose($this->getItems()) as $k => $v) { + yield $k => static::from($v); + } + }); } /** @@ -751,23 +793,23 @@ public function transpose() * it must be escaped using \ character. * * @param mixed $keyPath - * @return CollectionInterface + * @return CollectionInterface */ public function extract($keyPath) { - return \DusanKasan\Knapsack\extract($this->getItems(), $keyPath); + return Collection::from(extract($this->getItems(), $keyPath)); } /** * Returns a lazy collection of items that are in $this and all the other arguments, indexed by the keys from * the first collection. Note that the ...$collections are iterated non-lazily. * - * @param array|\Traversable ...$collections - * @return CollectionInterface + * @param iterable ...$collections + * @return static */ - public function intersect(...$collections) + public function intersect(iterable ...$collections) { - return intersect($this->getItems(), ...$collections); + return static::from(intersect($this->getItems(), ...$collections)); } /** @@ -776,7 +818,7 @@ public function intersect(...$collections) * @param int $size * @return bool */ - public function sizeIs($size) + public function sizeIs(int $size): bool { return sizeIs($this->getItems(), $size); } @@ -787,7 +829,7 @@ public function sizeIs($size) * @param int $size * @return bool */ - public function sizeIsLessThan($size) + public function sizeIsLessThan(int $size): bool { return sizeIsLessThan($this->getItems(), $size); } @@ -798,7 +840,7 @@ public function sizeIsLessThan($size) * @param int $size * @return bool */ - public function sizeIsGreaterThan($size) + public function sizeIsGreaterThan(int $size): bool { return sizeIsGreaterThan($this->getItems(), $size); } @@ -811,7 +853,7 @@ public function sizeIsGreaterThan($size) * @param int $toSize * @return bool */ - public function sizeIsBetween($fromSize, $toSize) + public function sizeIsBetween(int $fromSize, int $toSize): bool { return sizeIsBetween($this->getItems(), $fromSize, $toSize); } @@ -839,21 +881,21 @@ public function average() /** * Returns maximal value from this collection. * - * @return mixed + * @return TVal */ public function max() { - return \DusanKasan\Knapsack\max($this->getItems()); + return max($this->getItems()); } /** * Returns minimal value from this collection. * - * @return mixed + * @return TVal */ public function min() { - return \DusanKasan\Knapsack\min($this->getItems()); + return min($this->getItems()); } /** @@ -861,7 +903,7 @@ public function min() * * @return string */ - public function toString() + public function toString(): string { return toString($this->getItems()); } @@ -870,12 +912,12 @@ public function toString() * Returns a lazy collection with items from $collection, but items with keys that are found in keys of * $replacementMap are replaced by their values. * - * @param array|\Traversable $replacementMap - * @return CollectionInterface + * @param iterable $replacementMap + * @return static */ - public function replaceByKeys($replacementMap) + public function replaceByKeys(iterable $replacementMap) { - return replaceByKeys($this->getItems(), $replacementMap); + return static::from(replaceByKeys($this->getItems(), $replacementMap)); } /** @@ -902,7 +944,7 @@ public function replaceByKeys($replacementMap) * @param int|null $maxDepth * @return array */ - public function dump($maxItemsPerCollection = null, $maxDepth = null) + public function dump(int $maxItemsPerCollection = null, int $maxDepth = null): array { return dump($this->getItems(), $maxItemsPerCollection, $maxDepth); } @@ -912,24 +954,24 @@ public function dump($maxItemsPerCollection = null, $maxDepth = null) * * @param int|null $maxItemsPerCollection * @param int|null $maxDepth - * @return CollectionInterface + * @return static */ - public function printDump($maxItemsPerCollection = null, $maxDepth = null) + public function printDump(int $maxItemsPerCollection = null, int $maxDepth = null) { - return printDump($this->getItems(), $maxItemsPerCollection, $maxDepth); + printDump($this->getItems(), $maxItemsPerCollection, $maxDepth); + return $this; } /** - * @return array|\Traversable + * @return iterable */ - protected function getItems() - { - return $this; - } + protected abstract function getItems(): iterable; /** - * @param Collection $collection - * @return CollectionInterface + * @template CKey + * @template CVal + * @param callable():iterable|iterable $i + * @return static */ - protected abstract function buildFromCollection(CollectionInterface $collection); + protected abstract static function from($i); } diff --git a/src/RewindableIterable.php b/src/RewindableIterable.php new file mode 100644 index 0000000..967f49c --- /dev/null +++ b/src/RewindableIterable.php @@ -0,0 +1,42 @@ + + */ + private $factory; + + /** + * @param callable(): iterable $factory + */ + public function __construct(callable $factory) + { + $this->factory = function() use ($factory): Traversable { + $iterable = $factory(); + if (is_array($iterable)) { + $iterable = new ArrayIterator($iterable); + } + return $iterable; + }; + } + + /** + * @return Traversable + */ + public function getIterator(): Traversable + { + $fn = $this->factory; + return $fn(); + } +} \ No newline at end of file diff --git a/src/collection_functions.php b/src/collection_functions.php index 29f1a2c..6761a77 100644 --- a/src/collection_functions.php +++ b/src/collection_functions.php @@ -5,17 +5,20 @@ use DusanKasan\Knapsack\Exceptions\InvalidArgument; use DusanKasan\Knapsack\Exceptions\ItemNotFound; use DusanKasan\Knapsack\Exceptions\NoMoreItems; +use Generator; use Iterator; -use IteratorIterator; +use ReflectionObject; use Traversable; /** * Converts $collection to array. If there are multiple items with the same key, only the last will be preserved. * - * @param array|Traversable $collection - * @return array + * @template TKey + * @template TVal + * @param iterable $collection + * @return array */ -function toArray($collection) +function toArray(iterable $collection) { return is_array($collection) ? $collection : iterator_to_array($collection); } @@ -23,14 +26,15 @@ function toArray($collection) /** * Returns a lazy collection of distinct items in $collection. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @return iterable */ -function distinct($collection) +function distinct(iterable $collection): iterable { - $generatorFactory = function () use ($collection) { + $factory = function () use ($collection): Generator { $distinctValues = []; - foreach ($collection as $key => $value) { if (!in_array($value, $distinctValues)) { $distinctValues[] = $value; @@ -39,19 +43,19 @@ function distinct($collection) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns number of items in $collection. * - * @param array|Traversable $collection + * @param iterable $collection * @return int */ -function size($collection) +function size($collection): int { $result = 0; - foreach ($collection as $value) { + foreach ($collection as $_) { $result++; } @@ -61,76 +65,74 @@ function size($collection) /** * Returns a non-lazy collection with items from $collection in reversed order. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @return iterable */ -function reverse($collection) +function reverse(iterable $collection): iterable { - $generatorFactory = function () use ($collection) { + $factory = function () use ($collection): Generator { $array = []; foreach ($collection as $key => $value) { $array[] = [$key, $value]; } - return map( - indexBy( - array_reverse($array), - function ($item) { - return $item[0]; - } - ), - function ($item) { - return $item[1]; - } - ); + foreach (array_reverse($array) as $item) { + yield $item[0] => $item[1]; + } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of values from $collection (i.e. the keys are reset). * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TVal + * @param iterable $collection + * @return iterable */ -function values($collection) +function values(iterable $collection): iterable { - $generatorFactory = function () use ($collection) { + $factory = function () use ($collection): iterable { foreach ($collection as $value) { yield $value; } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of keys from $collection. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @param iterable $collection + * @return iterable */ -function keys($collection) +function keys(iterable $collection): iterable { - $generatorFactory = function () use ($collection) { + $factory = function () use ($collection): Generator { foreach ($collection as $key => $value) { yield $key; } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of items from $collection repeated infinitely. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @return iterable */ -function cycle($collection) +function cycle(iterable $collection): iterable { - $generatorFactory = function () use ($collection) { + $factory = function () use ($collection): Generator { while (true) { foreach ($collection as $key => $value) { yield $key => $value; @@ -138,36 +140,42 @@ function cycle($collection) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a non-lazy collection of shuffled items from $collection. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @return iterable */ -function shuffle($collection) +function shuffle(iterable $collection): iterable { - $buffer = []; - foreach ($collection as $key => $value) { - $buffer[] = [$key, $value]; - } + $factory = function () use ($collection): Traversable { + $buffer = []; + foreach ($collection as $key => $value) { + $buffer[] = [$key, $value]; + } - \shuffle($buffer); + \shuffle($buffer); - return dereferenceKeyValue($buffer); + return dereferenceKeyValue($buffer); + }; + + return new RewindableIterable($factory); } /** * Returns true if $collection does not contain any items. * - * @param array|Traversable $collection + * @param iterable $collection * @return bool */ -function isEmpty($collection) +function isEmpty(iterable $collection): bool { - foreach ($collection as $value) { + foreach ($collection as $_) { return false; } @@ -177,10 +185,10 @@ function isEmpty($collection) /** * Returns true if $collection does contain any items. * - * @param array|Traversable $collection + * @param iterable $collection * @return bool */ -function isNotEmpty($collection) +function isNotEmpty(iterable $collection) { return !isEmpty($collection); } @@ -189,21 +197,32 @@ function isNotEmpty($collection) * Returns a collection where keys are distinct values from $collection and values are number of occurrences of each * value. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TVal + * @param iterable $collection + * @return iterable */ -function frequencies($collection) +function frequencies(iterable $collection): iterable { - return countBy($collection, '\DusanKasan\Knapsack\identity'); + return countBy( + $collection, + /** + * @param mixed $item + * @return mixed + */ + function ($item) { + return $item; + } + ); } /** * Returns the first item of $collection or throws ItemNotFound if #collection is empty. * - * @param array|Traversable $collection - * @return mixed + * @template TVal + * @param iterable $collection + * @return TVal */ -function first($collection) +function first(iterable $collection) { return get(values($collection), 0); } @@ -211,8 +230,9 @@ function first($collection) /** * Returns the last item of $collection or throws ItemNotFound if #collection is empty. * - * @param array|Traversable $collection - * @return mixed + * @template TVal + * @param iterable $collection + * @return TVal */ function last($collection) { @@ -223,37 +243,48 @@ function last($collection) * Returns a lazy collection of items of $collection where value of each item is set to the return value of calling * $function on its value and key. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TVal, TKey):TRes $function + * @return iterable */ -function map($collection, callable $function) +function map(iterable $collection, callable $function): iterable { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { foreach ($collection as $key => $value) { yield $key => $function($value, $key); } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of items from $collection for which $function returns true. * - * @param array|Traversable $collection - * @param callable|null $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool|null $function + * @return iterable */ function filter($collection, callable $function = null) { if (null === $function) { - $function = function ($value) { - return (bool) $value; - }; + $function = + /** + * @param mixed $value + * @param mixed $_ + * @return bool + */ + function ($value, $_): bool { + return (bool)$value; + }; } - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { foreach ($collection as $key => $value) { if ($function($value, $key)) { yield $key => $value; @@ -261,18 +292,20 @@ function filter($collection, callable $function = null) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection with items from all $collections passed as argument appended together * - * @param array|Traversable ...$collections - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable ...$collections + * @return iterable */ -function concat(...$collections) +function concat(iterable ...$collections): iterable { - $generatorFactory = function () use ($collections) { + $factory = function () use ($collections): iterable { foreach ($collections as $collection) { foreach ($collection as $key => $value) { yield $key => $value; @@ -280,7 +313,7 @@ function concat(...$collections) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** @@ -288,12 +321,15 @@ function concat(...$collections) * passing $startValue and current key/item as parameters. The output of $function is used as $startValue in * next iteration. The output of $function on last element is the return value of this function. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @param mixed $startValue - * @return mixed + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TRes, TVal, TKey): TRes $function + * @param TRes $startValue + * @return TRes */ -function reduce($collection, callable $function, $startValue) +function reduce(iterable $collection, callable $function, $startValue) { $tmp = duplicate($startValue); @@ -308,13 +344,13 @@ function reduce($collection, callable $function, $startValue) * Flattens multiple levels of nesting in collection. If $levelsToFlatten is not specified, flattens all levels of * nesting. * - * @param array|Traversable $collection + * @param iterable $collection * @param int $levelsToFlatten -1 to flatten everything - * @return CollectionInterface + * @return iterable */ -function flatten($collection, $levelsToFlatten = -1) +function flatten(iterable $collection, int $levelsToFlatten = -1): iterable { - $generatorFactory = function () use ($collection, $levelsToFlatten) { + $factory = function () use ($collection, $levelsToFlatten): Generator { $flattenNextLevel = $levelsToFlatten < 0 || $levelsToFlatten > 0; $childLevelsToFlatten = $levelsToFlatten > 0 ? $levelsToFlatten - 1 : $levelsToFlatten; @@ -329,38 +365,54 @@ function flatten($collection, $levelsToFlatten = -1) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** - * Returns a non-lazy collection sorted using $collection($item1, $item2, $key1, $key2 ). $collection should + * Returns a non-lazy collection sorted using $function($item1, $item2, $key1, $key2). $function should * return true if first item is larger than the second and false otherwise. * - * @param array|Traversable $collection - * @param callable $function ($value1, $value2, $key1, $key2) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TVal, TKey, TKey): bool $function + * @return iterable */ -function sort($collection, callable $function) +function sort(iterable $collection, callable $function): iterable { - $array = iterator_to_array( - values( - map( - $collection, - function ($value, $key) { - return [$key, $value]; - } + $factory = function () use ($collection, $function): Traversable { + $array = toArray( + values( + map( + $collection, + /** + * @param mixed $value + * @param mixed $key + * @return array + */ + function ($value, $key): array { + return [$key, $value]; + } + ) ) - ) - ); + ); - uasort( - $array, - function ($a, $b) use ($function) { - return $function($a[1], $b[1], $a[0], $b[0]); - } - ); + uasort( + $array, + /** + * @param mixed $a + * @param mixed $b + * @return int + */ + function ($a, $b) use ($function): int { + return (int)$function($a[1], $b[1], $a[0], $b[0]); + } + ); + + return dereferenceKeyValue($array); + }; - return dereferenceKeyValue($array); + return new RewindableIterable($factory); } /** @@ -368,14 +420,16 @@ function ($a, $b) use ($function) { * If $to is not provided, the returned collection is contains all items from $from until end of $collection. All items * before $from are iterated over, but not included in result. * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $from * @param int $to -1 to slice until end - * @return CollectionInterface + * @return iterable */ -function slice($collection, $from, $to = -1) +function slice(iterable $collection, int $from, int $to = -1): iterable { - $generatorFactory = function () use ($collection, $from, $to) { + $factory = function () use ($collection, $from, $to): iterable { $index = 0; foreach ($collection as $key => $value) { if ($index >= $from && ($index < $to || $to == -1)) { @@ -388,69 +442,84 @@ function slice($collection, $from, $to = -1) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a non-lazy collection of items grouped by the result of $function. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TVal, TKey): TRes $function + * @return iterable> */ -function groupBy($collection, callable $function) +function groupBy(iterable $collection, callable $function): iterable { - $result = []; + $factory = function () use ($collection, $function): array { + $result = []; - foreach ($collection as $key => $value) { - $newKey = $function($value, $key); + foreach ($collection as $key => $value) { + $newKey = $function($value, $key); + $result[$newKey][] = $value; + } - $result[$newKey][] = $value; - } + return $result; + }; - return Collection::from($result) - ->map(function ($entry) { - return new Collection($entry); - }); + return new RewindableIterable($factory); } /** * Returns a non-lazy collection of items grouped by the value at given key. Ignores non-collection items and items * without the given keys * - * @param array|Traversable $collection - * @param mixed $key - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable> $collection + * @param TKey $key + * @return iterable> */ -function groupByKey($collection, $key) +function groupByKey(iterable $collection, $key): iterable { - $generatorFactory = function () use ($collection, $key) { - + $generatorFactory = function () use ($collection, $key): iterable { return groupBy( filter( $collection, - function ($item) use ($key) { - return isCollection($item) && has($item, $key); + /** + * @param mixed $item + * @return bool + */ + function ($item) use ($key): bool { + return is_iterable($item) && has($item, $key); } ), + /** + * @param mixed $value + * @return mixed + */ function ($value) use ($key) { return get($value, $key); } ); }; - return new Collection($generatorFactory); + return new RewindableIterable($generatorFactory); } + /** * Executes $function for each item in $collection * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): void $function + * @return iterable */ -function each($collection, callable $function) +function each(iterable $collection, callable $function): iterable { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { foreach ($collection as $key => $value) { $function($value, $key); @@ -458,17 +527,19 @@ function each($collection, callable $function) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns an item with $key key from $collection. If that key is not present, throws ItemNotFound. * - * @param array|Traversable $collection - * @param mixed $key - * @return mixed + * @template TKey + * @template TVal + * @param iterable $collection + * @param TKey $key + * @return TVal */ -function get($collection, $key) +function get(iterable $collection, $key) { foreach ($collection as $valueKey => $value) { if ($key === $valueKey) { @@ -482,12 +553,14 @@ function get($collection, $key) /** * Returns an item with $key key from $collection. If that key is not present, returns $default. * - * @param array|Traversable $collection - * @param mixed $key - * @param mixed $default value returned if key is not found - * @return mixed + * @template TKey + * @template TVal + * @param iterable $collection + * @param TKey $key + * @param TVal $default value returned if key is not found + * @return TVal */ -function getOrDefault($collection, $key, $default) +function getOrDefault(iterable $collection, $key, $default) { try { return get($collection, $key); @@ -500,12 +573,14 @@ function getOrDefault($collection, $key, $default) * Returns the first item from $collection for which $function returns true. If item like that is not present, returns * $default. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @param mixed $default - * @return mixed + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function + * @param TVal|null $default + * @return TVal|null */ -function find($collection, callable $function, $default = null) +function find(iterable $collection, callable $function, $default = null) { foreach ($collection as $key => $value) { if ($function($value, $key)) { @@ -520,42 +595,56 @@ function find($collection, callable $function, $default = null) * Returns a lazy collection by changing keys of $collection for each item to the result of $function for * that item. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @template TNewKey + * @param iterable $collection + * @param callable(TVal, TKey): TNewKey $function + * @return iterable */ function indexBy($collection, callable $function) { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { foreach ($collection as $key => $value) { yield $function($value, $key) => $value; } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a non-lazy collection of items whose keys are the return values of $function and values are the number of * items in this collection for which the $function returned this value. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TVal, TKey): TRes $function + * @return iterable */ function countBy($collection, callable $function) { return map( groupBy($collection, $function), - '\DusanKasan\Knapsack\size' + /** + * @param mixed $c + * @return int + */ + function ($c): int { + return size($c); + } ); } /** * Returns true if $function returns true for every item in $collection * - * @param array|Traversable $collection - * @param callable $function ($value, $key) + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function * @return bool */ function every($collection, callable $function) @@ -572,8 +661,10 @@ function every($collection, callable $function) /** * Returns true if $function returns true for at least one item in $collection. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function * @return bool */ function some($collection, callable $function) @@ -590,7 +681,7 @@ function some($collection, callable $function) /** * Returns true if $needle is found in $collection values. * - * @param array|Traversable $collection + * @param iterable $collection * @param mixed $needle * @return bool */ @@ -608,12 +699,15 @@ function contains($collection, $needle) /** * Reduce that walks from right to the left. * - * @param array|Traversable $collection - * @param callable $function - * @param mixed $startValue - * @return mixed + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TRes, TVal, TKey): TRes $function + * @param TRes $startValue + * @return TRes */ -function reduceRight($collection, callable $function, $startValue) +function reduceRight(iterable $collection, callable $function, $startValue) { return reduce(reverse($collection), $function, $startValue); } @@ -621,11 +715,13 @@ function reduceRight($collection, callable $function, $startValue) /** * Returns a lazy collection of first $numberOfItems items of $collection. * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $numberOfItems - * @return CollectionInterface + * @return iterable */ -function take($collection, $numberOfItems) +function take(iterable $collection, int $numberOfItems): iterable { return slice($collection, 0, $numberOfItems); } @@ -633,11 +729,13 @@ function take($collection, $numberOfItems) /** * Returns a lazy collection of all but first $numberOfItems items of $collection. * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $numberOfItems - * @return CollectionInterface + * @return iterable */ -function drop($collection, $numberOfItems) +function drop(iterable $collection, int $numberOfItems): iterable { return slice($collection, $numberOfItems); } @@ -647,14 +745,15 @@ function drop($collection, $numberOfItems) * $function to the last value in the collection. By default this produces an infinite collection. However you can * end the collection by throwing a NoMoreItems exception. * - * @param mixed $value - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TVal + * @param TVal $value + * @param callable(TVal): TVal $function + * @return iterable */ function iterate($value, callable $function) { $duplicated = duplicate($value); - $generatorFactory = function () use ($duplicated, $function) { + $factory = function () use ($duplicated, $function): iterable { $value = $duplicated; yield $value; @@ -669,21 +768,28 @@ function iterate($value, callable $function) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of items from $collection for which $function returned true. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function + * @return iterable */ -function reject($collection, callable $function) +function reject(iterable $collection, callable $function): iterable { return filter( $collection, - function ($value, $key) use ($function) { + /** + * @param mixed $value + * @param mixed $key + * @return bool + */ + function ($value, $key) use ($function): bool { return !$function($value, $key); } ); @@ -692,13 +798,15 @@ function ($value, $key) use ($function) { /** * Returns a lazy collection of items in $collection without the last $numberOfItems items. * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $numberOfItems - * @return CollectionInterface + * @return iterable */ -function dropLast($collection, $numberOfItems = 1) +function dropLast(iterable $collection, $numberOfItems = 1): iterable { - $generatorFactory = function () use ($collection, $numberOfItems) { + $factory = function () use ($collection, $numberOfItems): iterable { $buffer = []; foreach ($collection as $key => $value) { @@ -711,19 +819,21 @@ function dropLast($collection, $numberOfItems = 1) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of items from $collection separated by $separator. * - * @param array|Traversable $collection - * @param mixed $separator - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param TVal $separator + * @return iterable */ -function interpose($collection, $separator) +function interpose(iterable $collection, $separator): iterable { - $generatorFactory = function () use ($collection, $separator) { + $factory = function () use ($collection, $separator): iterable { foreach (take($collection, 1) as $key => $value) { yield $key => $value; } @@ -734,23 +844,25 @@ function interpose($collection, $separator) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of first item from first collection, first item from second, second from first and * so on. Accepts any number of collections. * - * @param array|Traversable ...$collections - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable ...$collections + * @return iterable */ -function interleave(...$collections) +function interleave(iterable ...$collections): iterable { - $generatorFactory = function () use ($collections) { + $generatorFactory = function () use ($collections): iterable { /* @var Iterator[] $iterators */ $iterators = array_map( function ($collection) { - $it = new IteratorIterator(new Collection($collection)); + $it = iterableToIterator($collection); $it->rewind(); return $it; }, @@ -769,21 +881,23 @@ function ($collection) { } while ($valid); }; - return new Collection($generatorFactory); + return new RewindableIterable($generatorFactory); } /** * Returns a lazy collection of items in $collection with $value added as first element. If $key is not provided * it will be next integer index. * - * @param array|Traversable $collection - * @param mixed $value - * @param mixed|null $key - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param TVal $value + * @param TKey|null $key + * @return iterable */ -function prepend($collection, $value, $key = null) +function prepend(iterable $collection, $value, $key = null): iterable { - $generatorFactory = function () use ($collection, $value, $key) { + $generatorFactory = function () use ($collection, $value, $key): iterable { if ($key === null) { yield $value; } else { @@ -795,21 +909,23 @@ function prepend($collection, $value, $key = null) } }; - return new Collection($generatorFactory); + return new RewindableIterable($generatorFactory); } /** * Returns a lazy collection of items in $collection with $value added as last element. If $key is not provided * it will be next integer index. * - * @param array|Traversable $collection - * @param mixed $value - * @param mixed|null $key - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param TVal $value + * @param TKey|null $key + * @return iterable */ -function append($collection, $value, $key = null) +function append(iterable $collection, $value, $key = null): iterable { - $generatorFactory = function () use ($collection, $value, $key) { + $generatorFactory = function () use ($collection, $value, $key): iterable { foreach ($collection as $k => $v) { yield $k => $v; } @@ -821,19 +937,21 @@ function append($collection, $value, $key = null) } }; - return new Collection($generatorFactory); + return new RewindableIterable($generatorFactory); } /** * Returns a lazy collection by removing items from $collection until first item for which $function returns false. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function + * @return iterable */ -function dropWhile($collection, callable $function) +function dropWhile(iterable $collection, callable $function): iterable { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { $shouldDrop = true; foreach ($collection as $key => $value) { if ($shouldDrop) { @@ -846,19 +964,21 @@ function dropWhile($collection, callable $function) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of items from $collection until first item for which $function returns false. * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function + * @return iterable */ function takeWhile($collection, callable $function) { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { $shouldTake = true; foreach ($collection as $key => $value) { if ($shouldTake) { @@ -871,17 +991,20 @@ function takeWhile($collection, callable $function) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection. A result of calling map and flatten(1) * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TVal, TKey): iterable $function + * @return iterable */ -function mapcat($collection, callable $function) +function mapcat(iterable $collection, callable $function): iterable { return flatten(map($collection, $function), 1); } @@ -889,68 +1012,76 @@ function mapcat($collection, callable $function) /** * Returns a lazy collection [take($collection, $position), drop($collection, $position)] * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $position - * @return CollectionInterface + * @return iterable> */ -function splitAt($collection, $position) +function splitAt(iterable $collection, int $position): iterable { - $generatorFactory = function () use ($collection, $position) { + $factory = function () use ($collection, $position): Generator { yield take($collection, $position); yield drop($collection, $position); }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection [takeWhile($collection, $function), dropWhile($collection, $function)] * - * @param array|Traversable $collection - * @param callable $function ($value, $key) - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey): bool $function + * @return iterable> */ -function splitWith($collection, callable $function) +function splitWith($collection, callable $function): iterable { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { yield takeWhile($collection, $function); yield dropWhile($collection, $function); }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection with items from $collection but values that are found in keys of $replacementMap * are replaced by their values. * - * @param array|Traversable $collection - * @param array|Traversable $replacementMap - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param iterable $replacementMap + * @return iterable */ -function replace($collection, $replacementMap) +function replace(iterable $collection, iterable $replacementMap): iterable { - $generatorFactory = function () use ($collection, $replacementMap) { + $factory = function () use ($collection, $replacementMap): iterable { foreach ($collection as $key => $value) { - $newValue = getOrDefault($replacementMap, $value, $value); - yield $key => $newValue; + yield $key => getOrDefault($replacementMap, $value, $value); } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of reduction steps. * - * @param array|Traversable $collection - * @param callable $function - * @param mixed $startValue - * @return CollectionInterface + * @template TKey + * @template TVal + * @template TRes + * @param iterable $collection + * @param callable(TRes, TVal, TKey): TRes $function + * @param TRes $startValue + * @return iterable */ -function reductions($collection, callable $function, $startValue) +function reductions(iterable $collection, callable $function, $startValue): iterable { - $generatorFactory = function () use ($collection, $function, $startValue) { + $factory = function () use ($collection, $function, $startValue): iterable { $tmp = duplicate($startValue); yield $tmp; @@ -960,19 +1091,21 @@ function reductions($collection, callable $function, $startValue) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of every nth ($step) item in $collection. * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $step - * @return CollectionInterface + * @return iterable */ -function takeNth($collection, $step) +function takeNth(iterable $collection, int $step) { - $generatorFactory = function () use ($collection, $step) { + $factory = function () use ($collection, $step): iterable { $index = 0; foreach ($collection as $key => $value) { if ($index % $step == 0) { @@ -983,7 +1116,7 @@ function takeNth($collection, $step) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** @@ -993,15 +1126,17 @@ function takeNth($collection, $step) * necessary to complete last partition up to $numberOfItems items. In case there are * not enough padding elements, return a partition with less than $numberOfItems items. * - * @param array|Traversable $collection + * @template TKey + * @template TVal + * @param iterable $collection * @param int $numberOfItems * @param int $step - * @param array|Traversable $padding - * @return CollectionInterface + * @param iterable $padding + * @return iterable> */ -function partition($collection, $numberOfItems, $step = -1, $padding = []) +function partition(iterable $collection, int $numberOfItems, int $step = -1, iterable $padding = []): iterable { - $generatorFactory = function () use ($collection, $numberOfItems, $step, $padding) { + $generator = function () use ($collection, $numberOfItems, $step, $padding): Generator { $buffer = []; $itemsToSkip = 0; $tmpStep = $step ?: $numberOfItems; @@ -1021,25 +1156,24 @@ function partition($collection, $numberOfItems, $step = -1, $padding = []) } } - yield take( - concat(dereferenceKeyValue($buffer), $padding), - $numberOfItems - ); + yield take(concat(dereferenceKeyValue($buffer), $padding), $numberOfItems); }; - return new Collection($generatorFactory); + return new RewindableIterable($generator); } /** * Returns a lazy collection created by partitioning $collection each time $function returned a different value. * - * @param array|Traversable $collection - * @param callable $function - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param callable(TVal, TKey=): mixed $function + * @return iterable> */ -function partitionBy($collection, callable $function) +function partitionBy(iterable $collection, callable $function): iterable { - $generatorFactory = function () use ($collection, $function) { + $factory = function () use ($collection, $function): iterable { $result = null; $buffer = []; @@ -1060,19 +1194,20 @@ function partitionBy($collection, callable $function) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of $value repeated $times times. If $times is not provided the collection is infinite. * - * @param mixed $value + * @template TVal + * @param TVal $value * @param int $times - * @return CollectionInterface + * @return iterable */ -function repeat($value, $times = -1) +function repeat($value, int $times = -1): iterable { - $generatorFactory = function () use ($value, $times) { + $factory = function () use ($value, $times): iterable { $tmpTimes = $times; while ($tmpTimes != 0) { @@ -1082,7 +1217,7 @@ function repeat($value, $times = -1) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** @@ -1091,14 +1226,14 @@ function repeat($value, $times = -1) * @param int $start * @param int|null $end * @param int $step - * @return CollectionInterface + * @return iterable */ -function range($start = 0, $end = null, $step = 1) +function range(int $start = 0, int $end = null, int $step = 1): iterable { - $generatorFactory = function () use ($start, $end, $step) { + $factory = function () use ($start, $end, $step): iterable { return iterate( $start, - function ($value) use ($step, $end) { + function (int $value) use ($step, $end): int { $result = $value + $step; if ($end !== null && $result > $end) { @@ -1110,26 +1245,16 @@ function ($value) use ($step, $end) { ); }; - return new Collection($generatorFactory); -} - -/** - * Returns true if $input is array or Traversable object. - * - * @param mixed $input - * @return bool - */ -function isCollection($input) -{ - return is_array($input) || $input instanceof Traversable; + return new RewindableIterable($factory); } /** * Returns duplicated/cloned $input that has no relation to the original one. Used for making sure there are no side * effect in functions. * - * @param mixed $input - * @return mixed + * @template TVal + * @param TVal $input + * @return TVal */ function duplicate($input) { @@ -1137,6 +1262,10 @@ function duplicate($input) return toArray( map( $input, + /** + * @param mixed $i + * @return mixed + */ function ($i) { return duplicate($i); } @@ -1152,33 +1281,37 @@ function ($i) { /** * Transforms [[$key, $value], [$key2, $value2]] into [$key => $value, $key2 => $value2]. Used as a helper * - * @param array|Traversable $collection - * @return CollectionInterface + * @TODO: types + * @param iterable $collection + * @return Traversable */ -function dereferenceKeyValue($collection) +function dereferenceKeyValue(iterable $collection): Traversable { - $generatorFactory = function () use ($collection) { - foreach ($collection as $value) { - yield $value[0] => $value[1]; - } - }; - - return new Collection($generatorFactory); + foreach ($collection as $value) { + yield $value[0] => $value[1]; + } } /** * Realizes collection - turns lazy collection into non-lazy one by iterating over it and storing the key/values. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @return iterable */ -function realize($collection) +function realize(iterable $collection): iterable { return dereferenceKeyValue( toArray( map( $collection, - function ($value, $key) { + /** + * @param mixed $value + * @param mixed $key + * @return array + */ + function ($value, $key): array { return [$key, $value]; } ) @@ -1189,8 +1322,11 @@ function ($value, $key) { /** * Returns the second item of $collection or throws ItemNotFound if $collection is empty or has 1 item. * - * @param array|Traversable $collection - * @return mixed + * @template TKey + * @template TVal + * @param iterable $collection + * @return TVal + * @throws ItemNotFound */ function second($collection) { @@ -1201,44 +1337,50 @@ function second($collection) * Combines $keys and $values into a lazy collection. The resulting collection has length equal to the size of smaller * argument. * - * @param array|Traversable $keys - * @param array|Traversable $values - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $keys + * @param iterable $values + * @return iterable */ -function combine($keys, $values) +function combine(iterable $keys, iterable $values): iterable { - $generatorFactory = function () use ($keys, $values) { - $keyCollection = new Collection($keys); - $valueIt = new IteratorIterator(new Collection($values)); - $valueIt->rewind(); - - foreach ($keyCollection as $key) { - if (!$valueIt->valid()) { + $values = iterableToIterator($values); + $factory = function () use ($keys, $values): iterable { + foreach ($keys as $key) { + if (!$values->valid()) { break; } - yield $key => $valueIt->current(); - $valueIt->next(); + yield $key => $values->current(); + $values->next(); } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection without the items associated to any of the keys from $keys. * - * @param array|Traversable $collection - * @param array|Traversable $keys - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param iterable $keys + * @return iterable */ -function except($collection, $keys) +function except(iterable $collection, iterable $keys): iterable { $keys = toArray(values($keys)); return reject( $collection, - function ($value, $key) use ($keys) { + /** + * @param mixed $value + * @param mixed $key + * @return bool + */ + function ($value, $key) use ($keys): bool { return in_array($key, $keys); } ); @@ -1247,9 +1389,11 @@ function ($value, $key) use ($keys) { /** * Returns a lazy collection of items associated to any of the keys from $keys. * - * @param array|Traversable $collection - * @param array|Traversable $keys - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param iterable $keys + * @return iterable */ function only($collection, $keys) { @@ -1257,7 +1401,12 @@ function only($collection, $keys) return filter( $collection, - function ($value, $key) use ($keys) { + /** + * @param mixed $_ + * @param mixed $key + * @return bool + */ + function ($_, $key) use ($keys): bool { return in_array($key, $keys, true); } ); @@ -1267,14 +1416,16 @@ function ($value, $key) use ($keys) { * Returns a lazy collection of items that are in $collection but are not in any of the other arguments, indexed by the * keys from the first collection. Note that the ...$collections are iterated non-lazily. * - * @param array|Traversable $collection - * @param array|Traversable ...$collections - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param iterable ...$collections + * @return iterable */ -function diff($collection, ...$collections) +function diff(iterable $collection, ...$collections) { $valuesToCompare = toArray(values(concat(...$collections))); - $generatorFactory = function () use ($collection, $valuesToCompare) { + $factory = function () use ($collection, $valuesToCompare): iterable { foreach ($collection as $key => $value) { if (!in_array($value, $valuesToCompare)) { yield $key => $value; @@ -1282,21 +1433,23 @@ function diff($collection, ...$collections) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection of items that are in $collection and all the other arguments, indexed by the keys from the * first collection. Note that the ...$collections are iterated non-lazily. * - * @param array|Traversable $collection - * @param array|Traversable ...$collections - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param iterable ...$collections + * @return iterable */ -function intersect($collection, ...$collections) +function intersect(iterable $collection, iterable ...$collections): iterable { $valuesToCompare = toArray(values(concat(...$collections))); - $generatorFactory = function () use ($collection, $valuesToCompare) { + $factory = function () use ($collection, $valuesToCompare): iterable { foreach ($collection as $key => $value) { if (in_array($value, $valuesToCompare)) { yield $key => $value; @@ -1304,34 +1457,37 @@ function intersect($collection, ...$collections) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Returns a lazy collection where keys and values are flipped. * - * @param array|Traversable $collection - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @return iterable */ function flip($collection) { - $generatorFactory = function () use ($collection) { + $factory = function () use ($collection): iterable { foreach ($collection as $key => $value) { yield $value => $key; } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Checks for the existence of an item with key $key in $collection. * - * @param array|Traversable $collection - * @param mixed $key + * @template TKey + * @param iterable $collection + * @param TKey $key * @return bool */ -function has($collection, $key) +function has(iterable $collection, $key): bool { try { get($collection, $key); @@ -1345,25 +1501,27 @@ function has($collection, $key) * Returns a lazy collection of non-lazy collections of items from nth position from each passed collection. Stops when * any of the collections don't have an item at the nth position. * - * @param array|Traversable ...$collections - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable ...$collections + * @return iterable> */ -function zip(...$collections) +function zip(iterable ...$collections): iterable { /* @var Iterator[] $iterators */ $iterators = array_map( function ($collection) { - $it = new IteratorIterator(new Collection($collection)); + $it = iterableToIterator($collection); $it->rewind(); return $it; }, $collections ); - $generatorFactory = function () use ($iterators) { + $factory = function () use ($iterators): iterable { while (true) { $isMissingItems = false; - $zippedItem = new Collection([]); + $zippedItem = []; foreach ($iterators as $it) { if (!$it->valid()) { @@ -1383,34 +1541,42 @@ function ($collection) { } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Transpose each item in a collection, interchanging the row and column indexes. * Can only transpose collections of collections. Otherwise an InvalidArgument is raised. * - * @param Collection[] $collection - * @return CollectionInterface + * @template TVal + * @param iterable> $collection + * @return iterable> */ -function transpose($collection) +function transpose(iterable $collection): iterable { - if (some($collection, function ($value) { - return !($value instanceof CollectionInterface); - })) { + if (some( + $collection, + /** + * @param mixed $value + * @return bool + */ + function ($value): bool { + return !is_iterable($value); + } + )) { throw new InvalidArgument('Can only transpose collections of collections.'); } - return Collection::from( - array_map( - function (...$items) { - return new Collection($items); - }, - ...toArray( - map( - $collection, - 'DusanKasan\Knapsack\toArray' - ) + return array_map( + function (...$items) { + return $items; + }, + ...toArray( + map( + $collection, + function (iterable $c): array { + return toArray($c); + } ) ) ); @@ -1420,18 +1586,30 @@ function (...$items) { * Returns a lazy collection of data extracted from $collection items by dot separated key path. Supports the * * wildcard. If a key contains \ or * it must be escaped using \ character. * - * @param array|Traversable $collection - * @param mixed $keyPath - * @return CollectionInterface + * @param iterable $collection + * @param string $keyPath + * @return iterable */ -function extract($collection, $keyPath) +function extract(iterable $collection, string $keyPath): iterable { preg_match_all('/(.*[^\\\])(?:\.|$)/U', $keyPath, $matches); $pathParts = $matches[1]; - $extractor = function ($coll) use ($pathParts) { + $extractor = function (iterable $coll) use ($pathParts): iterable { foreach ($pathParts as $pathPart) { - $coll = flatten(filter($coll, '\DusanKasan\Knapsack\isCollection'), 1); + $coll = flatten( + filter( + $coll, + /** + * @param mixed $item + * @return bool + */ + function ($item) { + return is_iterable($item); + } + ), + 1 + ); if ($pathPart != '*') { $pathPart = str_replace(['\.', '\*'], ['.', '*'], $pathPart); @@ -1442,7 +1620,7 @@ function extract($collection, $keyPath) return $coll; }; - $generatorFactory = function () use ($collection, $extractor) { + $factory = function () use ($collection, $extractor): iterable { foreach ($collection as $item) { foreach ($extractor([$item]) as $extracted) { yield $extracted; @@ -1450,17 +1628,17 @@ function extract($collection, $keyPath) } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** * Checks whether $collection has exactly $size items. * - * @param array|Traversable $collection + * @param iterable $collection * @param int $size * @return bool */ -function sizeIs($collection, $size) +function sizeIs(iterable $collection, int $size): bool { $itemsTempCount = 0; @@ -1478,11 +1656,11 @@ function sizeIs($collection, $size) /** * Checks whether $collection has less than $size items. * - * @param array|Traversable $collection + * @param iterable $collection * @param int $size * @return bool */ -function sizeIsLessThan($collection, $size) +function sizeIsLessThan(iterable $collection, int $size): bool { $itemsTempCount = 0; @@ -1500,11 +1678,11 @@ function sizeIsLessThan($collection, $size) /** * Checks whether $collection has more than $size items. * - * @param array|Traversable $collection + * @param iterable $collection * @param int $size * @return bool */ -function sizeIsGreaterThan($collection, $size) +function sizeIsGreaterThan(iterable $collection, int $size): bool { $itemsTempCount = 0; @@ -1523,12 +1701,12 @@ function sizeIsGreaterThan($collection, $size) * Checks whether $collection has between $fromSize to $toSize items. $toSize can be * smaller than $fromSize. * - * @param array|Traversable $collection + * @param iterable $collection * @param int $fromSize * @param int $toSize * @return bool */ -function sizeIsBetween($collection, $fromSize, $toSize) +function sizeIsBetween(iterable $collection, int $fromSize, int $toSize): bool { if ($fromSize > $toSize) { $tmp = $toSize; @@ -1551,10 +1729,11 @@ function sizeIsBetween($collection, $fromSize, $toSize) /** * Returns a sum of all values in the $collection. * - * @param array|Traversable $collection - * @return int|float + * @template TVal of numeric + * @param iterable $collection + * @return TVal */ -function sum($collection) +function sum(iterable $collection) { $result = 0; @@ -1568,8 +1747,8 @@ function sum($collection) /** * Returns average of values from $collection. * - * @param array|Traversable $collection - * @return int|float + * @param iterable $collection + * @return float */ function average($collection) { @@ -1581,14 +1760,15 @@ function average($collection) $count++; } - return $count ? $sum/$count : 0; + return (float)($count ? $sum / $count : 0); } /** * Returns maximal value from $collection. * - * @param array|Traversable $collection - * @return mixed + * @template TVal of numeric + * @param iterable $collection + * @return TVal */ function max($collection) { @@ -1604,8 +1784,9 @@ function max($collection) /** * Returns minimal value from $collection. * - * @param array|Traversable $collection - * @return mixed + * @template TVal of numeric + * @param iterable $collection + * @return TVal */ function min($collection) { @@ -1627,7 +1808,7 @@ function min($collection) /** * Returns a string by concatenating the $collection values into a string. * - * @param array|Traversable $collection + * @param iterable $collection * @return string */ function toString($collection) @@ -1635,7 +1816,7 @@ function toString($collection) $result = ''; foreach ($collection as $value) { - $result .= (string) $value; + $result .= (string)$value; } return $result; @@ -1643,23 +1824,25 @@ function toString($collection) /** - * Returns a lazy collection with items from $collection, but items with keys that are found in keys of $replacementMap + * Returns a lazy collection with items from $collection, but items with keys that are found in keys of $replacementMap * are replaced by their values. * - * @param array|Traversable $collection - * @param array|Traversable $replacementMap - * @return CollectionInterface + * @template TKey + * @template TVal + * @param iterable $collection + * @param iterable $replacementMap + * @return iterable */ function replaceByKeys($collection, $replacementMap) { - $generatorFactory = function () use ($collection, $replacementMap) { + $factory = function () use ($collection, $replacementMap): iterable { foreach ($collection as $key => $value) { $newValue = getOrDefault($replacementMap, $key, $value); yield $key => $newValue; } }; - return new Collection($generatorFactory); + return new RewindableIterable($factory); } /** @@ -1686,7 +1869,7 @@ function replaceByKeys($collection, $replacementMap) * @param int|null $maxDepth * @return array|mixed */ -function dump($input, $maxItemsPerCollection = null, $maxDepth = null) +function dump($input, int $maxItemsPerCollection = null, int $maxDepth = null) { if (is_scalar($input)) { return $input; @@ -1710,7 +1893,7 @@ function dump($input, $maxItemsPerCollection = null, $maxDepth = null) $normalizedProperties[$betterKey] = dump( $value, $maxItemsPerCollection, - $maxDepth>0 ? $maxDepth-1 : null + $maxDepth > 0 ? $maxDepth - 1 : null ); break; @@ -1726,13 +1909,13 @@ function dump($input, $maxItemsPerCollection = null, $maxDepth = null) return '^^^'; } - $reflection = new \ReflectionObject($input); + $reflection = new ReflectionObject($input); $normalizedProperties = []; foreach ($reflection->getProperties() as $property) { $property->setAccessible(true); $normalizedProperties[$property->getName()] = $property->getValue($input); } - return [get_class($input) => dump($normalizedProperties, null, $maxDepth>0 ? $maxDepth-1 : null)]; + return [get_class($input) => dump($normalizedProperties, null, $maxDepth > 0 ? $maxDepth - 1 : null)]; } return gettype($input); @@ -1741,12 +1924,13 @@ function dump($input, $maxItemsPerCollection = null, $maxDepth = null) /** * Calls dump on $input and then prints it using the var_export. Returns $input. * - * @param mixed $input + * + * @param iterable $input * @param int|null $maxItemsPerCollection * @param int|null $maxDepth * @return mixed */ -function printDump($input, $maxItemsPerCollection = null, $maxDepth = null) +function printDump(iterable $input, int $maxItemsPerCollection = null, int $maxDepth = null) { var_export(dump($input, $maxItemsPerCollection, $maxDepth)); return $input; diff --git a/src/utility_functions.php b/src/utility_functions.php index b71228b..f78389d 100644 --- a/src/utility_functions.php +++ b/src/utility_functions.php @@ -2,6 +2,10 @@ namespace DusanKasan\Knapsack; +use ArrayIterator; +use Iterator; +use IteratorAggregate; + /** * Returns its argument. * @@ -51,3 +55,22 @@ function decrement($value) { return $value - 1; } + +/** + * Converts any iterable to an Iterator. + * + * @param iterable $iterable + * @return Iterator + */ +function iterableToIterator(iterable $iterable): Iterator { + if ($iterable instanceof IteratorAggregate) { + $iterable = $iterable->getIterator(); + } + + if ($iterable instanceof Iterator) { + return $iterable; + } + + /** @var array $iterable */ + return new ArrayIterator($iterable); +} \ No newline at end of file diff --git a/tests/spec/CollectionSpec.php b/tests/spec/CollectionSpec.php index ba3967d..579146e 100644 --- a/tests/spec/CollectionSpec.php +++ b/tests/spec/CollectionSpec.php @@ -404,8 +404,8 @@ function ($v) { ) ->shouldReturn('not found'); - $this->find('\DusanKasan\Knapsack\isCollection', null, true)->first()->shouldReturn(5); - $this->find('\DusanKasan\Knapsack\isCollection')->shouldReturn([5]); + $this->find(function($item) {return is_iterable($item);}, null, true)->first()->shouldReturn(5); + $this->find(function($item) {return is_iterable($item);})->shouldReturn([5]); } function it_can_count_by() @@ -1188,14 +1188,14 @@ function it_can_sum_the_collection() function it_can_get_average_of_the_collection() { $this->beConstructedWith([1, 2, 2, 3]); - $this->average()->shouldReturn(2); + $this->average()->shouldReturn(2.0); $this->append(3)->average()->shouldReturn(2.2); } function it_will_return_zero_when_average_is_called_on_empty_collection() { $this->beConstructedWith([]); - $this->average()->shouldReturn(0); + $this->average()->shouldReturn(0.0); } function it_can_get_maximal_value_in_the_colleciton() @@ -1267,12 +1267,12 @@ function it_can_transpose_arrays_of_different_lengths() function it_should_throw_an_invalid_argument_if_collection_items_are_not_collection() { $this->beConstructedWith([ - [1, 2, 3], + 1, [4, 5, 6], [7, 8, 9], ]); - $this->shouldThrow(InvalidArgument::class)->during('transpose'); + $this->transpose()->getIterator()->shouldThrow(InvalidArgument::class)->during('rewind'); } function it_can_use_the_utility_methods()