├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── extension.neon └── src └── Reflection └── ObjectProphecy ├── MethodReflection.php └── MethodsClassReflectionExtension.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## Unreleased 8 | 9 | For a full diff see [`1.0.0...main`][1.0.0...master]. 10 | 11 | ## [`1.0.0`][1.0.0] 12 | 13 | For a full diff see [`0.8.1...1.0.0`][0.8.1...1.0.0]. 14 | 15 | ### Changed 16 | 17 | - Added support for `phpstan/phpstan:^1.0.0` and dropped support for non-stable versions of `phpstan/phpstan` ([#266]), by [@alexander-schranz] 18 | 19 | ## [`0.8.1`][0.8.1] 20 | 21 | For a full diff see [`0.8.0...0.8.1`][0.8.0...0.8.1]. 22 | 23 | ### Changed 24 | 25 | - Allowed installation with PHP 8.0 ([#236]), by [@localheinz] 26 | 27 | ## [`0.8.0`][0.8.0] 28 | 29 | For a full diff see [`0.7.0...0.8.0`][0.7.0...0.8.0]. 30 | 31 | ### Removed 32 | 33 | - Removed the symbolic link from `src/extension.neon` to `extension.neon` ([#182]), by [@localheinz] 34 | 35 | When using [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer), no changes on your end are required. 36 | 37 | When not using [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer), you need to adjust `phpstan.neon`: 38 | 39 | ```diff 40 | includes: 41 | - - vendor/jangregor/phpstan-prophecy/src/extension.neon 42 | + - vendor/jangregor/phpstan-prophecy/extension.neon 43 | ``` 44 | 45 | ## [`0.7.0`][0.7.0] 46 | 47 | For a full diff see [`0.6.2...0.7.0`][0.6.2...0.7.0]. 48 | 49 | ### Changed 50 | 51 | - Moved `src/extension.neon` to `extension.neon` ([#140]), by [@localheinz] 52 | - Marked classes as `@internal` ([#144]), by [@localheinz] 53 | - Moved and renamed internal classes ([#153]), by [@localheinz] 54 | - Required `phpstan/phpstan:~0.12.6` ([#165]), by [@Jean85] 55 | - Simplified extension by making use of generics ([#165]), by [@Jean85] and [@ondrejmirtes] 56 | 57 | ## [`0.6.2`][0.6.2] 58 | 59 | For a full diff see [`0.6.1...0.6.2`][0.6.1...0.6.2]. 60 | 61 | ### Fixed 62 | 63 | - Allowed installation with `phpunit/phpunit:^9` ([#124]), by [@localheinz] 64 | 65 | ## [`0.6.1`][0.6.1] 66 | 67 | For a full diff see [`0.6.0...0.6.1`][0.6.0...0.6.1]. 68 | 69 | ### Changed 70 | 71 | - Marked classes as `final` ([#118]), by [@localheinz] 72 | - Modified return value of `ObjectPropecyMethodReflection::hasSideEffects()` as invoking methods on an instance of `Prophecy\Prophecy\ObjectProphecy` might have side effects ([#119]), by [@localheinz] 73 | 74 | ## [`0.6.0`][0.6.0] 75 | 76 | For a full diff see [`0.5.1...0.6.0`][0.5.1...0.6.0]. 77 | 78 | ### Added 79 | 80 | - Support for `willImplement()` ([#92]), by [@localheinz] 81 | - Support for `willExtend()` ([#94]), by [@localheinz] 82 | 83 | ## [`0.5.1`][0.5.1] 84 | 85 | For a full diff see [`0.5.0...0.5.1`][0.5.0...0.5.1]. 86 | 87 | ### Changed 88 | 89 | - Required at least `phpstan/phpstan:^0.12.0` ([#79]), by [@localheinz] 90 | 91 | ## [`0.5.0`][0.5.0] 92 | 93 | For a full diff see [`0.4.2...0.5.0`][0.4.2...0.5.0]. 94 | 95 | ### Added 96 | 97 | - Allowed installation with `phpstan/phpstan:~0.12.2` ([#67]), by [@localheinz] and [@PedroTroller] 98 | 99 | ## [`0.4.2`][0.4.2] 100 | 101 | For a full diff see [`0.4.1...0.4.2`][0.4.1...0.4.2]. 102 | 103 | ## [`0.4.1`][0.4.1] 104 | 105 | For a full diff see [`0.4...0.4.1`][0.4...0.4.1]. 106 | 107 | ## [`0.4`][0.4] 108 | 109 | For a full diff see [`0.3.0...0.4`][0.3.0...0.4]. 110 | 111 | ## [`0.3.0`][0.3.0] 112 | 113 | For a full diff see [`0.2.0...0.3.0`][0.2.0...0.3.0]. 114 | 115 | ## [`0.2.0`][0.2.0] 116 | 117 | For a full diff see [`0.1.2...0.2.0`][0.1.2...0.2.0]. 118 | 119 | ## [`0.1.2`][0.1.2] 120 | 121 | For a full diff see [`0.1.1...0.1.2`][0.1.1...0.1.2]. 122 | 123 | ## [`0.1.1`][0.1.1] 124 | 125 | For a full diff see [`0.1...0.1.1`][0.1...0.1.1]. 126 | 127 | ## [`0.1`][0.1] 128 | 129 | For a full diff see [`afd6fd9...0.1`][afd6fd9...0.1]. 130 | 131 | [0.1]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.1 132 | [0.1.1]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.1.1 133 | [0.1.2]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.1.2 134 | [0.2.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.2.0 135 | [0.3.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.3.0 136 | [0.4]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.4 137 | [0.4.1]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.4.1 138 | [0.4.2]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.4.2 139 | [0.5.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.5.0 140 | [0.5.1]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.5.1 141 | [0.6.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.6.0 142 | [0.6.1]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.6.1 143 | [0.6.2]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.6.2 144 | [0.7.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.7.0 145 | [0.8.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.8.0 146 | [0.8.1]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/0.8.1 147 | [1.0.0]: https://github.com/Jan0707/phpstan-prophecy/releases/tag/1.0.0 148 | 149 | [afd6fd9...0.1]: https://github.com/Jan0707/phpstan-prophecy/compare/afd6fd9...0.1 150 | [0.1...0.1.1]: https://github.com/Jan0707/phpstan-prophecy/compare/0.1...0.1.1 151 | [0.1.1...0.1.2]: https://github.com/Jan0707/phpstan-prophecy/compare/0.1.1...0.1.2 152 | [0.1.2...0.2.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.1.2...0.2.0 153 | [0.2.0...0.3.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.2.0...0.3.0 154 | [0.3.0...0.4]: https://github.com/Jan0707/phpstan-prophecy/compare/0.3.0...0.4 155 | [0.4...0.4.1]: https://github.com/Jan0707/phpstan-prophecy/compare/0.4...0.4.1 156 | [0.4.1...0.4.2]: https://github.com/Jan0707/phpstan-prophecy/compare/0.4.1...0.4.2 157 | [0.4.2...0.5.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.4.2...0.5.0 158 | [0.5.0...0.5.1]: https://github.com/Jan0707/phpstan-prophecy/compare/0.5.0...0.5.1 159 | [0.5.1...0.6.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.5.1...0.6.0 160 | [0.6.0...0.6.1]: https://github.com/Jan0707/phpstan-prophecy/compare/0.6.0...0.6.1 161 | [0.6.1...0.6.2]: https://github.com/Jan0707/phpstan-prophecy/compare/0.6.1...0.6.2 162 | [0.6.2...0.7.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.6.2...0.7.0 163 | [0.7.0...0.8.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.7.0...0.8.0 164 | [0.8.0...0.8.1]: https://github.com/Jan0707/phpstan-prophecy/compare/0.8.0...0.8.1 165 | [0.8.1...1.0.0]: https://github.com/Jan0707/phpstan-prophecy/compare/0.8.1...1.0.0 166 | [1.0.0...master]: https://github.com/Jan0707/phpstan-prophecy/compare/1.0.0...master 167 | 168 | [#67]: https://github.com/Jan0707/phpstan-prophecy/pull/67 169 | [#79]: https://github.com/Jan0707/phpstan-prophecy/pull/79 170 | [#92]: https://github.com/Jan0707/phpstan-prophecy/pull/92 171 | [#94]: https://github.com/Jan0707/phpstan-prophecy/pull/94 172 | [#118]: https://github.com/Jan0707/phpstan-prophecy/pull/118 173 | [#119]: https://github.com/Jan0707/phpstan-prophecy/pull/119 174 | [#124]: https://github.com/Jan0707/phpstan-prophecy/pull/124 175 | [#140]: https://github.com/Jan0707/phpstan-prophecy/pull/140 176 | [#144]: https://github.com/Jan0707/phpstan-prophecy/pull/144 177 | [#153]: https://github.com/Jan0707/phpstan-prophecy/pull/153 178 | [#165]: https://github.com/Jan0707/phpstan-prophecy/pull/165 179 | [#182]: https://github.com/Jan0707/phpstan-prophecy/pull/182 180 | [#236]: https://github.com/Jan0707/phpstan-prophecy/pull/236 181 | [#266]: https://github.com/Jan0707/phpstan-prophecy/pull/266 182 | 183 | [@alexander-schranz]: https://github.com/alexander-schranz 184 | [@Jean85]: https://github.com/Jean85 185 | [@localheinz]: https://github.com/localheinz 186 | [@ondrejmirtes ]: https://github.com/ondrejmirtes 187 | [@PedroTroller]: https://github.com/PedroTroller 188 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Jan Gregor Emge-Triebel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 11 | Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 14 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 15 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 16 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # phpstan-prophecy 2 | 3 | [![Close](https://github.com/Jan0707/phpstan-prophecy/workflows/Close/badge.svg)](https://github.com/Jan0707/phpstan-prophecy/actions) 4 | [![Integrate](https://github.com/Jan0707/phpstan-prophecy/workflows/Integrate/badge.svg)](https://github.com/Jan0707/phpstan-prophecy/actions) 5 | [![Merge](https://github.com/Jan0707/phpstan-prophecy/workflows/Merge/badge.svg)](https://github.com/Jan0707/phpstan-prophecy/actions) 6 | [![Triage](https://github.com/Jan0707/phpstan-prophecy/workflows/Triage/badge.svg)](https://github.com/Jan0707/phpstan-prophecy/actions) 7 | 8 | [![Latest Stable Version](https://poser.pugx.org/jangregor/phpstan-prophecy/v/stable)](https://packagist.org/packages/jangregor/phpstan-prophecy) 9 | [![Total Downloads](https://poser.pugx.org/jangregor/phpstan-prophecy/downloads)](https://packagist.org/packages/jangregor/phpstan-prophecy) 10 | 11 | [![Violinist Enabled](https://img.shields.io/badge/violinist-enabled-brightgreen.svg)](https://violinist.io) 12 | 13 | Provides a [`phpspec/prophecy`](https://github.com/phpspec/prophecy) extension for [`phpstan/phpstan`](https://github.com/phpstan/phpstan). 14 | 15 | ## Installation 16 | 17 | Run 18 | 19 | ```shell 20 | composer require --dev jangregor/phpstan-prophecy 21 | ``` 22 | 23 | ## Configuration 24 | 25 | ### Automatic 26 | 27 | When using [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer), no further setup is required. 28 | 29 | ### Manual 30 | 31 | When not using [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer), [`extension.neon`](extension.neon) needs to be included in `phpstan.neon`: 32 | 33 | ```diff 34 | includes: 35 | + - vendor/jangregor/phpstan-prophecy/extension.neon 36 | ``` 37 | 38 | ## Usage 39 | 40 | ### `prophesize()` and `reveal()` 41 | 42 | ```php 43 | prophesize(SomeModel::class); 52 | 53 | $testDouble = $prophecy->reveal(); 54 | 55 | // ... 56 | } 57 | } 58 | ``` 59 | 60 | :bulb: With this extension enabled, `phpstan/phpstan` will understand that `$testDouble` is an instance of `SomeModel`. 61 | 62 | ### `prophesize()`, `willExtend()`, and `reveal()` 63 | 64 | ```php 65 | prophesize()->willExtend(SomeModel::class); 74 | 75 | $testDouble = $prophecy->reveal(); 76 | 77 | // ... 78 | } 79 | } 80 | ``` 81 | 82 | :bulb: With this extension enabled, `phpstan/phpstan` will understand that `$testDouble` is an instance of `SomeModel`. 83 | 84 | ### `prophesize()`, `willImplement()`, and `reveal()` 85 | 86 | ```php 87 | prophesize(SomeModel::class)->willImplement(SomeInterface::class); 96 | 97 | $testDouble = $prophecy->reveal(); 98 | 99 | // ... 100 | } 101 | } 102 | ``` 103 | 104 | :bulb: With this extension enabled, `phpstan/phpstan` will understand that `$testDouble` is an instance of `SomeModel` that also implements `SomeInterface`. 105 | 106 | ### Method Predictions 107 | 108 | ```php 109 | prophesize(SomeModel::class); 118 | 119 | $prophecy 120 | ->doubleTheNumber(Argument::is(2)) 121 | ->willReturn(4); 122 | 123 | $testDouble = $prophecy->reveal(); 124 | 125 | // ... 126 | } 127 | } 128 | ``` 129 | 130 | :bulb: With this extension enabled, `phpstan/phpstan` will understand that `$prophecy` accepts method calls to all methods that are implemented by its prophesized class (or additionally implemented interfaces, when using `willImplement()`). 131 | 132 | ### Method Arguments 133 | 134 | :exclamation: Currently here are no checks in place to validate the arguments of methods that are invoked on prophecies. 135 | 136 | ## Development 137 | 138 | A development environment is provided via [`.docker/Dockerfile`](.docker/Dockerfile). 139 | 140 | Run 141 | 142 | ```shell 143 | $ docker build --tag phpstan-prophecy .docker/ 144 | ``` 145 | 146 | to build and tag the Docker image. 147 | 148 | Run 149 | 150 | ```shell 151 | $ docker run -it --rm --volume "$PWD":/var/www/html --workdir /var/www/html phpstan-prophecy bash 152 | ``` 153 | 154 | to open a shell in the Docker container. 155 | 156 | ## Changelog 157 | 158 | Please have a look at [`CHANGELOG.md`](CHANGELOG.md). 159 | 160 | ## Contributing 161 | 162 | Please have a look at [`CONTRIBUTING.md`](.github/CONTRIBUTING.md). 163 | 164 | ## License 165 | 166 | This package is licensed using the MIT License. 167 | 168 | Please have a look at [`LICENSE.md`](LICENSE.md). 169 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jangregor/phpstan-prophecy", 3 | "description": "Provides a phpstan/phpstan extension for phpspec/prophecy", 4 | "license": "MIT", 5 | "type": "phpstan-extension", 6 | "authors": [ 7 | { 8 | "name": "Jan Gregor Emge-Triebel", 9 | "email": "jan@jangregor.me" 10 | } 11 | ], 12 | "require": { 13 | "php": "^7.4 || ^8.0", 14 | "phpstan/phpstan": "^2.1.5" 15 | }, 16 | "require-dev": { 17 | "ergebnis/composer-normalize": "^2.47.0", 18 | "ergebnis/license": "^2.6.0", 19 | "ergebnis/php-cs-fixer-config": "^6.46.0", 20 | "phpspec/prophecy": "^1.7.0", 21 | "phpspec/prophecy-phpunit": "^2.3", 22 | "phpunit/phpunit": "^9.1.0" 23 | }, 24 | "conflict": { 25 | "phpspec/prophecy": "<1.17.0 || >=2.0.0", 26 | "phpspec/prophecy-phpunit": "<2.3.0 || >=3.0.0", 27 | "phpunit/phpunit": "<9.1.0 || >=13.0.0" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "JanGregor\\Prophecy\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "JanGregor\\Prophecy\\Test\\": "test/" 37 | } 38 | }, 39 | "config": { 40 | "allow-plugins": { 41 | "ergebnis/composer-normalize": true 42 | }, 43 | "sort-packages": true 44 | }, 45 | "extra": { 46 | "phpstan": { 47 | "includes": [ 48 | "extension.neon" 49 | ] 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /extension.neon: -------------------------------------------------------------------------------- 1 | services: 2 | - 3 | class: JanGregor\Prophecy\Reflection\ObjectProphecy\MethodsClassReflectionExtension 4 | tags: 5 | - phpstan.broker.methodsClassReflectionExtension 6 | -------------------------------------------------------------------------------- /src/Reflection/ObjectProphecy/MethodReflection.php: -------------------------------------------------------------------------------- 1 | declaringClass = $declaringClass; 32 | $this->name = $name; 33 | } 34 | 35 | public function getDeclaringClass(): Reflection\ClassReflection 36 | { 37 | return $this->declaringClass; 38 | } 39 | 40 | public function isStatic(): bool 41 | { 42 | return false; 43 | } 44 | 45 | public function isPrivate(): bool 46 | { 47 | return false; 48 | } 49 | 50 | public function isPublic(): bool 51 | { 52 | return true; 53 | } 54 | 55 | public function getName(): string 56 | { 57 | return $this->name; 58 | } 59 | 60 | public function getVariants(): array 61 | { 62 | return [ 63 | new Reflection\FunctionVariant( 64 | Type\Generic\TemplateTypeMap::createEmpty(), 65 | null, 66 | [], 67 | true, 68 | new Type\ObjectType(Prophecy\MethodProphecy::class), 69 | ), 70 | ]; 71 | } 72 | 73 | public function getPrototype(): Reflection\ClassMemberReflection 74 | { 75 | return $this; 76 | } 77 | 78 | public function isDeprecated(): TrinaryLogic 79 | { 80 | return TrinaryLogic::createNo(); 81 | } 82 | 83 | public function getDeprecatedDescription(): ?string 84 | { 85 | return null; 86 | } 87 | 88 | public function isFinal(): TrinaryLogic 89 | { 90 | return TrinaryLogic::createYes(); 91 | } 92 | 93 | public function isInternal(): TrinaryLogic 94 | { 95 | return TrinaryLogic::createNo(); 96 | } 97 | 98 | public function getThrowType(): ?Type\Type 99 | { 100 | return null; 101 | } 102 | 103 | public function hasSideEffects(): TrinaryLogic 104 | { 105 | return TrinaryLogic::createMaybe(); 106 | } 107 | 108 | public function getDocComment(): ?string 109 | { 110 | return null; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Reflection/ObjectProphecy/MethodsClassReflectionExtension.php: -------------------------------------------------------------------------------- 1 | getName(); 28 | } 29 | 30 | public function getMethod(Reflection\ClassReflection $classReflection, string $methodName): Reflection\MethodReflection 31 | { 32 | return new MethodReflection($classReflection, $methodName); 33 | } 34 | } 35 | --------------------------------------------------------------------------------