├── .editorconfig ├── .github └── workflows │ └── php.yml ├── .gitignore ├── .php_cs.dist ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── docs └── definition.md ├── phpcs.xml ├── phpunit.xml ├── psalm.xml ├── src └── Enum.php └── tests ├── EqualityTest.php ├── ExistenceTest.php ├── Fixtures ├── AbstractTestEnum.php └── FooEnum.php ├── InheritanceTest.php ├── MiscTest.php ├── NameTest.php ├── ResolveTest.php └── SerializeTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | max_line_length = off 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: php 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | tests: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | php-versions: ['7.1', '7.2', '7.3', '7.4'] 11 | name: PHP ${{ matrix.php-versions }} test 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | - name: Setup PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: ${{ matrix.php-versions }} 20 | extensions: mbstring, ctype, intl, xml, pdo 21 | coverage: xdebug 22 | 23 | - name: Setup Problem Matchers for PHP 24 | run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" 25 | 26 | - name: Setup Problem Matchers for PHPUnit 27 | run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" 28 | 29 | - name: Validate composer.json and composer.lock 30 | run: composer validate 31 | 32 | - name: Install dependencies 33 | run: composer install --prefer-dist --no-progress --no-suggest 34 | 35 | - name: Run tests 36 | run: vendor/bin/simple-phpunit --coverage-clover=build/logs/clover.xml 37 | 38 | - name: Send coverage data 39 | run: vendor/bin/php-coveralls 40 | env: 41 | COVERALLS_REPO_TOKEN: ${{ secrets.CoverallsRepoToken }} 42 | 43 | coding-standards: 44 | name: Coding Standards 45 | runs-on: ubuntu-latest 46 | steps: 47 | - name: Checkout 48 | uses: actions/checkout@v2 49 | 50 | - name: Setup PHP 51 | uses: shivammathur/setup-php@v2 52 | with: 53 | php-version: '7.3' 54 | extensions: mbstring, ctype, intl, xml, pdo 55 | tools: cs2pr 56 | 57 | - name: Validate composer.json and composer.lock 58 | run: composer validate 59 | 60 | - name: Install dependencies 61 | run: composer install --prefer-dist --no-progress --no-suggest 62 | 63 | - name: PHP CodeSniffer 64 | run: vendor/bin/phpcs -q --report=checkstyle | cs2pr --graceful-warnings 65 | 66 | static-analysis: 67 | name: Static Analysis 68 | runs-on: ubuntu-latest 69 | steps: 70 | - name: Checkout 71 | uses: actions/checkout@v2 72 | 73 | - name: Setup PHP 74 | uses: shivammathur/setup-php@v2 75 | with: 76 | php-version: '7.3' 77 | extensions: mbstring, ctype, intl, xml, pdo 78 | tools: cs2pr 79 | 80 | - name: Validate composer.json and composer.lock 81 | run: composer validate 82 | 83 | - name: Install dependencies 84 | run: composer install --prefer-dist --no-progress --no-suggest 85 | 86 | - name: Static analysis using Psalm 87 | run: vendor/bin/psalm --output-format=github --no-progress 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /vendor/ 3 | 4 | /.phpunit.result.cache 5 | /.php_cs.cache 6 | -------------------------------------------------------------------------------- /.php_cs.dist: -------------------------------------------------------------------------------- 1 | in(__DIR__.'/src') 5 | ->in(__DIR__.'/tests') 6 | ; 7 | 8 | return PhpCsFixer\Config::create() 9 | ->setCacheFile(__DIR__.'/.php_cs.cache') 10 | ->setRiskyAllowed(false) 11 | ->setRules([ 12 | '@PSR2' => true, 13 | 'yoda_style' => false, 14 | 'trailing_comma_in_multiline_array' => false, 15 | 'single_blank_line_before_namespace' => true, 16 | 'no_leading_namespace_whitespace' => true, 17 | 'ordered_imports' => true, 18 | 'no_unused_imports' => true, 19 | 'phpdoc_var_without_name' => false, 20 | 'no_superfluous_phpdoc_tags' => false, 21 | 'single_line_throw' => false 22 | ]) 23 | ->setFinder($finder) 24 | ; 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Maarten de Boer, Cloudstek 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Enum 2 | 3 | > Enumeration support for PHP. 4 | 5 | [![Build Status](https://img.shields.io/github/workflow/status/Cloudstek/php-enum/php)](https://github.com/Cloudstek/php-enum/actions) [![Coverage Status](https://coveralls.io/repos/github/Cloudstek/php-enum/badge.svg)](https://coveralls.io/github/Cloudstek/php-enum) ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/Cloudstek/php-enum?label=latest) ![Downloads](https://img.shields.io/packagist/dt/cloudstek/php-enum) ![GitHub](https://img.shields.io/github/license/Cloudstek/php-enum) ![GitHub stars](https://img.shields.io/github/stars/Cloudstek/php-enum) 6 | 7 | This package adds support for [enumerations](https://en.wikipedia.org/wiki/Enumerated_type) to PHP, ~~which are unfortunately not supported natively~~. 8 | 9 | ⚠️ Since PHP 8.1 there is finally native support for enums in PHP. Please consider upgrading to PHP 8.1+ and migrating away from this package if you require enums in your application. 10 | 11 | Using a simple class with constants alone doesn't allow you to use type hints meaning you still have to do extensive checks whether the value is expected. This package allows you to define enumerations the same way but allows for type hinting for example your method parameter. This way you can always be sure it holds a concrete set of members and values. 12 | 13 | ## Requirements 14 | 15 | - PHP 7.1+ 16 | - Composer* 17 | 18 | *\* Installation without composer is possible as the package consists of a single class, but is obviously not recommended.* 19 | 20 | ## Installation 21 | 22 | Install the package through composer: 23 | 24 | ```bash 25 | composer require cloudstek/php-enum 26 | ``` 27 | 28 | ## Usage 29 | 30 | ### Definition 31 | 32 | The `Cloudstek\Enum\Enum` base class takes care of all the work behind the scenes so all you have to do is extend your enum class from that and define your members using either properties, constants, methods or a mix of those. 33 | 34 | Take for example this `TaskStatus` enum with three members: `TODO`, `IN_PROGRESS` and `DONE`. Each has a string value in this example but you're free to assign any kind of value you like. 35 | 36 | ```php 37 | use Cloudstek\Enum\Enum; 38 | 39 | /** 40 | * @method static self TODO() 41 | * @method static self IN_PROGRESS() 42 | * @method static self DONE() 43 | */ 44 | class TaskStatus extends Enum 45 | { 46 | private const TODO = 'todo'; 47 | private const IN_PROGRESS = 'in_progress'; 48 | private const DONE = 'done'; 49 | } 50 | ``` 51 | 52 | *The doctype is only required for autocompletion in IDEs, not for the enum to function.* 53 | 54 | Make sure you define your members as either `private` or `protected` to avoid confusion leading to direct access to a member's value instead of an instance, causing exceptions when your code expects an instance and not the value (such as the example below). 55 | 56 | ```php 57 | TaskStatus::TODO !== TaskStatus::TODO() 58 | ``` 59 | 60 | ```php 61 | class Task 62 | { 63 | /** @var TaskStatus */ 64 | private $status; 65 | 66 | /** 67 | * Set status 68 | * 69 | * @param TaskStatus $status 70 | */ 71 | public function setStatus(TaskStatus $status) 72 | { 73 | $this->status = $status; 74 | } 75 | 76 | // .. 77 | } 78 | ``` 79 | 80 | Or if you need to be more flexible, the `get` method will intelligently return the member by name or if an object is given, check that it's the correct type. 81 | 82 | ```php 83 | class Task 84 | { 85 | /** @var TaskStatus */ 86 | private $status; 87 | 88 | /** 89 | * Set status 90 | * 91 | * @param TaskStatus|string $status 92 | * 93 | * @throws \UnexpectedValueException On unknown status. 94 | */ 95 | public function setStatus($status) 96 | { 97 | $this->status = TaskStatus::get($status); 98 | } 99 | 100 | // .. 101 | } 102 | ``` 103 | 104 | To read more about ways to define your members and how to name them, please see [docs/definition.md](docs/definition.md). 105 | 106 | ### Comparison 107 | 108 | With enums you're always dealing with a single instance per member therefore you can compare them directly. 109 | 110 | ```php 111 | // Compare by instance 112 | TaskStatus::TODO() === TaskStatus::TODO(); // true 113 | TaskStatus::TODO() === TaskStatus::get('todo'); // true 114 | TaskStatus::get('TODO') === TaskStatus::get('todo'); // true 115 | TaskStatus::TODO() === TaskStatus::get(TaskStatus::TODO()) // true 116 | 117 | TaskStatus::TODO() === TaskStatus::DONE(); // false 118 | TaskStatus::TODO() === TaskStatus::get('done'); // false 119 | 120 | // Compare by value 121 | (string) TaskStatus::TODO() === 'todo'; // true 122 | TaskStatus::TODO()->getValue() === 'todo'; // true 123 | ``` 124 | 125 | ### Inheritance 126 | 127 | You should always define your enums as `final` classes to prevent other classes from inheriting from it. If you want other classes inheriting it, consider making it `abstract` and write `final` concrete classes that inherit from it. 128 | 129 | Without making it final, your code could accept inherited enums when all you expected was the base class. This could lead to nasty bugs. 130 | 131 | For example consider these enums: 132 | 133 | ```php 134 | use Cloudstek\Enum\Enum; 135 | 136 | class FooEnum extends Enum 137 | { 138 | private const FOO = 'foo'; 139 | } 140 | 141 | class BarEnum extends FooEnum 142 | { 143 | private const BAR = 'bar'; 144 | } 145 | ``` 146 | 147 | Without making `FooEnum` final, your code could unintentionally accept `BarEnum` as well even though it is expecting `FooEnum`. 148 | 149 | ```php 150 | class Foo 151 | { 152 | public function doSomething(FooEnum $foo) 153 | { 154 | // Do something... 155 | } 156 | } 157 | 158 | $foo = new Foo(); 159 | $foo->doSomething(FooEnum::FOO()); // Allowed and OK, we were expecting FooEnum 160 | $foo->doSomething(BarEnum::BAR()); // Allowed but not OK, we got BarEnum! 161 | ``` 162 | 163 | To prevent this and to make sure we always get `FooEnum` we should mark it final. Which doesn't mean it can't inherit anything else. 164 | 165 | ```php 166 | use Cloudstek\Enum\Enum; 167 | 168 | abstract class BaseEnum extends Enum 169 | { 170 | private const HELLO = 'world'; 171 | } 172 | 173 | final class FooEnum extends BaseEnum 174 | { 175 | private const FOO = 'foo'; 176 | } 177 | 178 | final class BarEnum extends BaseEnum 179 | { 180 | private const BAR = 'bar'; 181 | } 182 | ``` 183 | 184 | Now we're sure we only get instances of `FooEnum`. 185 | 186 | ```php 187 | class Foo 188 | { 189 | public function doSomething(FooEnum $foo) 190 | { 191 | // Do something... 192 | } 193 | } 194 | 195 | $foo = new Foo(); 196 | $foo->doSomething(FooEnum::FOO()); // Allowed and OK, we were expecting FooEnum 197 | $foo->doSomething(BarEnum::BAR()); // Fatal error 198 | ``` 199 | 200 | But in case we really don't care, as long as its base type is `BaseEnum`, we have to change the parameter type to `BaseEnum` explicitly like so: 201 | 202 | ```php 203 | class Foo 204 | { 205 | public function doSomething(BaseEnum $foo) 206 | { 207 | // Do something... 208 | } 209 | } 210 | 211 | $foo = new Foo(); 212 | $foo->doSomething(FooEnum::FOO()); // OK 213 | $foo->doSomething(BarEnum::BAR()); // OK 214 | ``` 215 | 216 | ### Storing data 217 | 218 | If you store data containing an enum and you want to convert it back into an enum later, make sure to store the member name using `getName()` instead of storing its value. If you only care about the value, just store the value using `getValue()` or by casting it to a string (if possible). 219 | 220 | ```php 221 | // Update task 222 | $status = TaskStatus::TODO(); 223 | 224 | $db->update($task, [ 225 | 'status' => $status->getName() // 'status' => 'todo' 226 | ]); 227 | ``` 228 | 229 | ```php 230 | // Fetch task 231 | $taskRow = $db->tasks->fetchOne(13); // [..., 'status' => 'todo', ...] 232 | 233 | $task = new Task(); 234 | // .. 235 | $task->setStatus(TaskStatus::get($taskRow['status'])); 236 | 237 | // or if you call TaskStatus::get() in Task::setStatus() 238 | $task->setStatus($taskRow['status']); 239 | ``` 240 | 241 | ## Support 242 | 243 | You can support this project by contributing to open issues, submitting pull requests, giving this project a :star: or telling your friends about it. 244 | 245 | If you have any ideas or issues, please open up an issue! 246 | 247 | ## Related projects 248 | 249 | * [spatie/enum](https://github.com/spatie/enum) 250 | * [myclabs/php-enum](https://github.com/myclabs/php-enum) 251 | * [eloquent/enumeration](https://github.com/eloquent/enumeration) 252 | 253 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cloudstek/php-enum", 3 | "description": "Enumeration support for PHP", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Maarten de Boer", 9 | "email": "maarten@cloudstek.nl" 10 | } 11 | ], 12 | "autoload": { 13 | "psr-4": { 14 | "Cloudstek\\Enum\\": "src/" 15 | } 16 | }, 17 | "autoload-dev": { 18 | "psr-4": { 19 | "Cloudstek\\Enum\\Tests\\": "tests/" 20 | } 21 | }, 22 | "require": { 23 | "php": ">=7.1" 24 | }, 25 | "require-dev": { 26 | "symfony/phpunit-bridge": "^5.0", 27 | "vimeo/psalm": "^3.8", 28 | "squizlabs/php_codesniffer": "^3.5", 29 | "php-coveralls/php-coveralls": "^2.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "4223263b5686c84f846107584d013038", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "amphp/amp", 12 | "version": "v2.4.1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/amphp/amp.git", 16 | "reference": "2ac3b550c4997f2ec304faa63c8b2885079a2dc4" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/amphp/amp/zipball/2ac3b550c4997f2ec304faa63c8b2885079a2dc4", 21 | "reference": "2ac3b550c4997f2ec304faa63c8b2885079a2dc4", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": ">=7" 26 | }, 27 | "require-dev": { 28 | "amphp/php-cs-fixer-config": "dev-master", 29 | "amphp/phpunit-util": "^1", 30 | "ext-json": "*", 31 | "phpstan/phpstan": "^0.8.5", 32 | "phpunit/phpunit": "^6.0.9 | ^7", 33 | "react/promise": "^2" 34 | }, 35 | "type": "library", 36 | "extra": { 37 | "branch-alias": { 38 | "dev-master": "2.0.x-dev" 39 | } 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Amp\\": "lib" 44 | }, 45 | "files": [ 46 | "lib/functions.php", 47 | "lib/Internal/functions.php" 48 | ] 49 | }, 50 | "notification-url": "https://packagist.org/downloads/", 51 | "license": [ 52 | "MIT" 53 | ], 54 | "authors": [ 55 | { 56 | "name": "Daniel Lowrey", 57 | "email": "rdlowrey@php.net" 58 | }, 59 | { 60 | "name": "Aaron Piotrowski", 61 | "email": "aaron@trowski.com" 62 | }, 63 | { 64 | "name": "Bob Weinand", 65 | "email": "bobwei9@hotmail.com" 66 | }, 67 | { 68 | "name": "Niklas Keller", 69 | "email": "me@kelunik.com" 70 | } 71 | ], 72 | "description": "A non-blocking concurrency framework for PHP applications.", 73 | "homepage": "http://amphp.org/amp", 74 | "keywords": [ 75 | "async", 76 | "asynchronous", 77 | "awaitable", 78 | "concurrency", 79 | "event", 80 | "event-loop", 81 | "future", 82 | "non-blocking", 83 | "promise" 84 | ], 85 | "time": "2020-02-10T18:10:57+00:00" 86 | }, 87 | { 88 | "name": "amphp/byte-stream", 89 | "version": "v1.7.2", 90 | "source": { 91 | "type": "git", 92 | "url": "https://github.com/amphp/byte-stream.git", 93 | "reference": "1e52f1752b2e20e2a7e464476ef887a2388e3832" 94 | }, 95 | "dist": { 96 | "type": "zip", 97 | "url": "https://api.github.com/repos/amphp/byte-stream/zipball/1e52f1752b2e20e2a7e464476ef887a2388e3832", 98 | "reference": "1e52f1752b2e20e2a7e464476ef887a2388e3832", 99 | "shasum": "" 100 | }, 101 | "require": { 102 | "amphp/amp": "^2" 103 | }, 104 | "require-dev": { 105 | "amphp/php-cs-fixer-config": "dev-master", 106 | "amphp/phpunit-util": "^1", 107 | "friendsofphp/php-cs-fixer": "^2.3", 108 | "infection/infection": "^0.9.3", 109 | "phpunit/phpunit": "^6" 110 | }, 111 | "type": "library", 112 | "autoload": { 113 | "psr-4": { 114 | "Amp\\ByteStream\\": "lib" 115 | }, 116 | "files": [ 117 | "lib/functions.php" 118 | ] 119 | }, 120 | "notification-url": "https://packagist.org/downloads/", 121 | "license": [ 122 | "MIT" 123 | ], 124 | "authors": [ 125 | { 126 | "name": "Aaron Piotrowski", 127 | "email": "aaron@trowski.com" 128 | }, 129 | { 130 | "name": "Niklas Keller", 131 | "email": "me@kelunik.com" 132 | } 133 | ], 134 | "description": "A stream abstraction to make working with non-blocking I/O simple.", 135 | "homepage": "http://amphp.org/byte-stream", 136 | "keywords": [ 137 | "amp", 138 | "amphp", 139 | "async", 140 | "io", 141 | "non-blocking", 142 | "stream" 143 | ], 144 | "time": "2020-01-29T18:22:23+00:00" 145 | }, 146 | { 147 | "name": "composer/semver", 148 | "version": "1.5.1", 149 | "source": { 150 | "type": "git", 151 | "url": "https://github.com/composer/semver.git", 152 | "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" 153 | }, 154 | "dist": { 155 | "type": "zip", 156 | "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", 157 | "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", 158 | "shasum": "" 159 | }, 160 | "require": { 161 | "php": "^5.3.2 || ^7.0" 162 | }, 163 | "require-dev": { 164 | "phpunit/phpunit": "^4.5 || ^5.0.5" 165 | }, 166 | "type": "library", 167 | "extra": { 168 | "branch-alias": { 169 | "dev-master": "1.x-dev" 170 | } 171 | }, 172 | "autoload": { 173 | "psr-4": { 174 | "Composer\\Semver\\": "src" 175 | } 176 | }, 177 | "notification-url": "https://packagist.org/downloads/", 178 | "license": [ 179 | "MIT" 180 | ], 181 | "authors": [ 182 | { 183 | "name": "Nils Adermann", 184 | "email": "naderman@naderman.de", 185 | "homepage": "http://www.naderman.de" 186 | }, 187 | { 188 | "name": "Jordi Boggiano", 189 | "email": "j.boggiano@seld.be", 190 | "homepage": "http://seld.be" 191 | }, 192 | { 193 | "name": "Rob Bast", 194 | "email": "rob.bast@gmail.com", 195 | "homepage": "http://robbast.nl" 196 | } 197 | ], 198 | "description": "Semver library that offers utilities, version constraint parsing and validation.", 199 | "keywords": [ 200 | "semantic", 201 | "semver", 202 | "validation", 203 | "versioning" 204 | ], 205 | "time": "2020-01-13T12:06:48+00:00" 206 | }, 207 | { 208 | "name": "composer/xdebug-handler", 209 | "version": "1.4.0", 210 | "source": { 211 | "type": "git", 212 | "url": "https://github.com/composer/xdebug-handler.git", 213 | "reference": "cbe23383749496fe0f373345208b79568e4bc248" 214 | }, 215 | "dist": { 216 | "type": "zip", 217 | "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", 218 | "reference": "cbe23383749496fe0f373345208b79568e4bc248", 219 | "shasum": "" 220 | }, 221 | "require": { 222 | "php": "^5.3.2 || ^7.0 || ^8.0", 223 | "psr/log": "^1.0" 224 | }, 225 | "require-dev": { 226 | "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" 227 | }, 228 | "type": "library", 229 | "autoload": { 230 | "psr-4": { 231 | "Composer\\XdebugHandler\\": "src" 232 | } 233 | }, 234 | "notification-url": "https://packagist.org/downloads/", 235 | "license": [ 236 | "MIT" 237 | ], 238 | "authors": [ 239 | { 240 | "name": "John Stevenson", 241 | "email": "john-stevenson@blueyonder.co.uk" 242 | } 243 | ], 244 | "description": "Restarts a process without Xdebug.", 245 | "keywords": [ 246 | "Xdebug", 247 | "performance" 248 | ], 249 | "time": "2019-11-06T16:40:04+00:00" 250 | }, 251 | { 252 | "name": "felixfbecker/advanced-json-rpc", 253 | "version": "v3.1.0", 254 | "source": { 255 | "type": "git", 256 | "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", 257 | "reference": "a407a6cb0325cd489c6dff57afcba6baeccc0483" 258 | }, 259 | "dist": { 260 | "type": "zip", 261 | "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/a407a6cb0325cd489c6dff57afcba6baeccc0483", 262 | "reference": "a407a6cb0325cd489c6dff57afcba6baeccc0483", 263 | "shasum": "" 264 | }, 265 | "require": { 266 | "netresearch/jsonmapper": "^1.0", 267 | "php": ">=7.0", 268 | "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" 269 | }, 270 | "require-dev": { 271 | "phpunit/phpunit": "^6.0.0" 272 | }, 273 | "type": "library", 274 | "autoload": { 275 | "psr-4": { 276 | "AdvancedJsonRpc\\": "lib/" 277 | } 278 | }, 279 | "notification-url": "https://packagist.org/downloads/", 280 | "license": [ 281 | "ISC" 282 | ], 283 | "authors": [ 284 | { 285 | "name": "Felix Becker", 286 | "email": "felix.b@outlook.com" 287 | } 288 | ], 289 | "description": "A more advanced JSONRPC implementation", 290 | "time": "2020-02-11T20:48:40+00:00" 291 | }, 292 | { 293 | "name": "felixfbecker/language-server-protocol", 294 | "version": "v1.4.0", 295 | "source": { 296 | "type": "git", 297 | "url": "https://github.com/felixfbecker/php-language-server-protocol.git", 298 | "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" 299 | }, 300 | "dist": { 301 | "type": "zip", 302 | "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", 303 | "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", 304 | "shasum": "" 305 | }, 306 | "require": { 307 | "php": "^7.0" 308 | }, 309 | "require-dev": { 310 | "phpstan/phpstan": "*", 311 | "phpunit/phpunit": "^6.3", 312 | "squizlabs/php_codesniffer": "^3.1" 313 | }, 314 | "type": "library", 315 | "autoload": { 316 | "psr-4": { 317 | "LanguageServerProtocol\\": "src/" 318 | } 319 | }, 320 | "notification-url": "https://packagist.org/downloads/", 321 | "license": [ 322 | "ISC" 323 | ], 324 | "authors": [ 325 | { 326 | "name": "Felix Becker", 327 | "email": "felix.b@outlook.com" 328 | } 329 | ], 330 | "description": "PHP classes for the Language Server Protocol", 331 | "keywords": [ 332 | "language", 333 | "microsoft", 334 | "php", 335 | "server" 336 | ], 337 | "time": "2019-06-23T21:03:50+00:00" 338 | }, 339 | { 340 | "name": "guzzlehttp/guzzle", 341 | "version": "6.5.2", 342 | "source": { 343 | "type": "git", 344 | "url": "https://github.com/guzzle/guzzle.git", 345 | "reference": "43ece0e75098b7ecd8d13918293029e555a50f82" 346 | }, 347 | "dist": { 348 | "type": "zip", 349 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82", 350 | "reference": "43ece0e75098b7ecd8d13918293029e555a50f82", 351 | "shasum": "" 352 | }, 353 | "require": { 354 | "ext-json": "*", 355 | "guzzlehttp/promises": "^1.0", 356 | "guzzlehttp/psr7": "^1.6.1", 357 | "php": ">=5.5" 358 | }, 359 | "require-dev": { 360 | "ext-curl": "*", 361 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", 362 | "psr/log": "^1.1" 363 | }, 364 | "suggest": { 365 | "ext-intl": "Required for Internationalized Domain Name (IDN) support", 366 | "psr/log": "Required for using the Log middleware" 367 | }, 368 | "type": "library", 369 | "extra": { 370 | "branch-alias": { 371 | "dev-master": "6.5-dev" 372 | } 373 | }, 374 | "autoload": { 375 | "psr-4": { 376 | "GuzzleHttp\\": "src/" 377 | }, 378 | "files": [ 379 | "src/functions_include.php" 380 | ] 381 | }, 382 | "notification-url": "https://packagist.org/downloads/", 383 | "license": [ 384 | "MIT" 385 | ], 386 | "authors": [ 387 | { 388 | "name": "Michael Dowling", 389 | "email": "mtdowling@gmail.com", 390 | "homepage": "https://github.com/mtdowling" 391 | } 392 | ], 393 | "description": "Guzzle is a PHP HTTP client library", 394 | "homepage": "http://guzzlephp.org/", 395 | "keywords": [ 396 | "client", 397 | "curl", 398 | "framework", 399 | "http", 400 | "http client", 401 | "rest", 402 | "web service" 403 | ], 404 | "time": "2019-12-23T11:57:10+00:00" 405 | }, 406 | { 407 | "name": "guzzlehttp/promises", 408 | "version": "v1.3.1", 409 | "source": { 410 | "type": "git", 411 | "url": "https://github.com/guzzle/promises.git", 412 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" 413 | }, 414 | "dist": { 415 | "type": "zip", 416 | "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", 417 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", 418 | "shasum": "" 419 | }, 420 | "require": { 421 | "php": ">=5.5.0" 422 | }, 423 | "require-dev": { 424 | "phpunit/phpunit": "^4.0" 425 | }, 426 | "type": "library", 427 | "extra": { 428 | "branch-alias": { 429 | "dev-master": "1.4-dev" 430 | } 431 | }, 432 | "autoload": { 433 | "psr-4": { 434 | "GuzzleHttp\\Promise\\": "src/" 435 | }, 436 | "files": [ 437 | "src/functions_include.php" 438 | ] 439 | }, 440 | "notification-url": "https://packagist.org/downloads/", 441 | "license": [ 442 | "MIT" 443 | ], 444 | "authors": [ 445 | { 446 | "name": "Michael Dowling", 447 | "email": "mtdowling@gmail.com", 448 | "homepage": "https://github.com/mtdowling" 449 | } 450 | ], 451 | "description": "Guzzle promises library", 452 | "keywords": [ 453 | "promise" 454 | ], 455 | "time": "2016-12-20T10:07:11+00:00" 456 | }, 457 | { 458 | "name": "guzzlehttp/psr7", 459 | "version": "1.6.1", 460 | "source": { 461 | "type": "git", 462 | "url": "https://github.com/guzzle/psr7.git", 463 | "reference": "239400de7a173fe9901b9ac7c06497751f00727a" 464 | }, 465 | "dist": { 466 | "type": "zip", 467 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", 468 | "reference": "239400de7a173fe9901b9ac7c06497751f00727a", 469 | "shasum": "" 470 | }, 471 | "require": { 472 | "php": ">=5.4.0", 473 | "psr/http-message": "~1.0", 474 | "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" 475 | }, 476 | "provide": { 477 | "psr/http-message-implementation": "1.0" 478 | }, 479 | "require-dev": { 480 | "ext-zlib": "*", 481 | "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" 482 | }, 483 | "suggest": { 484 | "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" 485 | }, 486 | "type": "library", 487 | "extra": { 488 | "branch-alias": { 489 | "dev-master": "1.6-dev" 490 | } 491 | }, 492 | "autoload": { 493 | "psr-4": { 494 | "GuzzleHttp\\Psr7\\": "src/" 495 | }, 496 | "files": [ 497 | "src/functions_include.php" 498 | ] 499 | }, 500 | "notification-url": "https://packagist.org/downloads/", 501 | "license": [ 502 | "MIT" 503 | ], 504 | "authors": [ 505 | { 506 | "name": "Michael Dowling", 507 | "email": "mtdowling@gmail.com", 508 | "homepage": "https://github.com/mtdowling" 509 | }, 510 | { 511 | "name": "Tobias Schultze", 512 | "homepage": "https://github.com/Tobion" 513 | } 514 | ], 515 | "description": "PSR-7 message implementation that also provides common utility methods", 516 | "keywords": [ 517 | "http", 518 | "message", 519 | "psr-7", 520 | "request", 521 | "response", 522 | "stream", 523 | "uri", 524 | "url" 525 | ], 526 | "time": "2019-07-01T23:21:34+00:00" 527 | }, 528 | { 529 | "name": "netresearch/jsonmapper", 530 | "version": "v1.6.0", 531 | "source": { 532 | "type": "git", 533 | "url": "https://github.com/cweiske/jsonmapper.git", 534 | "reference": "0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06" 535 | }, 536 | "dist": { 537 | "type": "zip", 538 | "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06", 539 | "reference": "0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06", 540 | "shasum": "" 541 | }, 542 | "require": { 543 | "ext-json": "*", 544 | "ext-pcre": "*", 545 | "ext-reflection": "*", 546 | "ext-spl": "*", 547 | "php": ">=5.6" 548 | }, 549 | "require-dev": { 550 | "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4", 551 | "squizlabs/php_codesniffer": "~1.5" 552 | }, 553 | "type": "library", 554 | "autoload": { 555 | "psr-0": { 556 | "JsonMapper": "src/" 557 | } 558 | }, 559 | "notification-url": "https://packagist.org/downloads/", 560 | "license": [ 561 | "OSL-3.0" 562 | ], 563 | "authors": [ 564 | { 565 | "name": "Christian Weiske", 566 | "email": "cweiske@cweiske.de", 567 | "homepage": "http://github.com/cweiske/jsonmapper/", 568 | "role": "Developer" 569 | } 570 | ], 571 | "description": "Map nested JSON structures onto PHP classes", 572 | "time": "2019-08-15T19:41:25+00:00" 573 | }, 574 | { 575 | "name": "nikic/php-parser", 576 | "version": "v4.3.0", 577 | "source": { 578 | "type": "git", 579 | "url": "https://github.com/nikic/PHP-Parser.git", 580 | "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" 581 | }, 582 | "dist": { 583 | "type": "zip", 584 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", 585 | "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", 586 | "shasum": "" 587 | }, 588 | "require": { 589 | "ext-tokenizer": "*", 590 | "php": ">=7.0" 591 | }, 592 | "require-dev": { 593 | "ircmaxell/php-yacc": "0.0.5", 594 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" 595 | }, 596 | "bin": [ 597 | "bin/php-parse" 598 | ], 599 | "type": "library", 600 | "extra": { 601 | "branch-alias": { 602 | "dev-master": "4.3-dev" 603 | } 604 | }, 605 | "autoload": { 606 | "psr-4": { 607 | "PhpParser\\": "lib/PhpParser" 608 | } 609 | }, 610 | "notification-url": "https://packagist.org/downloads/", 611 | "license": [ 612 | "BSD-3-Clause" 613 | ], 614 | "authors": [ 615 | { 616 | "name": "Nikita Popov" 617 | } 618 | ], 619 | "description": "A PHP parser written in PHP", 620 | "keywords": [ 621 | "parser", 622 | "php" 623 | ], 624 | "time": "2019-11-08T13:50:10+00:00" 625 | }, 626 | { 627 | "name": "ocramius/package-versions", 628 | "version": "1.4.2", 629 | "source": { 630 | "type": "git", 631 | "url": "https://github.com/Ocramius/PackageVersions.git", 632 | "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d" 633 | }, 634 | "dist": { 635 | "type": "zip", 636 | "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", 637 | "reference": "44af6f3a2e2e04f2af46bcb302ad9600cba41c7d", 638 | "shasum": "" 639 | }, 640 | "require": { 641 | "composer-plugin-api": "^1.0.0", 642 | "php": "^7.1.0" 643 | }, 644 | "require-dev": { 645 | "composer/composer": "^1.6.3", 646 | "doctrine/coding-standard": "^5.0.1", 647 | "ext-zip": "*", 648 | "infection/infection": "^0.7.1", 649 | "phpunit/phpunit": "^7.5.17" 650 | }, 651 | "type": "composer-plugin", 652 | "extra": { 653 | "class": "PackageVersions\\Installer", 654 | "branch-alias": { 655 | "dev-master": "2.0.x-dev" 656 | } 657 | }, 658 | "autoload": { 659 | "psr-4": { 660 | "PackageVersions\\": "src/PackageVersions" 661 | } 662 | }, 663 | "notification-url": "https://packagist.org/downloads/", 664 | "license": [ 665 | "MIT" 666 | ], 667 | "authors": [ 668 | { 669 | "name": "Marco Pivetta", 670 | "email": "ocramius@gmail.com" 671 | } 672 | ], 673 | "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", 674 | "time": "2019-11-15T16:17:10+00:00" 675 | }, 676 | { 677 | "name": "openlss/lib-array2xml", 678 | "version": "1.0.0", 679 | "source": { 680 | "type": "git", 681 | "url": "https://github.com/nullivex/lib-array2xml.git", 682 | "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" 683 | }, 684 | "dist": { 685 | "type": "zip", 686 | "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", 687 | "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", 688 | "shasum": "" 689 | }, 690 | "require": { 691 | "php": ">=5.3.2" 692 | }, 693 | "type": "library", 694 | "autoload": { 695 | "psr-0": { 696 | "LSS": "" 697 | } 698 | }, 699 | "notification-url": "https://packagist.org/downloads/", 700 | "license": [ 701 | "Apache-2.0" 702 | ], 703 | "authors": [ 704 | { 705 | "name": "Bryan Tong", 706 | "email": "bryan@nullivex.com", 707 | "homepage": "https://www.nullivex.com" 708 | }, 709 | { 710 | "name": "Tony Butler", 711 | "email": "spudz76@gmail.com", 712 | "homepage": "https://www.nullivex.com" 713 | } 714 | ], 715 | "description": "Array2XML conversion library credit to lalit.org", 716 | "homepage": "https://www.nullivex.com", 717 | "keywords": [ 718 | "array", 719 | "array conversion", 720 | "xml", 721 | "xml conversion" 722 | ], 723 | "time": "2019-03-29T20:06:56+00:00" 724 | }, 725 | { 726 | "name": "php-coveralls/php-coveralls", 727 | "version": "v2.2.0", 728 | "source": { 729 | "type": "git", 730 | "url": "https://github.com/php-coveralls/php-coveralls.git", 731 | "reference": "3e6420fa666ef7bae5e750ddeac903153e193bae" 732 | }, 733 | "dist": { 734 | "type": "zip", 735 | "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/3e6420fa666ef7bae5e750ddeac903153e193bae", 736 | "reference": "3e6420fa666ef7bae5e750ddeac903153e193bae", 737 | "shasum": "" 738 | }, 739 | "require": { 740 | "ext-json": "*", 741 | "ext-simplexml": "*", 742 | "guzzlehttp/guzzle": "^6.0", 743 | "php": "^5.5 || ^7.0", 744 | "psr/log": "^1.0", 745 | "symfony/config": "^2.1 || ^3.0 || ^4.0 || ^5.0", 746 | "symfony/console": "^2.1 || ^3.0 || ^4.0 || ^5.0", 747 | "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0 || ^5.0", 748 | "symfony/yaml": "^2.0.5 || ^3.0 || ^4.0 || ^5.0" 749 | }, 750 | "require-dev": { 751 | "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0" 752 | }, 753 | "suggest": { 754 | "symfony/http-kernel": "Allows Symfony integration" 755 | }, 756 | "bin": [ 757 | "bin/php-coveralls" 758 | ], 759 | "type": "library", 760 | "extra": { 761 | "branch-alias": { 762 | "dev-master": "2.2-dev" 763 | } 764 | }, 765 | "autoload": { 766 | "psr-4": { 767 | "PhpCoveralls\\": "src/" 768 | } 769 | }, 770 | "notification-url": "https://packagist.org/downloads/", 771 | "license": [ 772 | "MIT" 773 | ], 774 | "authors": [ 775 | { 776 | "name": "Kitamura Satoshi", 777 | "email": "with.no.parachute@gmail.com", 778 | "homepage": "https://www.facebook.com/satooshi.jp", 779 | "role": "Original creator" 780 | }, 781 | { 782 | "name": "Takashi Matsuo", 783 | "email": "tmatsuo@google.com" 784 | }, 785 | { 786 | "name": "Google Inc" 787 | }, 788 | { 789 | "name": "Dariusz Ruminski", 790 | "email": "dariusz.ruminski@gmail.com", 791 | "homepage": "https://github.com/keradus" 792 | }, 793 | { 794 | "name": "Contributors", 795 | "homepage": "https://github.com/php-coveralls/php-coveralls/graphs/contributors" 796 | } 797 | ], 798 | "description": "PHP client library for Coveralls API", 799 | "homepage": "https://github.com/php-coveralls/php-coveralls", 800 | "keywords": [ 801 | "ci", 802 | "coverage", 803 | "github", 804 | "test" 805 | ], 806 | "time": "2019-11-20T16:29:20+00:00" 807 | }, 808 | { 809 | "name": "phpdocumentor/reflection-common", 810 | "version": "2.0.0", 811 | "source": { 812 | "type": "git", 813 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 814 | "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" 815 | }, 816 | "dist": { 817 | "type": "zip", 818 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", 819 | "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", 820 | "shasum": "" 821 | }, 822 | "require": { 823 | "php": ">=7.1" 824 | }, 825 | "require-dev": { 826 | "phpunit/phpunit": "~6" 827 | }, 828 | "type": "library", 829 | "extra": { 830 | "branch-alias": { 831 | "dev-master": "2.x-dev" 832 | } 833 | }, 834 | "autoload": { 835 | "psr-4": { 836 | "phpDocumentor\\Reflection\\": "src/" 837 | } 838 | }, 839 | "notification-url": "https://packagist.org/downloads/", 840 | "license": [ 841 | "MIT" 842 | ], 843 | "authors": [ 844 | { 845 | "name": "Jaap van Otterdijk", 846 | "email": "opensource@ijaap.nl" 847 | } 848 | ], 849 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 850 | "homepage": "http://www.phpdoc.org", 851 | "keywords": [ 852 | "FQSEN", 853 | "phpDocumentor", 854 | "phpdoc", 855 | "reflection", 856 | "static analysis" 857 | ], 858 | "time": "2018-08-07T13:53:10+00:00" 859 | }, 860 | { 861 | "name": "phpdocumentor/reflection-docblock", 862 | "version": "4.3.4", 863 | "source": { 864 | "type": "git", 865 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 866 | "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" 867 | }, 868 | "dist": { 869 | "type": "zip", 870 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", 871 | "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", 872 | "shasum": "" 873 | }, 874 | "require": { 875 | "php": "^7.0", 876 | "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", 877 | "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", 878 | "webmozart/assert": "^1.0" 879 | }, 880 | "require-dev": { 881 | "doctrine/instantiator": "^1.0.5", 882 | "mockery/mockery": "^1.0", 883 | "phpdocumentor/type-resolver": "0.4.*", 884 | "phpunit/phpunit": "^6.4" 885 | }, 886 | "type": "library", 887 | "extra": { 888 | "branch-alias": { 889 | "dev-master": "4.x-dev" 890 | } 891 | }, 892 | "autoload": { 893 | "psr-4": { 894 | "phpDocumentor\\Reflection\\": [ 895 | "src/" 896 | ] 897 | } 898 | }, 899 | "notification-url": "https://packagist.org/downloads/", 900 | "license": [ 901 | "MIT" 902 | ], 903 | "authors": [ 904 | { 905 | "name": "Mike van Riel", 906 | "email": "me@mikevanriel.com" 907 | } 908 | ], 909 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 910 | "time": "2019-12-28T18:55:12+00:00" 911 | }, 912 | { 913 | "name": "phpdocumentor/type-resolver", 914 | "version": "1.0.1", 915 | "source": { 916 | "type": "git", 917 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 918 | "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" 919 | }, 920 | "dist": { 921 | "type": "zip", 922 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", 923 | "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", 924 | "shasum": "" 925 | }, 926 | "require": { 927 | "php": "^7.1", 928 | "phpdocumentor/reflection-common": "^2.0" 929 | }, 930 | "require-dev": { 931 | "ext-tokenizer": "^7.1", 932 | "mockery/mockery": "~1", 933 | "phpunit/phpunit": "^7.0" 934 | }, 935 | "type": "library", 936 | "extra": { 937 | "branch-alias": { 938 | "dev-master": "1.x-dev" 939 | } 940 | }, 941 | "autoload": { 942 | "psr-4": { 943 | "phpDocumentor\\Reflection\\": "src" 944 | } 945 | }, 946 | "notification-url": "https://packagist.org/downloads/", 947 | "license": [ 948 | "MIT" 949 | ], 950 | "authors": [ 951 | { 952 | "name": "Mike van Riel", 953 | "email": "me@mikevanriel.com" 954 | } 955 | ], 956 | "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", 957 | "time": "2019-08-22T18:11:29+00:00" 958 | }, 959 | { 960 | "name": "psr/container", 961 | "version": "1.0.0", 962 | "source": { 963 | "type": "git", 964 | "url": "https://github.com/php-fig/container.git", 965 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 966 | }, 967 | "dist": { 968 | "type": "zip", 969 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 970 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 971 | "shasum": "" 972 | }, 973 | "require": { 974 | "php": ">=5.3.0" 975 | }, 976 | "type": "library", 977 | "extra": { 978 | "branch-alias": { 979 | "dev-master": "1.0.x-dev" 980 | } 981 | }, 982 | "autoload": { 983 | "psr-4": { 984 | "Psr\\Container\\": "src/" 985 | } 986 | }, 987 | "notification-url": "https://packagist.org/downloads/", 988 | "license": [ 989 | "MIT" 990 | ], 991 | "authors": [ 992 | { 993 | "name": "PHP-FIG", 994 | "homepage": "http://www.php-fig.org/" 995 | } 996 | ], 997 | "description": "Common Container Interface (PHP FIG PSR-11)", 998 | "homepage": "https://github.com/php-fig/container", 999 | "keywords": [ 1000 | "PSR-11", 1001 | "container", 1002 | "container-interface", 1003 | "container-interop", 1004 | "psr" 1005 | ], 1006 | "time": "2017-02-14T16:28:37+00:00" 1007 | }, 1008 | { 1009 | "name": "psr/http-message", 1010 | "version": "1.0.1", 1011 | "source": { 1012 | "type": "git", 1013 | "url": "https://github.com/php-fig/http-message.git", 1014 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 1015 | }, 1016 | "dist": { 1017 | "type": "zip", 1018 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 1019 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 1020 | "shasum": "" 1021 | }, 1022 | "require": { 1023 | "php": ">=5.3.0" 1024 | }, 1025 | "type": "library", 1026 | "extra": { 1027 | "branch-alias": { 1028 | "dev-master": "1.0.x-dev" 1029 | } 1030 | }, 1031 | "autoload": { 1032 | "psr-4": { 1033 | "Psr\\Http\\Message\\": "src/" 1034 | } 1035 | }, 1036 | "notification-url": "https://packagist.org/downloads/", 1037 | "license": [ 1038 | "MIT" 1039 | ], 1040 | "authors": [ 1041 | { 1042 | "name": "PHP-FIG", 1043 | "homepage": "http://www.php-fig.org/" 1044 | } 1045 | ], 1046 | "description": "Common interface for HTTP messages", 1047 | "homepage": "https://github.com/php-fig/http-message", 1048 | "keywords": [ 1049 | "http", 1050 | "http-message", 1051 | "psr", 1052 | "psr-7", 1053 | "request", 1054 | "response" 1055 | ], 1056 | "time": "2016-08-06T14:39:51+00:00" 1057 | }, 1058 | { 1059 | "name": "psr/log", 1060 | "version": "1.1.2", 1061 | "source": { 1062 | "type": "git", 1063 | "url": "https://github.com/php-fig/log.git", 1064 | "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" 1065 | }, 1066 | "dist": { 1067 | "type": "zip", 1068 | "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", 1069 | "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", 1070 | "shasum": "" 1071 | }, 1072 | "require": { 1073 | "php": ">=5.3.0" 1074 | }, 1075 | "type": "library", 1076 | "extra": { 1077 | "branch-alias": { 1078 | "dev-master": "1.1.x-dev" 1079 | } 1080 | }, 1081 | "autoload": { 1082 | "psr-4": { 1083 | "Psr\\Log\\": "Psr/Log/" 1084 | } 1085 | }, 1086 | "notification-url": "https://packagist.org/downloads/", 1087 | "license": [ 1088 | "MIT" 1089 | ], 1090 | "authors": [ 1091 | { 1092 | "name": "PHP-FIG", 1093 | "homepage": "http://www.php-fig.org/" 1094 | } 1095 | ], 1096 | "description": "Common interface for logging libraries", 1097 | "homepage": "https://github.com/php-fig/log", 1098 | "keywords": [ 1099 | "log", 1100 | "psr", 1101 | "psr-3" 1102 | ], 1103 | "time": "2019-11-01T11:05:21+00:00" 1104 | }, 1105 | { 1106 | "name": "ralouphie/getallheaders", 1107 | "version": "3.0.3", 1108 | "source": { 1109 | "type": "git", 1110 | "url": "https://github.com/ralouphie/getallheaders.git", 1111 | "reference": "120b605dfeb996808c31b6477290a714d356e822" 1112 | }, 1113 | "dist": { 1114 | "type": "zip", 1115 | "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", 1116 | "reference": "120b605dfeb996808c31b6477290a714d356e822", 1117 | "shasum": "" 1118 | }, 1119 | "require": { 1120 | "php": ">=5.6" 1121 | }, 1122 | "require-dev": { 1123 | "php-coveralls/php-coveralls": "^2.1", 1124 | "phpunit/phpunit": "^5 || ^6.5" 1125 | }, 1126 | "type": "library", 1127 | "autoload": { 1128 | "files": [ 1129 | "src/getallheaders.php" 1130 | ] 1131 | }, 1132 | "notification-url": "https://packagist.org/downloads/", 1133 | "license": [ 1134 | "MIT" 1135 | ], 1136 | "authors": [ 1137 | { 1138 | "name": "Ralph Khattar", 1139 | "email": "ralph.khattar@gmail.com" 1140 | } 1141 | ], 1142 | "description": "A polyfill for getallheaders.", 1143 | "time": "2019-03-08T08:55:37+00:00" 1144 | }, 1145 | { 1146 | "name": "sebastian/diff", 1147 | "version": "3.0.2", 1148 | "source": { 1149 | "type": "git", 1150 | "url": "https://github.com/sebastianbergmann/diff.git", 1151 | "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" 1152 | }, 1153 | "dist": { 1154 | "type": "zip", 1155 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", 1156 | "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", 1157 | "shasum": "" 1158 | }, 1159 | "require": { 1160 | "php": "^7.1" 1161 | }, 1162 | "require-dev": { 1163 | "phpunit/phpunit": "^7.5 || ^8.0", 1164 | "symfony/process": "^2 || ^3.3 || ^4" 1165 | }, 1166 | "type": "library", 1167 | "extra": { 1168 | "branch-alias": { 1169 | "dev-master": "3.0-dev" 1170 | } 1171 | }, 1172 | "autoload": { 1173 | "classmap": [ 1174 | "src/" 1175 | ] 1176 | }, 1177 | "notification-url": "https://packagist.org/downloads/", 1178 | "license": [ 1179 | "BSD-3-Clause" 1180 | ], 1181 | "authors": [ 1182 | { 1183 | "name": "Kore Nordmann", 1184 | "email": "mail@kore-nordmann.de" 1185 | }, 1186 | { 1187 | "name": "Sebastian Bergmann", 1188 | "email": "sebastian@phpunit.de" 1189 | } 1190 | ], 1191 | "description": "Diff implementation", 1192 | "homepage": "https://github.com/sebastianbergmann/diff", 1193 | "keywords": [ 1194 | "diff", 1195 | "udiff", 1196 | "unidiff", 1197 | "unified diff" 1198 | ], 1199 | "time": "2019-02-04T06:01:07+00:00" 1200 | }, 1201 | { 1202 | "name": "squizlabs/php_codesniffer", 1203 | "version": "3.5.4", 1204 | "source": { 1205 | "type": "git", 1206 | "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", 1207 | "reference": "dceec07328401de6211037abbb18bda423677e26" 1208 | }, 1209 | "dist": { 1210 | "type": "zip", 1211 | "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26", 1212 | "reference": "dceec07328401de6211037abbb18bda423677e26", 1213 | "shasum": "" 1214 | }, 1215 | "require": { 1216 | "ext-simplexml": "*", 1217 | "ext-tokenizer": "*", 1218 | "ext-xmlwriter": "*", 1219 | "php": ">=5.4.0" 1220 | }, 1221 | "require-dev": { 1222 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" 1223 | }, 1224 | "bin": [ 1225 | "bin/phpcs", 1226 | "bin/phpcbf" 1227 | ], 1228 | "type": "library", 1229 | "extra": { 1230 | "branch-alias": { 1231 | "dev-master": "3.x-dev" 1232 | } 1233 | }, 1234 | "notification-url": "https://packagist.org/downloads/", 1235 | "license": [ 1236 | "BSD-3-Clause" 1237 | ], 1238 | "authors": [ 1239 | { 1240 | "name": "Greg Sherwood", 1241 | "role": "lead" 1242 | } 1243 | ], 1244 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 1245 | "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", 1246 | "keywords": [ 1247 | "phpcs", 1248 | "standards" 1249 | ], 1250 | "time": "2020-01-30T22:20:29+00:00" 1251 | }, 1252 | { 1253 | "name": "symfony/config", 1254 | "version": "v4.4.5", 1255 | "source": { 1256 | "type": "git", 1257 | "url": "https://github.com/symfony/config.git", 1258 | "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9" 1259 | }, 1260 | "dist": { 1261 | "type": "zip", 1262 | "url": "https://api.github.com/repos/symfony/config/zipball/cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", 1263 | "reference": "cbfef5ae91ccd3b06621c18d58cd355c68c87ae9", 1264 | "shasum": "" 1265 | }, 1266 | "require": { 1267 | "php": "^7.1.3", 1268 | "symfony/filesystem": "^3.4|^4.0|^5.0", 1269 | "symfony/polyfill-ctype": "~1.8" 1270 | }, 1271 | "conflict": { 1272 | "symfony/finder": "<3.4" 1273 | }, 1274 | "require-dev": { 1275 | "symfony/event-dispatcher": "^3.4|^4.0|^5.0", 1276 | "symfony/finder": "^3.4|^4.0|^5.0", 1277 | "symfony/messenger": "^4.1|^5.0", 1278 | "symfony/service-contracts": "^1.1|^2", 1279 | "symfony/yaml": "^3.4|^4.0|^5.0" 1280 | }, 1281 | "suggest": { 1282 | "symfony/yaml": "To use the yaml reference dumper" 1283 | }, 1284 | "type": "library", 1285 | "extra": { 1286 | "branch-alias": { 1287 | "dev-master": "4.4-dev" 1288 | } 1289 | }, 1290 | "autoload": { 1291 | "psr-4": { 1292 | "Symfony\\Component\\Config\\": "" 1293 | }, 1294 | "exclude-from-classmap": [ 1295 | "/Tests/" 1296 | ] 1297 | }, 1298 | "notification-url": "https://packagist.org/downloads/", 1299 | "license": [ 1300 | "MIT" 1301 | ], 1302 | "authors": [ 1303 | { 1304 | "name": "Fabien Potencier", 1305 | "email": "fabien@symfony.com" 1306 | }, 1307 | { 1308 | "name": "Symfony Community", 1309 | "homepage": "https://symfony.com/contributors" 1310 | } 1311 | ], 1312 | "description": "Symfony Config Component", 1313 | "homepage": "https://symfony.com", 1314 | "time": "2020-02-04T09:32:40+00:00" 1315 | }, 1316 | { 1317 | "name": "symfony/console", 1318 | "version": "v4.4.5", 1319 | "source": { 1320 | "type": "git", 1321 | "url": "https://github.com/symfony/console.git", 1322 | "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9" 1323 | }, 1324 | "dist": { 1325 | "type": "zip", 1326 | "url": "https://api.github.com/repos/symfony/console/zipball/4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", 1327 | "reference": "4fa15ae7be74e53f6ec8c83ed403b97e23b665e9", 1328 | "shasum": "" 1329 | }, 1330 | "require": { 1331 | "php": "^7.1.3", 1332 | "symfony/polyfill-mbstring": "~1.0", 1333 | "symfony/polyfill-php73": "^1.8", 1334 | "symfony/service-contracts": "^1.1|^2" 1335 | }, 1336 | "conflict": { 1337 | "symfony/dependency-injection": "<3.4", 1338 | "symfony/event-dispatcher": "<4.3|>=5", 1339 | "symfony/lock": "<4.4", 1340 | "symfony/process": "<3.3" 1341 | }, 1342 | "provide": { 1343 | "psr/log-implementation": "1.0" 1344 | }, 1345 | "require-dev": { 1346 | "psr/log": "~1.0", 1347 | "symfony/config": "^3.4|^4.0|^5.0", 1348 | "symfony/dependency-injection": "^3.4|^4.0|^5.0", 1349 | "symfony/event-dispatcher": "^4.3", 1350 | "symfony/lock": "^4.4|^5.0", 1351 | "symfony/process": "^3.4|^4.0|^5.0", 1352 | "symfony/var-dumper": "^4.3|^5.0" 1353 | }, 1354 | "suggest": { 1355 | "psr/log": "For using the console logger", 1356 | "symfony/event-dispatcher": "", 1357 | "symfony/lock": "", 1358 | "symfony/process": "" 1359 | }, 1360 | "type": "library", 1361 | "extra": { 1362 | "branch-alias": { 1363 | "dev-master": "4.4-dev" 1364 | } 1365 | }, 1366 | "autoload": { 1367 | "psr-4": { 1368 | "Symfony\\Component\\Console\\": "" 1369 | }, 1370 | "exclude-from-classmap": [ 1371 | "/Tests/" 1372 | ] 1373 | }, 1374 | "notification-url": "https://packagist.org/downloads/", 1375 | "license": [ 1376 | "MIT" 1377 | ], 1378 | "authors": [ 1379 | { 1380 | "name": "Fabien Potencier", 1381 | "email": "fabien@symfony.com" 1382 | }, 1383 | { 1384 | "name": "Symfony Community", 1385 | "homepage": "https://symfony.com/contributors" 1386 | } 1387 | ], 1388 | "description": "Symfony Console Component", 1389 | "homepage": "https://symfony.com", 1390 | "time": "2020-02-24T13:10:00+00:00" 1391 | }, 1392 | { 1393 | "name": "symfony/filesystem", 1394 | "version": "v4.4.5", 1395 | "source": { 1396 | "type": "git", 1397 | "url": "https://github.com/symfony/filesystem.git", 1398 | "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd" 1399 | }, 1400 | "dist": { 1401 | "type": "zip", 1402 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/266c9540b475f26122b61ef8b23dd9198f5d1cfd", 1403 | "reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd", 1404 | "shasum": "" 1405 | }, 1406 | "require": { 1407 | "php": "^7.1.3", 1408 | "symfony/polyfill-ctype": "~1.8" 1409 | }, 1410 | "type": "library", 1411 | "extra": { 1412 | "branch-alias": { 1413 | "dev-master": "4.4-dev" 1414 | } 1415 | }, 1416 | "autoload": { 1417 | "psr-4": { 1418 | "Symfony\\Component\\Filesystem\\": "" 1419 | }, 1420 | "exclude-from-classmap": [ 1421 | "/Tests/" 1422 | ] 1423 | }, 1424 | "notification-url": "https://packagist.org/downloads/", 1425 | "license": [ 1426 | "MIT" 1427 | ], 1428 | "authors": [ 1429 | { 1430 | "name": "Fabien Potencier", 1431 | "email": "fabien@symfony.com" 1432 | }, 1433 | { 1434 | "name": "Symfony Community", 1435 | "homepage": "https://symfony.com/contributors" 1436 | } 1437 | ], 1438 | "description": "Symfony Filesystem Component", 1439 | "homepage": "https://symfony.com", 1440 | "time": "2020-01-21T08:20:44+00:00" 1441 | }, 1442 | { 1443 | "name": "symfony/phpunit-bridge", 1444 | "version": "v5.0.5", 1445 | "source": { 1446 | "type": "git", 1447 | "url": "https://github.com/symfony/phpunit-bridge.git", 1448 | "reference": "b8fee53045a55ccbb9209e453bf6fdcf74381959" 1449 | }, 1450 | "dist": { 1451 | "type": "zip", 1452 | "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/b8fee53045a55ccbb9209e453bf6fdcf74381959", 1453 | "reference": "b8fee53045a55ccbb9209e453bf6fdcf74381959", 1454 | "shasum": "" 1455 | }, 1456 | "require": { 1457 | "php": ">=5.5.9" 1458 | }, 1459 | "conflict": { 1460 | "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0|<6.4,>=6.0" 1461 | }, 1462 | "suggest": { 1463 | "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" 1464 | }, 1465 | "bin": [ 1466 | "bin/simple-phpunit" 1467 | ], 1468 | "type": "symfony-bridge", 1469 | "extra": { 1470 | "branch-alias": { 1471 | "dev-master": "5.0-dev" 1472 | }, 1473 | "thanks": { 1474 | "name": "phpunit/phpunit", 1475 | "url": "https://github.com/sebastianbergmann/phpunit" 1476 | } 1477 | }, 1478 | "autoload": { 1479 | "files": [ 1480 | "bootstrap.php" 1481 | ], 1482 | "psr-4": { 1483 | "Symfony\\Bridge\\PhpUnit\\": "" 1484 | }, 1485 | "exclude-from-classmap": [ 1486 | "/Tests/" 1487 | ] 1488 | }, 1489 | "notification-url": "https://packagist.org/downloads/", 1490 | "license": [ 1491 | "MIT" 1492 | ], 1493 | "authors": [ 1494 | { 1495 | "name": "Nicolas Grekas", 1496 | "email": "p@tchwork.com" 1497 | }, 1498 | { 1499 | "name": "Symfony Community", 1500 | "homepage": "https://symfony.com/contributors" 1501 | } 1502 | ], 1503 | "description": "Symfony PHPUnit Bridge", 1504 | "homepage": "https://symfony.com", 1505 | "time": "2020-02-24T15:05:31+00:00" 1506 | }, 1507 | { 1508 | "name": "symfony/polyfill-ctype", 1509 | "version": "v1.14.0", 1510 | "source": { 1511 | "type": "git", 1512 | "url": "https://github.com/symfony/polyfill-ctype.git", 1513 | "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" 1514 | }, 1515 | "dist": { 1516 | "type": "zip", 1517 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", 1518 | "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", 1519 | "shasum": "" 1520 | }, 1521 | "require": { 1522 | "php": ">=5.3.3" 1523 | }, 1524 | "suggest": { 1525 | "ext-ctype": "For best performance" 1526 | }, 1527 | "type": "library", 1528 | "extra": { 1529 | "branch-alias": { 1530 | "dev-master": "1.14-dev" 1531 | } 1532 | }, 1533 | "autoload": { 1534 | "psr-4": { 1535 | "Symfony\\Polyfill\\Ctype\\": "" 1536 | }, 1537 | "files": [ 1538 | "bootstrap.php" 1539 | ] 1540 | }, 1541 | "notification-url": "https://packagist.org/downloads/", 1542 | "license": [ 1543 | "MIT" 1544 | ], 1545 | "authors": [ 1546 | { 1547 | "name": "Gert de Pagter", 1548 | "email": "BackEndTea@gmail.com" 1549 | }, 1550 | { 1551 | "name": "Symfony Community", 1552 | "homepage": "https://symfony.com/contributors" 1553 | } 1554 | ], 1555 | "description": "Symfony polyfill for ctype functions", 1556 | "homepage": "https://symfony.com", 1557 | "keywords": [ 1558 | "compatibility", 1559 | "ctype", 1560 | "polyfill", 1561 | "portable" 1562 | ], 1563 | "time": "2020-01-13T11:15:53+00:00" 1564 | }, 1565 | { 1566 | "name": "symfony/polyfill-mbstring", 1567 | "version": "v1.14.0", 1568 | "source": { 1569 | "type": "git", 1570 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1571 | "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" 1572 | }, 1573 | "dist": { 1574 | "type": "zip", 1575 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", 1576 | "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", 1577 | "shasum": "" 1578 | }, 1579 | "require": { 1580 | "php": ">=5.3.3" 1581 | }, 1582 | "suggest": { 1583 | "ext-mbstring": "For best performance" 1584 | }, 1585 | "type": "library", 1586 | "extra": { 1587 | "branch-alias": { 1588 | "dev-master": "1.14-dev" 1589 | } 1590 | }, 1591 | "autoload": { 1592 | "psr-4": { 1593 | "Symfony\\Polyfill\\Mbstring\\": "" 1594 | }, 1595 | "files": [ 1596 | "bootstrap.php" 1597 | ] 1598 | }, 1599 | "notification-url": "https://packagist.org/downloads/", 1600 | "license": [ 1601 | "MIT" 1602 | ], 1603 | "authors": [ 1604 | { 1605 | "name": "Nicolas Grekas", 1606 | "email": "p@tchwork.com" 1607 | }, 1608 | { 1609 | "name": "Symfony Community", 1610 | "homepage": "https://symfony.com/contributors" 1611 | } 1612 | ], 1613 | "description": "Symfony polyfill for the Mbstring extension", 1614 | "homepage": "https://symfony.com", 1615 | "keywords": [ 1616 | "compatibility", 1617 | "mbstring", 1618 | "polyfill", 1619 | "portable", 1620 | "shim" 1621 | ], 1622 | "time": "2020-01-13T11:15:53+00:00" 1623 | }, 1624 | { 1625 | "name": "symfony/polyfill-php73", 1626 | "version": "v1.14.0", 1627 | "source": { 1628 | "type": "git", 1629 | "url": "https://github.com/symfony/polyfill-php73.git", 1630 | "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" 1631 | }, 1632 | "dist": { 1633 | "type": "zip", 1634 | "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", 1635 | "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", 1636 | "shasum": "" 1637 | }, 1638 | "require": { 1639 | "php": ">=5.3.3" 1640 | }, 1641 | "type": "library", 1642 | "extra": { 1643 | "branch-alias": { 1644 | "dev-master": "1.14-dev" 1645 | } 1646 | }, 1647 | "autoload": { 1648 | "psr-4": { 1649 | "Symfony\\Polyfill\\Php73\\": "" 1650 | }, 1651 | "files": [ 1652 | "bootstrap.php" 1653 | ], 1654 | "classmap": [ 1655 | "Resources/stubs" 1656 | ] 1657 | }, 1658 | "notification-url": "https://packagist.org/downloads/", 1659 | "license": [ 1660 | "MIT" 1661 | ], 1662 | "authors": [ 1663 | { 1664 | "name": "Nicolas Grekas", 1665 | "email": "p@tchwork.com" 1666 | }, 1667 | { 1668 | "name": "Symfony Community", 1669 | "homepage": "https://symfony.com/contributors" 1670 | } 1671 | ], 1672 | "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", 1673 | "homepage": "https://symfony.com", 1674 | "keywords": [ 1675 | "compatibility", 1676 | "polyfill", 1677 | "portable", 1678 | "shim" 1679 | ], 1680 | "time": "2020-01-13T11:15:53+00:00" 1681 | }, 1682 | { 1683 | "name": "symfony/service-contracts", 1684 | "version": "v1.1.8", 1685 | "source": { 1686 | "type": "git", 1687 | "url": "https://github.com/symfony/service-contracts.git", 1688 | "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" 1689 | }, 1690 | "dist": { 1691 | "type": "zip", 1692 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", 1693 | "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", 1694 | "shasum": "" 1695 | }, 1696 | "require": { 1697 | "php": "^7.1.3", 1698 | "psr/container": "^1.0" 1699 | }, 1700 | "suggest": { 1701 | "symfony/service-implementation": "" 1702 | }, 1703 | "type": "library", 1704 | "extra": { 1705 | "branch-alias": { 1706 | "dev-master": "1.1-dev" 1707 | } 1708 | }, 1709 | "autoload": { 1710 | "psr-4": { 1711 | "Symfony\\Contracts\\Service\\": "" 1712 | } 1713 | }, 1714 | "notification-url": "https://packagist.org/downloads/", 1715 | "license": [ 1716 | "MIT" 1717 | ], 1718 | "authors": [ 1719 | { 1720 | "name": "Nicolas Grekas", 1721 | "email": "p@tchwork.com" 1722 | }, 1723 | { 1724 | "name": "Symfony Community", 1725 | "homepage": "https://symfony.com/contributors" 1726 | } 1727 | ], 1728 | "description": "Generic abstractions related to writing services", 1729 | "homepage": "https://symfony.com", 1730 | "keywords": [ 1731 | "abstractions", 1732 | "contracts", 1733 | "decoupling", 1734 | "interfaces", 1735 | "interoperability", 1736 | "standards" 1737 | ], 1738 | "time": "2019-10-14T12:27:06+00:00" 1739 | }, 1740 | { 1741 | "name": "symfony/stopwatch", 1742 | "version": "v4.4.5", 1743 | "source": { 1744 | "type": "git", 1745 | "url": "https://github.com/symfony/stopwatch.git", 1746 | "reference": "abc08d7c48987829bac301347faa10f7e8bbf4fb" 1747 | }, 1748 | "dist": { 1749 | "type": "zip", 1750 | "url": "https://api.github.com/repos/symfony/stopwatch/zipball/abc08d7c48987829bac301347faa10f7e8bbf4fb", 1751 | "reference": "abc08d7c48987829bac301347faa10f7e8bbf4fb", 1752 | "shasum": "" 1753 | }, 1754 | "require": { 1755 | "php": "^7.1.3", 1756 | "symfony/service-contracts": "^1.0|^2" 1757 | }, 1758 | "type": "library", 1759 | "extra": { 1760 | "branch-alias": { 1761 | "dev-master": "4.4-dev" 1762 | } 1763 | }, 1764 | "autoload": { 1765 | "psr-4": { 1766 | "Symfony\\Component\\Stopwatch\\": "" 1767 | }, 1768 | "exclude-from-classmap": [ 1769 | "/Tests/" 1770 | ] 1771 | }, 1772 | "notification-url": "https://packagist.org/downloads/", 1773 | "license": [ 1774 | "MIT" 1775 | ], 1776 | "authors": [ 1777 | { 1778 | "name": "Fabien Potencier", 1779 | "email": "fabien@symfony.com" 1780 | }, 1781 | { 1782 | "name": "Symfony Community", 1783 | "homepage": "https://symfony.com/contributors" 1784 | } 1785 | ], 1786 | "description": "Symfony Stopwatch Component", 1787 | "homepage": "https://symfony.com", 1788 | "time": "2020-01-04T13:00:46+00:00" 1789 | }, 1790 | { 1791 | "name": "symfony/yaml", 1792 | "version": "v4.4.5", 1793 | "source": { 1794 | "type": "git", 1795 | "url": "https://github.com/symfony/yaml.git", 1796 | "reference": "94d005c176db2080e98825d98e01e8b311a97a88" 1797 | }, 1798 | "dist": { 1799 | "type": "zip", 1800 | "url": "https://api.github.com/repos/symfony/yaml/zipball/94d005c176db2080e98825d98e01e8b311a97a88", 1801 | "reference": "94d005c176db2080e98825d98e01e8b311a97a88", 1802 | "shasum": "" 1803 | }, 1804 | "require": { 1805 | "php": "^7.1.3", 1806 | "symfony/polyfill-ctype": "~1.8" 1807 | }, 1808 | "conflict": { 1809 | "symfony/console": "<3.4" 1810 | }, 1811 | "require-dev": { 1812 | "symfony/console": "^3.4|^4.0|^5.0" 1813 | }, 1814 | "suggest": { 1815 | "symfony/console": "For validating YAML files using the lint command" 1816 | }, 1817 | "type": "library", 1818 | "extra": { 1819 | "branch-alias": { 1820 | "dev-master": "4.4-dev" 1821 | } 1822 | }, 1823 | "autoload": { 1824 | "psr-4": { 1825 | "Symfony\\Component\\Yaml\\": "" 1826 | }, 1827 | "exclude-from-classmap": [ 1828 | "/Tests/" 1829 | ] 1830 | }, 1831 | "notification-url": "https://packagist.org/downloads/", 1832 | "license": [ 1833 | "MIT" 1834 | ], 1835 | "authors": [ 1836 | { 1837 | "name": "Fabien Potencier", 1838 | "email": "fabien@symfony.com" 1839 | }, 1840 | { 1841 | "name": "Symfony Community", 1842 | "homepage": "https://symfony.com/contributors" 1843 | } 1844 | ], 1845 | "description": "Symfony Yaml Component", 1846 | "homepage": "https://symfony.com", 1847 | "time": "2020-02-03T10:46:43+00:00" 1848 | }, 1849 | { 1850 | "name": "vimeo/psalm", 1851 | "version": "3.9.3", 1852 | "source": { 1853 | "type": "git", 1854 | "url": "https://github.com/vimeo/psalm.git", 1855 | "reference": "2e4154d76e24d1b4e59e6cc2bebef7790cb9e550" 1856 | }, 1857 | "dist": { 1858 | "type": "zip", 1859 | "url": "https://api.github.com/repos/vimeo/psalm/zipball/2e4154d76e24d1b4e59e6cc2bebef7790cb9e550", 1860 | "reference": "2e4154d76e24d1b4e59e6cc2bebef7790cb9e550", 1861 | "shasum": "" 1862 | }, 1863 | "require": { 1864 | "amphp/amp": "^2.1", 1865 | "amphp/byte-stream": "^1.5", 1866 | "composer/semver": "^1.4", 1867 | "composer/xdebug-handler": "^1.1", 1868 | "ext-dom": "*", 1869 | "ext-json": "*", 1870 | "ext-libxml": "*", 1871 | "ext-simplexml": "*", 1872 | "ext-tokenizer": "*", 1873 | "felixfbecker/advanced-json-rpc": "^3.0.3", 1874 | "felixfbecker/language-server-protocol": "^1.4", 1875 | "netresearch/jsonmapper": "^1.0", 1876 | "nikic/php-parser": "^4.3", 1877 | "ocramius/package-versions": "^1.2", 1878 | "openlss/lib-array2xml": "^1.0", 1879 | "php": "^7.1.3|^8", 1880 | "sebastian/diff": "^3.0 || ^4.0", 1881 | "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", 1882 | "webmozart/glob": "^4.1", 1883 | "webmozart/path-util": "^2.3" 1884 | }, 1885 | "provide": { 1886 | "psalm/psalm": "self.version" 1887 | }, 1888 | "require-dev": { 1889 | "bamarni/composer-bin-plugin": "^1.2", 1890 | "ext-curl": "*", 1891 | "phpmyadmin/sql-parser": "5.1.0", 1892 | "phpspec/prophecy": ">=1.9.0", 1893 | "phpunit/phpunit": "^7.5.16 || ^8.0", 1894 | "psalm/plugin-phpunit": "^0.9", 1895 | "slevomat/coding-standard": "^5.0", 1896 | "squizlabs/php_codesniffer": "^3.5", 1897 | "symfony/process": "^4.3" 1898 | }, 1899 | "suggest": { 1900 | "ext-igbinary": "^2.0.5" 1901 | }, 1902 | "bin": [ 1903 | "psalm", 1904 | "psalm-language-server", 1905 | "psalm-plugin", 1906 | "psalm-refactor", 1907 | "psalter" 1908 | ], 1909 | "type": "library", 1910 | "extra": { 1911 | "branch-alias": { 1912 | "dev-master": "3.x-dev", 1913 | "dev-2.x": "2.x-dev", 1914 | "dev-1.x": "1.x-dev" 1915 | } 1916 | }, 1917 | "autoload": { 1918 | "psr-4": { 1919 | "Psalm\\Plugin\\": "src/Psalm/Plugin", 1920 | "Psalm\\": "src/Psalm" 1921 | }, 1922 | "files": [ 1923 | "src/functions.php", 1924 | "src/spl_object_id.php" 1925 | ] 1926 | }, 1927 | "notification-url": "https://packagist.org/downloads/", 1928 | "license": [ 1929 | "MIT" 1930 | ], 1931 | "authors": [ 1932 | { 1933 | "name": "Matthew Brown" 1934 | } 1935 | ], 1936 | "description": "A static analysis tool for finding errors in PHP applications", 1937 | "keywords": [ 1938 | "code", 1939 | "inspection", 1940 | "php" 1941 | ], 1942 | "time": "2020-02-19T01:30:37+00:00" 1943 | }, 1944 | { 1945 | "name": "webmozart/assert", 1946 | "version": "1.7.0", 1947 | "source": { 1948 | "type": "git", 1949 | "url": "https://github.com/webmozart/assert.git", 1950 | "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" 1951 | }, 1952 | "dist": { 1953 | "type": "zip", 1954 | "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", 1955 | "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", 1956 | "shasum": "" 1957 | }, 1958 | "require": { 1959 | "php": "^5.3.3 || ^7.0", 1960 | "symfony/polyfill-ctype": "^1.8" 1961 | }, 1962 | "conflict": { 1963 | "vimeo/psalm": "<3.6.0" 1964 | }, 1965 | "require-dev": { 1966 | "phpunit/phpunit": "^4.8.36 || ^7.5.13" 1967 | }, 1968 | "type": "library", 1969 | "autoload": { 1970 | "psr-4": { 1971 | "Webmozart\\Assert\\": "src/" 1972 | } 1973 | }, 1974 | "notification-url": "https://packagist.org/downloads/", 1975 | "license": [ 1976 | "MIT" 1977 | ], 1978 | "authors": [ 1979 | { 1980 | "name": "Bernhard Schussek", 1981 | "email": "bschussek@gmail.com" 1982 | } 1983 | ], 1984 | "description": "Assertions to validate method input/output with nice error messages.", 1985 | "keywords": [ 1986 | "assert", 1987 | "check", 1988 | "validate" 1989 | ], 1990 | "time": "2020-02-14T12:15:55+00:00" 1991 | }, 1992 | { 1993 | "name": "webmozart/glob", 1994 | "version": "4.1.0", 1995 | "source": { 1996 | "type": "git", 1997 | "url": "https://github.com/webmozart/glob.git", 1998 | "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" 1999 | }, 2000 | "dist": { 2001 | "type": "zip", 2002 | "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", 2003 | "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", 2004 | "shasum": "" 2005 | }, 2006 | "require": { 2007 | "php": "^5.3.3|^7.0", 2008 | "webmozart/path-util": "^2.2" 2009 | }, 2010 | "require-dev": { 2011 | "phpunit/phpunit": "^4.6", 2012 | "sebastian/version": "^1.0.1", 2013 | "symfony/filesystem": "^2.5" 2014 | }, 2015 | "type": "library", 2016 | "extra": { 2017 | "branch-alias": { 2018 | "dev-master": "4.1-dev" 2019 | } 2020 | }, 2021 | "autoload": { 2022 | "psr-4": { 2023 | "Webmozart\\Glob\\": "src/" 2024 | } 2025 | }, 2026 | "notification-url": "https://packagist.org/downloads/", 2027 | "license": [ 2028 | "MIT" 2029 | ], 2030 | "authors": [ 2031 | { 2032 | "name": "Bernhard Schussek", 2033 | "email": "bschussek@gmail.com" 2034 | } 2035 | ], 2036 | "description": "A PHP implementation of Ant's glob.", 2037 | "time": "2015-12-29T11:14:33+00:00" 2038 | }, 2039 | { 2040 | "name": "webmozart/path-util", 2041 | "version": "2.3.0", 2042 | "source": { 2043 | "type": "git", 2044 | "url": "https://github.com/webmozart/path-util.git", 2045 | "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" 2046 | }, 2047 | "dist": { 2048 | "type": "zip", 2049 | "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", 2050 | "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", 2051 | "shasum": "" 2052 | }, 2053 | "require": { 2054 | "php": ">=5.3.3", 2055 | "webmozart/assert": "~1.0" 2056 | }, 2057 | "require-dev": { 2058 | "phpunit/phpunit": "^4.6", 2059 | "sebastian/version": "^1.0.1" 2060 | }, 2061 | "type": "library", 2062 | "extra": { 2063 | "branch-alias": { 2064 | "dev-master": "2.3-dev" 2065 | } 2066 | }, 2067 | "autoload": { 2068 | "psr-4": { 2069 | "Webmozart\\PathUtil\\": "src/" 2070 | } 2071 | }, 2072 | "notification-url": "https://packagist.org/downloads/", 2073 | "license": [ 2074 | "MIT" 2075 | ], 2076 | "authors": [ 2077 | { 2078 | "name": "Bernhard Schussek", 2079 | "email": "bschussek@gmail.com" 2080 | } 2081 | ], 2082 | "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", 2083 | "time": "2015-12-17T08:42:14+00:00" 2084 | } 2085 | ], 2086 | "aliases": [], 2087 | "minimum-stability": "stable", 2088 | "stability-flags": [], 2089 | "prefer-stable": false, 2090 | "prefer-lowest": false, 2091 | "platform": { 2092 | "php": ">=7.1" 2093 | }, 2094 | "platform-dev": [] 2095 | } 2096 | -------------------------------------------------------------------------------- /docs/definition.md: -------------------------------------------------------------------------------- 1 | # PHP Enum 2 | 3 | ## Definition 4 | 5 | The `Cloudstek\Enum\Enum` base class takes care of all the work behind the scenes so all you have to do is extend your enum class from that and define your members using either properties, constants, methods or a mix of those. 6 | 7 | All properties, constants and methods will be made into enumeration members unless you prefix them with `_`. 8 | 9 | ```php 10 | use Cloudstek\Enum\Enum; 11 | 12 | /** 13 | * @method static self TODO() 14 | * @method static self IN_PROGRESS() 15 | * @method static self DONE() 16 | */ 17 | class TaskStatus extends Enum 18 | { 19 | private const TODO = 'todo'; 20 | 21 | private $inProgress = 'in_progress'; 22 | 23 | private function done() 24 | { 25 | return 'done'; 26 | } 27 | 28 | private const _I_AM_IGNORED = 'hello'; 29 | } 30 | ``` 31 | 32 | To allow for autocompletion in IDEs, add the `@method` 33 | 34 | ### Naming members 35 | 36 | Every time you access a member (either directly, using `get()` or `has()`), the name will be normalised to match how you name your constants, properties or methods. This allows for case-insensitive access to the enum members. 37 | 38 | ```php 39 | TaskStatus::has('toDo'); // true 40 | TaskStatus::has('IN_PROGRESS'); // true 41 | TaskStatus::has('DONE'); // true 42 | 43 | TaskStatus::get('ToDo') === TaskStatus::TODO(); // true 44 | TaskStatus::toDo() === TaskStatus::TODO(); // true 45 | ``` 46 | 47 | Notice how `$inProgress` is defined yet you can access it using `IN_PROGRESS`. 48 | 49 | Normalisation of names is controlled by several functions in the enum base class which you can override to suit your needs: 50 | 51 | **normalizeConstantName(string $name): string** 52 | For normalising to constant names. This defaults to upper snake case (e.g. FOO_BAR). 53 | 54 | **normalizePropertyName(string $name): string** 55 | For normalising to property names. This defaults to camel case (e.g. fooBar). 56 | 57 | **normalizeMethodName(string $name): string** 58 | For normalising to method names. This defaults to camel case (e.g. fooBar). 59 | 60 | For example to use camelCase for constants: 61 | 62 | ```php 63 | use Cloudstek\Enum\Enum; 64 | 65 | /** 66 | * @method static self TODO() 67 | * @method static self IN_PROGRESS() 68 | * @method static self DONE() 69 | */ 70 | class TaskStatus extends Enum 71 | { 72 | private const todo = 'todo'; 73 | private const inProgress = 'in_progress'; 74 | private const done = 'done'; 75 | 76 | /** 77 | * Convert the member name to camelCase constant name. 78 | */ 79 | protected static function normalizeConstantName(string $name): string 80 | { 81 | $parts = explode('_', strtolower($name), 2); 82 | 83 | if (count($parts) === 1) { 84 | return $parts[0]; 85 | } 86 | 87 | return $parts[0].str_replace(' ', '', ucwords(str_replace('_', ' ', $parts[1]))); 88 | } 89 | } 90 | ``` 91 | 92 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ./src 9 | tests/* 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | tests 14 | 15 | 16 | 17 | 18 | 19 | src 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Enum.php: -------------------------------------------------------------------------------- 1 | > 13 | */ 14 | private static $_instances = []; 15 | 16 | /** 17 | * Name. 18 | * 19 | * @var string 20 | */ 21 | private $_name; 22 | 23 | /** 24 | * Value. 25 | * 26 | * @var mixed 27 | */ 28 | private $_value; 29 | 30 | /** 31 | * Enum. 32 | * 33 | * @param string $name 34 | * @param mixed $value 35 | */ 36 | protected function __construct(string $name, $value = null) 37 | { 38 | $this->_name = $name; 39 | $this->_value = $value; 40 | } 41 | 42 | /** 43 | * Get name. 44 | * 45 | * @return string 46 | */ 47 | final public function getName(): string 48 | { 49 | return $this->_name; 50 | } 51 | 52 | /** 53 | * Get value. 54 | * 55 | * @return mixed 56 | */ 57 | final public function getValue() 58 | { 59 | return $this->_value; 60 | } 61 | 62 | /** 63 | * JSON serialize. 64 | * 65 | * @see http://php.net/manual/en/jsonserializable.jsonserialize.php 66 | * 67 | * @return mixed 68 | */ 69 | public function jsonSerialize() 70 | { 71 | return $this->_value; 72 | } 73 | 74 | /** 75 | * Convert the enum to a String value. 76 | * 77 | * @see https://www.php.net/manual/en/language.oop5.magic.php#object.tostring 78 | * 79 | * @return string 80 | */ 81 | public function __toString() 82 | { 83 | return (string) $this->_value; 84 | } 85 | 86 | /** 87 | * Sleep. 88 | * 89 | * @see https://www.php.net/manual/en/language.oop5.magic.php#object.sleep 90 | */ 91 | public function __sleep() 92 | { 93 | throw new \LogicException('Enum is not serializable.'); 94 | } 95 | 96 | /** 97 | * Wakeup. 98 | * 99 | * @see https://www.php.net/manual/en/language.oop5.magic.php#object.wakeup 100 | */ 101 | public function __wakeup() 102 | { 103 | throw new \LogicException('Enum is not serializable.'); 104 | } 105 | 106 | /** 107 | * Clone. 108 | * 109 | * @see https://www.php.net/manual/en/language.oop5.cloning.php#object.clone 110 | */ 111 | public function __clone() 112 | { 113 | throw new \LogicException('Enum is not cloneable.'); 114 | } 115 | 116 | /** 117 | * Get an enum instance by name. 118 | * 119 | * @param string|static $name Name or member instance. 120 | * 121 | * @throws \UnexpectedValueException on unknown enum member 122 | * 123 | * @return static 124 | */ 125 | final public static function get($name) 126 | { 127 | // Called class name 128 | $calledClass = static::class; 129 | 130 | // If it's an enum instance, check it. 131 | if (is_object($name)) { 132 | if ($name instanceof $calledClass === false) { 133 | throw new \UnexpectedValueException( 134 | sprintf('Instance is not an enum member of %s.', static::class) 135 | ); 136 | } 137 | 138 | // Get actual name 139 | $name = $name->getName(); 140 | 141 | $instance = self::$_instances[$calledClass][$name] ?? null; 142 | 143 | if ($instance !== null) { 144 | return $instance; 145 | } 146 | } 147 | 148 | // Prevent access to properties, constants and method prefixed with _ 149 | if (strpos($name, '_') === 0) { 150 | throw new \UnexpectedValueException( 151 | sprintf('%s is not an enum member of %s.', $name, static::class) 152 | ); 153 | } 154 | 155 | // Normalize name to upper snake_case 156 | $name = self::normalizeName($name); 157 | 158 | // Return cached instance. 159 | if (isset(self::$_instances[$calledClass][$name])) { 160 | return self::$_instances[$calledClass][$name]; 161 | } 162 | 163 | // Reflection 164 | $ref = new \ReflectionClass($calledClass); 165 | 166 | // Convert casing 167 | $constName = static::normalizeConstantName($name); 168 | $propName = static::normalizePropertyName($name); 169 | $methodName = static::normalizeMethodName($name); 170 | 171 | // Property or constant value 172 | $value = null; 173 | 174 | if ($ref->hasConstant($constName)) { 175 | $value = $ref->getConstant($constName); 176 | } elseif ($ref->hasProperty($propName)) { 177 | $prop = $ref->getProperty($propName); 178 | $prop->setAccessible(true); 179 | 180 | $value = $prop->getValue(new static('')); 181 | } elseif ($ref->hasMethod($methodName)) { 182 | $method = $ref->getMethod($methodName); 183 | $method->setAccessible(true); 184 | 185 | $value = $method->invoke(new static('')); 186 | } else { 187 | throw new \UnexpectedValueException( 188 | sprintf('%s is not an enum member of %s.', $name, $calledClass) 189 | ); 190 | } 191 | 192 | if (isset(self::$_instances[$calledClass]) === false) { 193 | self::$_instances[$calledClass] = []; 194 | } 195 | 196 | // Create and store instance 197 | self::$_instances[$calledClass][$name] = new static($name, $value); 198 | 199 | return self::$_instances[$calledClass][$name]; 200 | } 201 | 202 | /** 203 | * Check if enum has a member. 204 | * 205 | * @param string|static $name 206 | * 207 | * @return bool 208 | */ 209 | final public static function has($name): bool 210 | { 211 | // Called class name 212 | $calledClass = static::class; 213 | 214 | // If it's an enum instance, check it. 215 | if (is_object($name)) { 216 | if ($name instanceof $calledClass === false) { 217 | return false; 218 | } 219 | 220 | // Get actual name 221 | $name = $name->getName(); 222 | 223 | $instance = self::$_instances[$calledClass][$name] ?? null; 224 | 225 | if ($instance !== null) { 226 | return true; 227 | } 228 | } 229 | 230 | // Prevent access to properties, constants and method prefixed with _ 231 | if (strpos($name, '_') === 0) { 232 | return false; 233 | } 234 | 235 | $ref = new \ReflectionClass($calledClass); 236 | 237 | // Normalize name to upper snake_case. 238 | $normalName = self::normalizeName($name); 239 | 240 | // Check if cached. 241 | if (isset(self::$_instances[$calledClass][$name])) { 242 | return true; 243 | } 244 | 245 | // Convert casing 246 | $constName = static::normalizeConstantName($normalName); 247 | $propName = static::normalizePropertyName($normalName); 248 | $methodName = str_replace('_', '', self::normalizeMethodName($normalName)); 249 | 250 | return $ref->hasConstant($constName) 251 | || $ref->hasProperty($propName) 252 | || $ref->hasMethod($methodName) 253 | ; 254 | } 255 | 256 | /** 257 | * Call static. 258 | * 259 | * @param string $name 260 | * @param array $arguments 261 | * 262 | * @throws \BadMethodCallException on unknown enum member 263 | * 264 | * @see https://www.php.net/manual/en/language.oop5.overloading.php#object.callstatic 265 | * 266 | * @return static 267 | */ 268 | final public static function __callStatic($name, $arguments) 269 | { 270 | try { 271 | return static::get($name); 272 | } catch (\UnexpectedValueException $ex) { 273 | throw new \BadMethodCallException($ex->getMessage(), 0, $ex); 274 | } 275 | } 276 | 277 | /** 278 | * Convert the member name to constant name. 279 | * 280 | * By default this will convert everything to uppercase. 281 | * 282 | * Override this method if you prefer other casing. 283 | * 284 | * @param string $name The normalized member name (e.g. FOO_BAR) 285 | * 286 | * @return string the constant name 287 | */ 288 | protected static function normalizeConstantName(string $name): string 289 | { 290 | return strtoupper($name); 291 | } 292 | 293 | /** 294 | * Convert the member name to property name. 295 | * 296 | * By default this will convert upper snake_case (e.g. FOO_BAR) to camelCase (e.g. fooBar). 297 | * 298 | * Override this method if you prefer other casing like snake_case. 299 | * 300 | * @param string $name The normalized member name (e.g. FOO_BAR) 301 | * 302 | * @return string the property name 303 | */ 304 | protected static function normalizePropertyName(string $name): string 305 | { 306 | $parts = explode('_', strtolower($name), 2); 307 | 308 | if (count($parts) === 1) { 309 | return $parts[0]; 310 | } 311 | 312 | return $parts[0].str_replace(' ', '', ucwords(str_replace('_', ' ', $parts[1]))); 313 | } 314 | 315 | /** 316 | * Convert the member name to method name. 317 | * 318 | * By default this will convert upper snake_case (e.g. FOO_BAR) to camelCase (e.g. fooBar). 319 | * 320 | * Override this method if you prefer other casing like snake_case. 321 | * 322 | * @param string $name The normalized member name (e.g. FOO_BAR) 323 | * 324 | * @return string the method name (without ()) 325 | */ 326 | protected static function normalizeMethodName(string $name): string 327 | { 328 | $parts = explode('_', strtolower($name), 2); 329 | 330 | if (count($parts) === 1) { 331 | return $parts[0]; 332 | } 333 | 334 | return $parts[0].str_replace(' ', '', ucwords(str_replace('_', ' ', $parts[1]))); 335 | } 336 | 337 | /** 338 | * Normalize name. 339 | * 340 | * @param string $name 341 | * 342 | * @return string name in upper snake_case 343 | */ 344 | private static function normalizeName(string $name): string 345 | { 346 | $name = str_replace(' ', '_', $name); 347 | 348 | if (strpos($name, '_') === false && preg_match('/[A-Z]{2,}/', $name) !== 1) { 349 | $name = preg_replace('/(?assertInstanceOf(get_class($enum), $enum::FOO()); 27 | $this->assertSame($enum::FOO(), $enum::FOO()); 28 | $this->assertSame($enum::get('FOO'), $enum::FOO()); 29 | 30 | $this->assertInstanceOf(get_class($enum), $enum::BAR()); 31 | $this->assertSame($enum::BAR(), $enum::BAR()); 32 | $this->assertSame($enum::get('BAR'), $enum::BAR()); 33 | 34 | $this->assertInstanceOf(get_class($enum), $enum::LORUM()); 35 | $this->assertSame($enum::LORUM(), $enum::LORUM()); 36 | $this->assertSame($enum::get('LORUM'), $enum::LORUM()); 37 | } 38 | 39 | /** 40 | * Test same instances case-insensitive when calling static. 41 | */ 42 | public function testSameInstanceStaticCaseInsensitive() 43 | { 44 | $enum = new class() extends Fixtures\AbstractTestEnum { 45 | private $foo = 'foo'; 46 | private $otherFoo = 'other foo'; 47 | 48 | private const BAR = 'bar'; 49 | private const OTHER_BAR = 'other bar'; 50 | 51 | private function lorum() 52 | { 53 | return 'lorum'; 54 | } 55 | 56 | private function otherLorum() 57 | { 58 | return 'other lorum'; 59 | } 60 | }; 61 | 62 | $this->assertSame($enum::FOO(), $enum::foo()); 63 | $this->assertSame($enum::OTHER_FOO(), $enum::other_foo()); 64 | $this->assertSame($enum::OTHER_FOO(), $enum::Other_FoO()); 65 | $this->assertSame($enum::OTHER_FOO(), $enum::otherFoo()); 66 | $this->assertSame($enum::OTHER_FOO(), $enum::OtherFoo()); 67 | 68 | $this->assertSame($enum::BAR(), $enum::bar()); 69 | $this->assertSame($enum::OTHER_BAR(), $enum::other_bar()); 70 | $this->assertSame($enum::OTHER_BAR(), $enum::Other_BaR()); 71 | $this->assertSame($enum::OTHER_BAR(), $enum::otherBar()); 72 | $this->assertSame($enum::OTHER_BAR(), $enum::OtherBar()); 73 | 74 | $this->assertSame($enum::LORUM(), $enum::lorum()); 75 | $this->assertSame($enum::OTHER_LORUM(), $enum::other_lorum()); 76 | $this->assertSame($enum::OTHER_LORUM(), $enum::Other_LoRum()); 77 | $this->assertSame($enum::OTHER_LORUM(), $enum::otherLorum()); 78 | $this->assertSame($enum::OTHER_LORUM(), $enum::OtherLorum()); 79 | } 80 | 81 | /** 82 | * Test same instances case-insensitive when calling with get(). 83 | */ 84 | public function testSameInstanceGetterCaseInsensitive() 85 | { 86 | $enum = new class() extends Fixtures\AbstractTestEnum { 87 | private $foo = 'foo'; 88 | private $otherFoo = 'other foo'; 89 | 90 | private const BAR = 'bar'; 91 | private const OTHER_BAR = 'other bar'; 92 | 93 | private function lorum() 94 | { 95 | return 'lorum'; 96 | } 97 | 98 | private function otherLorum() 99 | { 100 | return 'other lorum'; 101 | } 102 | }; 103 | 104 | $this->assertSame($enum::FOO(), $enum::get('foo')); 105 | $this->assertSame($enum::OTHER_FOO(), $enum::get('other_foo')); 106 | $this->assertSame($enum::OTHER_FOO(), $enum::get('Other_FoO')); 107 | $this->assertSame($enum::OTHER_FOO(), $enum::get('otherFoo')); 108 | $this->assertSame($enum::OTHER_FOO(), $enum::get('OtherFoo')); 109 | 110 | $this->assertSame($enum::BAR(), $enum::get('bar')); 111 | $this->assertSame($enum::OTHER_BAR(), $enum::get('other_bar')); 112 | $this->assertSame($enum::OTHER_BAR(), $enum::get('Other_BaR')); 113 | $this->assertSame($enum::OTHER_BAR(), $enum::get('otherBar')); 114 | $this->assertSame($enum::OTHER_BAR(), $enum::get('OtherBar')); 115 | 116 | $this->assertSame($enum::LORUM(), $enum::get('lorum')); 117 | $this->assertSame($enum::OTHER_LORUM(), $enum::get('other_lorum')); 118 | $this->assertSame($enum::OTHER_LORUM(), $enum::get('Other_LoRum')); 119 | $this->assertSame($enum::OTHER_LORUM(), $enum::get('otherLorum')); 120 | $this->assertSame($enum::OTHER_LORUM(), $enum::get('OtherLorum')); 121 | } 122 | 123 | /** 124 | * Test same instances when calling with get() by instance. 125 | */ 126 | public function testSameInstanceGetterByInstance() 127 | { 128 | $enum = new class() extends Fixtures\AbstractTestEnum { 129 | private $foo = 'foo'; 130 | private const BAR = 'bar'; 131 | 132 | private function lorum() 133 | { 134 | return 'lorum'; 135 | } 136 | }; 137 | 138 | $this->assertSame($enum::get($enum::FOO()), $enum::FOO()); 139 | $this->assertSame($enum::get($enum::BAR()), $enum::BAR()); 140 | $this->assertSame($enum::get($enum::LORUM()), $enum::LORUM()); 141 | } 142 | 143 | /** 144 | * Test get() will throw an exception when calling it with a different instance. 145 | */ 146 | public function testSameInstanceGetterByDifferentInstanceThrowing() 147 | { 148 | $this->expectException(\UnexpectedValueException::class); 149 | 150 | $enum = new class() extends Fixtures\AbstractTestEnum { 151 | private $foo = 'foo'; 152 | private const BAR = 'bar'; 153 | 154 | private function lorum() 155 | { 156 | return 'lorum'; 157 | } 158 | }; 159 | 160 | $otherEnum = new class() extends Fixtures\AbstractTestEnum { 161 | private $hello = 'world'; 162 | }; 163 | 164 | $this->assertNotSame($enum::get($otherEnum::HELLO()), $otherEnum::HELLO()); 165 | } 166 | 167 | /** 168 | * Test different instances with same value to not equal. 169 | */ 170 | public function testSameValueDifferentInstance() 171 | { 172 | $enum = new class() extends Fixtures\AbstractTestEnum { 173 | private $foo = 'foo'; 174 | private $otherFoo = 'foo'; 175 | 176 | private const BAR = 'bar'; 177 | private const OTHER_BAR = 'bar'; 178 | 179 | private function lorum() 180 | { 181 | return 'lorum'; 182 | } 183 | 184 | private function otherLorum() 185 | { 186 | return 'lorum'; 187 | } 188 | }; 189 | 190 | $this->assertEquals('foo', $enum::FOO()->getValue()); 191 | $this->assertEquals('foo', $enum::OTHER_FOO()->getValue()); 192 | $this->assertNotSame($enum::FOO(), $enum::OTHER_FOO()); 193 | 194 | $this->assertEquals('bar', $enum::BAR()->getValue()); 195 | $this->assertEquals('bar', $enum::OTHER_BAR()->getValue()); 196 | $this->assertNotSame($enum::BAR(), $enum::OTHER_BAR()); 197 | 198 | $this->assertEquals('lorum', $enum::LORUM()->getValue()); 199 | $this->assertEquals('lorum', $enum::OTHER_LORUM()->getValue()); 200 | $this->assertNotSame($enum::LORUM(), $enum::OTHER_LORUM()); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /tests/ExistenceTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($enum::has('FOO')); 36 | $this->assertTrue($enum::has('foo')); 37 | 38 | // snake_case property 39 | $this->assertTrue($enum::has('OTHER_FOO')); 40 | $this->assertTrue($enum::has('other_foo')); 41 | $this->assertTrue($enum::has('Other_FoO')); 42 | 43 | // camelCase property 44 | $this->assertTrue($enum::has('otherFoo')); 45 | $this->assertTrue($enum::has('OtherFoo')); 46 | 47 | // Constant 48 | $this->assertTrue($enum::has('BAR')); 49 | $this->assertTrue($enum::has('bar')); 50 | 51 | // snake_case constant 52 | $this->assertTrue($enum::has('OTHER_BAR')); 53 | $this->assertTrue($enum::has('OTHER BAR')); 54 | $this->assertTrue($enum::has('other_bar')); 55 | $this->assertTrue($enum::has('Other_BaR')); 56 | 57 | // camelCase constant 58 | $this->assertTrue($enum::has('otherBar')); 59 | $this->assertTrue($enum::has('OtherBar')); 60 | 61 | // Method 62 | $this->assertTrue($enum::has('LORUM')); 63 | $this->assertTrue($enum::has('lorum')); 64 | 65 | // snake_case method 66 | $this->assertTrue($enum::has('OTHER_LORUM')); 67 | $this->assertTrue($enum::has('other_lorum')); 68 | $this->assertTrue($enum::has('Other_LoRum')); 69 | 70 | // camelCase method 71 | $this->assertTrue($enum::has('otherLorum')); 72 | $this->assertTrue($enum::has('OtherLorum')); 73 | 74 | // Method names are case insensitive 75 | $this->assertTrue($enum::has('LorUM')); 76 | $this->assertTrue($enum::has('OtHErLOrum')); 77 | } 78 | 79 | /** 80 | * Test if enum does not have a member by name. 81 | */ 82 | public function testHasByInvalidName() 83 | { 84 | $enum = new class() extends Fixtures\AbstractTestEnum { 85 | private $foo = 'foo'; 86 | private $otherFoo = 'other foo'; 87 | 88 | private const BAR = 'bar'; 89 | private const OTHER_BAR = 'other bar'; 90 | }; 91 | 92 | // Completely missing. 93 | $this->assertFalse($enum::has('bleep')); 94 | 95 | // Internal properties, not allowed 96 | $this->assertFalse($enum::has('_name')); 97 | $this->assertFalse($enum::has('_NAME')); 98 | $this->assertFalse($enum::has('_value')); 99 | $this->assertFalse($enum::has('_VALUE')); 100 | $this->assertFalse($enum::has('_instances')); 101 | $this->assertFalse($enum::has('_INSTANCES')); 102 | 103 | // Would be interpreted as camelCase and normalize to e.g. FO_O, which is missing. 104 | $this->assertFalse($enum::has('FoO')); 105 | $this->assertFalse($enum::has('OtHerFoO')); 106 | $this->assertFalse($enum::has('BaR')); 107 | $this->assertFalse($enum::has('OtHErBar')); 108 | } 109 | 110 | /** 111 | * Test if enum has a member by instance. 112 | */ 113 | public function testHasByInstance() 114 | { 115 | $enum = new class() extends Fixtures\AbstractTestEnum { 116 | private $foo = 'foo'; 117 | private $otherFoo = 'other foo'; 118 | 119 | private const BAR = 'bar'; 120 | private const OTHER_BAR = 'other bar'; 121 | 122 | private function lorum() 123 | { 124 | return 'lorum'; 125 | } 126 | 127 | private function otherLorum() 128 | { 129 | return 'other lorum'; 130 | } 131 | }; 132 | 133 | $this->assertTrue($enum::has($enum::FOO())); 134 | $this->assertTrue($enum::has($enum::OTHER_FOO())); 135 | $this->assertTrue($enum::has($enum::BAR())); 136 | $this->assertTrue($enum::has($enum::OTHER_BAR())); 137 | $this->assertTrue($enum::has($enum::LORUM())); 138 | $this->assertTrue($enum::has($enum::OTHER_LORUM())); 139 | } 140 | 141 | /** 142 | * Test if enum does not has a member by instance. 143 | */ 144 | public function testHasByInvalidInstance() 145 | { 146 | $enum = new class() extends Fixtures\AbstractTestEnum { 147 | private $foo = 'foo'; 148 | }; 149 | 150 | $otherEnum = new class() extends Fixtures\AbstractTestEnum { 151 | private $foo = 'foo'; 152 | }; 153 | 154 | $this->assertFalse($enum::has($otherEnum::FOO())); 155 | } 156 | 157 | /** 158 | * Test getting an invalid member when calling static. 159 | */ 160 | public function testNonExistingMemberStatic() 161 | { 162 | $this->expectException(\BadMethodCallException::class); 163 | $this->expectExceptionMessage('BAR is not an enum member of'); 164 | 165 | $enum = new class() extends Fixtures\AbstractTestEnum { 166 | private $foo = 'foo'; 167 | }; 168 | 169 | $enum::BAR(); 170 | } 171 | 172 | /** 173 | * Test getting an invalid member when calling static. 174 | */ 175 | public function testInvalidMemberStatic() 176 | { 177 | $this->expectException(\BadMethodCallException::class); 178 | $this->expectExceptionMessage('_NAME is not an enum member of'); 179 | 180 | $enum = new class() extends Fixtures\AbstractTestEnum { 181 | private $foo = 'foo'; 182 | }; 183 | 184 | $enum::_NAME(); 185 | } 186 | 187 | /** 188 | * Test getting an invalid member when calling with get(). 189 | */ 190 | public function testNonExistingMemberByGetter() 191 | { 192 | $this->expectException(\UnexpectedValueException::class); 193 | $this->expectExceptionMessage('BAR is not an enum member of'); 194 | 195 | $enum = new class() extends Fixtures\AbstractTestEnum { 196 | private $foo = 'foo'; 197 | }; 198 | 199 | $enum::get('BAR'); 200 | } 201 | 202 | /** 203 | * Test getting an invalid member when calling with get(). 204 | */ 205 | public function testInvalidMemberByGetter() 206 | { 207 | $this->expectException(\UnexpectedValueException::class); 208 | $this->expectExceptionMessage('_NAME is not an enum member of'); 209 | 210 | $enum = new class() extends Fixtures\AbstractTestEnum { 211 | private $foo = 'foo'; 212 | }; 213 | 214 | $enum::get('_NAME'); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /tests/Fixtures/AbstractTestEnum.php: -------------------------------------------------------------------------------- 1 | assertTrue($enum::has('FOO')); 22 | 23 | // Inherited member by own instance 24 | $this->assertTrue($enum::has($enum::FOO())); 25 | 26 | // Inherited member by parent instance 27 | $this->assertFalse($enum::has(Fixtures\FooEnum::FOO())); 28 | } 29 | 30 | /** 31 | * Test inherited member from different instance is not the same. 32 | */ 33 | public function testInheritedMemberDifferentInstanceNotSame() 34 | { 35 | $enum = new class() extends Fixtures\FooEnum { 36 | private $bar = 'bar'; 37 | }; 38 | 39 | $this->assertInstanceOf(get_class($enum), $enum::FOO()); 40 | 41 | // Inherited member, different instances 42 | $this->assertNotSame($enum::FOO(), Fixtures\FooEnum::FOO()); 43 | $this->assertNotSame($enum::get('FOO'), Fixtures\FooEnum::FOO()); 44 | } 45 | 46 | /** 47 | * Test getter on base class with inherited instance throwing exception. 48 | * 49 | * This makes sure that even though the inherited enum is an instance of the base enum, proper validation is done 50 | * in the getter so the member of the inherited enum is not mistaken for a member of the base class. 51 | */ 52 | public function testGetterByInheritedInstanceNotSame() 53 | { 54 | $this->expectException(\UnexpectedValueException::class); 55 | 56 | $fooEnum = new Fixtures\FooEnum(); 57 | 58 | $barEnum = new class() extends Fixtures\FooEnum { 59 | private $bar = 'bar'; 60 | }; 61 | 62 | $this->assertNotSame($fooEnum::get($barEnum::BAR()), $barEnum::BAR()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/MiscTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('foo', $enum::STRING_VALUE()->getValue()); 29 | $this->assertEquals(true, $enum::BOOL_VALUE()->getValue()); 30 | $this->assertEquals(3, $enum::INT_VALUE()->getValue()); 31 | $this->assertEquals(['apple', 'pie'], $enum::ARRAY_VALUE()->getValue()); 32 | 33 | $this->assertEquals('bar', $enum::VALUE_STRING()->getValue()); 34 | $this->assertEquals(false, $enum::VALUE_BOOL()->getValue()); 35 | $this->assertEquals(10, $enum::VALUE_INT()->getValue()); 36 | $this->assertEquals(['foo', 'bar'], $enum::VALUE_ARRAY()->getValue()); 37 | } 38 | 39 | /** 40 | * Test toString value. 41 | */ 42 | public function testToStringValue() 43 | { 44 | $enum = new class() extends Fixtures\AbstractTestEnum { 45 | private $foo = 'foo'; 46 | private $otherFoo = 'other foo'; 47 | 48 | private const BAR = 'bar'; 49 | private const OTHER_BAR = 'other bar'; 50 | 51 | private const LORUM = 'lorum const'; 52 | private $lorum = 'lorum prop'; 53 | }; 54 | 55 | $this->assertEquals('foo', (string) $enum::FOO()); 56 | $this->assertEquals('other foo', (string) $enum::OTHER_FOO()); 57 | 58 | $this->assertEquals('bar', (string) $enum::BAR()); 59 | $this->assertEquals('other bar', (string) $enum::OTHER_BAR()); 60 | 61 | $this->assertEquals('lorum const', (string) $enum::LORUM()); 62 | } 63 | 64 | /** 65 | * Make sure that cloning is not allowed. 66 | */ 67 | public function testClone() 68 | { 69 | $this->expectException(\LogicException::class); 70 | 71 | $enum = new class() extends Fixtures\AbstractTestEnum { 72 | private $foo = 'foo'; 73 | }; 74 | 75 | $foo = clone $enum; 76 | } 77 | 78 | /** 79 | * Test member method called once. 80 | * 81 | * Make sure that member methods are only called once to retreive their value. Any subsequent call to get the value 82 | * should lead to the same result. 83 | */ 84 | public function testMemberMethodCalledOnce() 85 | { 86 | $enum = new class() extends Fixtures\AbstractTestEnum { 87 | private function foo() 88 | { 89 | return bin2hex(random_bytes(4)); 90 | } 91 | }; 92 | 93 | $value = $enum::FOO()->getValue(); 94 | 95 | $this->assertEquals($enum::FOO()->getValue(), $value); 96 | $this->assertEquals($enum::FOO()->getValue(), $enum::FOO()->getValue()); 97 | $this->assertEquals((string) $enum::FOO(), $enum::FOO()->getValue()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /tests/NameTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('FOO', $enum::FOO()->getName()); 35 | $this->assertEquals('FOO', $enum::foo()->getName()); 36 | $this->assertEquals('OTHER_FOO', $enum::OTHER_FOO()->getName()); 37 | $this->assertEquals('OTHER_FOO', $enum::other_foo()->getName()); 38 | $this->assertEquals('OTHER_FOO', $enum::Other_FoO()->getName()); 39 | $this->assertEquals('OTHER_FOO', $enum::otherFoo()->getName()); 40 | $this->assertEquals('OTHER_FOO', $enum::OtherFoo()->getName()); 41 | 42 | $this->assertEquals('BAR', $enum::BAR()->getName()); 43 | $this->assertEquals('BAR', $enum::bar()->getName()); 44 | $this->assertEquals('OTHER_BAR', $enum::OTHER_BAR()->getName()); 45 | $this->assertEquals('OTHER_BAR', $enum::other_bar()->getName()); 46 | $this->assertEquals('OTHER_BAR', $enum::Other_BaR()->getName()); 47 | $this->assertEquals('OTHER_BAR', $enum::otherBar()->getName()); 48 | $this->assertEquals('OTHER_BAR', $enum::OtherBar()->getName()); 49 | 50 | $this->assertEquals('LORUM', $enum::LORUM()->getName()); 51 | $this->assertEquals('LORUM', $enum::lorum()->getName()); 52 | $this->assertEquals('OTHER_LORUM', $enum::OTHER_LORUM()->getName()); 53 | $this->assertEquals('OTHER_LORUM', $enum::OthER_LoRUm()->getName()); 54 | $this->assertEquals('OTHER_LORUM', $enum::other_lorum()->getName()); 55 | $this->assertEquals('OTHER_LORUM', $enum::otherLorum()->getName()); 56 | $this->assertEquals('OTHER_LORUM', $enum::OtherLorum()->getName()); 57 | } 58 | 59 | /** 60 | * Test name when calling with get(). 61 | */ 62 | public function testNameWithGetter() 63 | { 64 | $enum = new class() extends Fixtures\AbstractTestEnum { 65 | private $foo = 'foo'; 66 | private $otherFoo = 'other foo'; 67 | 68 | private const BAR = 'bar'; 69 | private const OTHER_BAR = 'other bar'; 70 | 71 | private function lorum() 72 | { 73 | return 'lorum'; 74 | } 75 | 76 | private function otherLorum() 77 | { 78 | return 'other lorum'; 79 | } 80 | }; 81 | 82 | $this->assertEquals('FOO', $enum::get('FOO')->getName()); 83 | $this->assertEquals('FOO', $enum::get('foo')->getName()); 84 | $this->assertEquals('OTHER_FOO', $enum::get('OTHER_FOO')->getName()); 85 | $this->assertEquals('OTHER_FOO', $enum::get('other_foo')->getName()); 86 | $this->assertEquals('OTHER_FOO', $enum::get('Other_FoO')->getName()); 87 | $this->assertEquals('OTHER_FOO', $enum::get('otherFoo')->getName()); 88 | $this->assertEquals('OTHER_FOO', $enum::get('OtherFoo')->getName()); 89 | 90 | $this->assertEquals('BAR', $enum::get('BAR')->getName()); 91 | $this->assertEquals('BAR', $enum::get('bar')->getName()); 92 | $this->assertEquals('OTHER_BAR', $enum::get('OTHER_BAR')->getName()); 93 | $this->assertEquals('OTHER_BAR', $enum::get('other_bar')->getName()); 94 | $this->assertEquals('OTHER_BAR', $enum::get('Other_BaR')->getName()); 95 | $this->assertEquals('OTHER_BAR', $enum::get('otherBar')->getName()); 96 | $this->assertEquals('OTHER_BAR', $enum::get('OtherBar')->getName()); 97 | 98 | $this->assertEquals('LORUM', $enum::get('LORUM')->getName()); 99 | $this->assertEquals('LORUM', $enum::get('lorum')->getName()); 100 | $this->assertEquals('OTHER_LORUM', $enum::get('OTHER_LORUM')->getName()); 101 | $this->assertEquals('OTHER_LORUM', $enum::get('OthER_LoRUm')->getName()); 102 | $this->assertEquals('OTHER_LORUM', $enum::get('other_lorum')->getName()); 103 | $this->assertEquals('OTHER_LORUM', $enum::get('otherLorum')->getName()); 104 | $this->assertEquals('OTHER_LORUM', $enum::get('OtherLorum')->getName()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tests/ResolveTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('foo const', $enum::FOO()->getValue()); 29 | $this->assertEquals('foo const', (string) $enum::FOO()); 30 | $this->assertSame($enum::FOO(), $enum::FOO()); 31 | $this->assertSame($enum::FOO(), $enum::get('FOO')); 32 | } 33 | 34 | /** 35 | * Test resolve property before method. 36 | * 37 | * Make sure that properties are resolved before methods. 38 | */ 39 | public function testResolvePropertyBeforeMethod() 40 | { 41 | $enum = new class() extends Fixtures\AbstractTestEnum { 42 | private $foo = 'foo prop'; 43 | 44 | private function foo() 45 | { 46 | return 'foo method'; 47 | } 48 | }; 49 | 50 | $this->assertEquals('foo prop', $enum::FOO()->getValue()); 51 | $this->assertEquals('foo prop', (string) $enum::FOO()); 52 | $this->assertSame($enum::FOO(), $enum::FOO()); 53 | $this->assertSame($enum::FOO(), $enum::get('FOO')); 54 | } 55 | 56 | /** 57 | * Test resolve methods last. 58 | * 59 | * Make sure that methods are resolved last. 60 | */ 61 | public function testResolveMethodsLast() 62 | { 63 | $enum = new class() extends Fixtures\AbstractTestEnum { 64 | private function foo() 65 | { 66 | return 'foo method'; 67 | } 68 | }; 69 | 70 | $this->assertEquals('foo method', $enum::FOO()->getValue()); 71 | $this->assertEquals('foo method', (string) $enum::FOO()); 72 | $this->assertSame($enum::FOO(), $enum::FOO()); 73 | $this->assertSame($enum::FOO(), $enum::get('FOO')); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/SerializeTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('"foo"', json_encode($enum::FOO())); 32 | $this->assertEquals('"other foo"', json_encode($enum::OTHER_FOO())); 33 | 34 | $this->assertEquals('"bar"', json_encode($enum::BAR())); 35 | $this->assertEquals('"other bar"', json_encode($enum::OTHER_BAR())); 36 | 37 | $this->assertEquals('"lorum const"', json_encode($enum::LORUM())); 38 | 39 | $this->assertEquals('false', json_encode($enum::VALUE_BOOL())); 40 | $this->assertEquals('3', json_encode($enum::VALUE_INT())); 41 | $this->assertEquals('["foo"]', json_encode($enum::VALUE_ARRAY())); 42 | } 43 | 44 | /** 45 | * Make sure that serialization is not allowed. 46 | */ 47 | public function testSerialize() 48 | { 49 | $this->expectException(\Exception::class); 50 | 51 | $enum = new class() extends Fixtures\AbstractTestEnum { 52 | private $foo = 'foo'; 53 | }; 54 | 55 | serialize($enum); 56 | } 57 | 58 | /** 59 | * Make sure that serialization is not allowed. 60 | */ 61 | public function testSleep() 62 | { 63 | $this->expectException(\LogicException::class); 64 | 65 | $enum = new class() extends Fixtures\AbstractTestEnum { 66 | private $foo = 'foo'; 67 | }; 68 | 69 | $enum->__sleep(); 70 | } 71 | 72 | /** 73 | * Make sure that serialization is not allowed. 74 | */ 75 | public function testWakeup() 76 | { 77 | $this->expectException(\LogicException::class); 78 | 79 | $enum = new class() extends Fixtures\AbstractTestEnum { 80 | private $foo = 'foo'; 81 | }; 82 | 83 | $enum->__wakeup(); 84 | } 85 | } 86 | --------------------------------------------------------------------------------