Skip to content

Commit

Permalink
Merge pull request #138 from Ocramius/feature/#134-mark-__callStatic-…
Browse files Browse the repository at this point in the history
…as-pure

Fix #134 by marking `Enum::__callStatic` as `@psalm-pure`
  • Loading branch information
mnapoli authored Feb 15, 2021
2 parents be0c9d5 + db6a2a8 commit 46cf3d8
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
.travis.yml export-ignore
tests/ export-ignore
phpunit.xml export-ignore
static-analysis/ export-ignore
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
language: php

php:
- '7.1'
- '7.2'
- '7.3'
- '7.4'
- '8.0'

matrix:
fast_finish: true
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
}
},
"require": {
"php": ">=7.1",
"php": "^7.3 || ^8.0",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "^7",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "1.*",
"vimeo/psalm": "^3.8"
"vimeo/psalm": "^4.5.1"
}
}
19 changes: 6 additions & 13 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
phpunit -c phpunit.xml
-->
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./tests/bootstrap.php">
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
bootstrap="./tests/bootstrap.php"
>
<testsuites>
<testsuite name="PHP Enum Test Suite">
<directory suffix=".php">./tests</directory>
Expand Down
15 changes: 15 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
>
<projectFiles>
<directory name="src" />
<directory name="static-analysis" />
<ignoreFiles>
<directory name="vendor" />
<directory name="src/PHPUnit" />
Expand All @@ -16,5 +17,19 @@

<issueHandlers>
<MixedAssignment errorLevel="info" />

<ImpureStaticProperty>
<!-- self::$... usages in Enum are used to populate an internal cache, and cause no side-effects -->
<errorLevel type="suppress">
<file name="src/Enum.php"/>
</errorLevel>
</ImpureStaticProperty>

<ImpureVariable>
<!-- $this usages in Enum point themselves to an immutable instance -->
<errorLevel type="suppress">
<file name="src/Enum.php"/>
</errorLevel>
</ImpureVariable>
</issueHandlers>
</psalm>
7 changes: 6 additions & 1 deletion src/Enum.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*
* @psalm-template T
* @psalm-immutable
* @psalm-consistent-constructor
*/
abstract class Enum implements \JsonSerializable
{
Expand Down Expand Up @@ -58,7 +59,7 @@ abstract class Enum implements \JsonSerializable
* @psalm-pure
* @param mixed $value
*
* @psalm-param static<T>|T $value
* @psalm-param T $value
* @throws \UnexpectedValueException if incompatible type is given.
*/
public function __construct($value)
Expand Down Expand Up @@ -186,7 +187,9 @@ public static function toArray()
$class = static::class;

if (!isset(static::$cache[$class])) {
/** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */
$reflection = new \ReflectionClass($class);
/** @psalm-suppress ImpureMethodCall this reflection API usage has no side-effects here */
static::$cache[$class] = $reflection->getConstants();
}

Expand Down Expand Up @@ -270,6 +273,8 @@ public static function search($value)
*
* @return static
* @throws \BadMethodCallException
*
* @psalm-pure
*/
public static function __callStatic($name, $arguments)
{
Expand Down
33 changes: 33 additions & 0 deletions static-analysis/EnumIsPure.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace MyCLabs\Tests\Enum\StaticAnalysis;

use MyCLabs\Enum\Enum;

/**
* @method static PureEnum A()
* @method static PureEnum C()
*
* @psalm-immutable
* @psalm-template T of 'A'|'B'
* @template-extends Enum<T>
*/
final class PureEnum extends Enum
{
const A = 'A';
const C = 'C';
}

/** @psalm-pure */
function enumFetchViaMagicMethodIsPure(): PureEnum
{
return PureEnum::A();
}

/** @psalm-pure */
function enumFetchViaExplicitMagicCallIsPure(): PureEnum
{
return PureEnum::__callStatic('A', []);
}
17 changes: 7 additions & 10 deletions tests/EnumTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,12 @@ public function testGetKey()
$this->assertNotEquals('BA', $value->getKey());
}

/**
* @dataProvider invalidValueProvider
* @expectedException \UnexpectedValueException
* @expectedExceptionMessage is not part of the enum MyCLabs\Tests\Enum\EnumFixture
*/
/** @dataProvider invalidValueProvider */
public function testCreatingEnumWithInvalidValue($value)
{
$this->expectException(\UnexpectedValueException::class);
$this->expectExceptionMessage('is not part of the enum ' . EnumFixture::class);

new EnumFixture($value);
}

Expand Down Expand Up @@ -166,13 +165,11 @@ public function testStaticAccess()
$this->assertNotSame(EnumFixture::NUMBER(), EnumFixture::NUMBER());
}

/**
* @expectedException \BadMethodCallException
* @expectedExceptionMessage No static method or enum constant 'UNKNOWN' in class
* UnitTest\MyCLabs\Enum\Enum\EnumFixture
*/
public function testBadStaticAccess()
{
$this->expectException(\BadMethodCallException::class);
$this->expectExceptionMessage('No static method or enum constant \'UNKNOWN\' in class ' . EnumFixture::class);

EnumFixture::UNKNOWN();
}

Expand Down

0 comments on commit 46cf3d8

Please sign in to comment.