Skip to content

Commit 942a38e

Browse files
authored
Merge pull request #29 from yamadashy/feat/add-playground-and-update-docs
feat: Add playground for testing and improve editorUrl documentation
2 parents 60531bd + bf32628 commit 942a38e

File tree

10 files changed

+299
-8
lines changed

10 files changed

+299
-8
lines changed

.php-cs-fixer.dist.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
$finder = PhpCsFixer\Finder::create()
44
->exclude([
5-
'tests/data'
5+
'tests/data',
6+
'playground',
67
])
78
->in(__DIR__);
89

README.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,38 @@ You can customize in your `phpstan.neon`:
6464
```neon
6565
parameters:
6666
friendly:
67-
# default is 3
68-
lineBefore: 3
69-
lineAfter: 3
70-
# default is null
67+
lineBefore: 3 # Number of lines to display before error line (default: 2)
68+
lineAfter: 3 # Number of lines to display after error line (default: 2)
69+
editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' # Editor URL (default: null)
70+
```
71+
72+
### Editor URL Configuration
73+
74+
The `editorUrl` option allows you to create clickable links in terminal output that open files directly in your editor.
75+
76+
**Available placeholders:**
77+
- `%%file%%` - Absolute file path
78+
- `%%relFile%%` - Relative file path (useful for Docker/container environments)
79+
- `%%line%%` - Line number
80+
81+
**Editor examples:**
82+
```neon
83+
parameters:
84+
friendly:
85+
# PhpStorm / IntelliJ IDEA
7186
editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%'
87+
88+
# VSCode (with absolute path)
89+
editorUrl: 'vscode://file/%%file%%:%%line%%'
90+
91+
# VSCode (with relative path - for Docker environments, requires base path)
92+
editorUrl: 'vscode://file//your/local/project/path/%%relFile%%:%%line%%'
93+
94+
# Sublime Text
95+
editorUrl: 'subl://open?url=file://%%file%%&line=%%line%%'
7296
```
7397

74-
- `lineBefore` ... Number of lines to display before error line
75-
- `lineAfter` ... Number of lines to display after error line
76-
- `editorUrl` ... URL with placeholders like [table formatter config](URL for editor like table formatter)
98+
> **Note:** When running PHPStan in Docker or other virtualized environments, use `%%relFile%%` instead of `%%file%%` to get the relative path. For VSCode, you may need to prepend your local project path since VSCode requires absolute paths.
7799
78100

79101
## 🖼️ Example

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"analyze": "phpstan analyze -c phpstan.neon.dist --error-format friendly",
5252
"analyze-raw": "phpstan analyze -c phpstan.neon.dist --error-format raw",
5353
"analyze-table": "phpstan analyze -c phpstan.neon.dist --error-format table",
54+
"playground": "phpstan analyze playground -c playground/phpstan.neon --error-format friendly",
5455
"cs-fix": "php-cs-fixer fix",
5556
"cs-fix-dry": "php-cs-fixer fix --dry-run"
5657
}

phpstan.neon.dist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ parameters:
3838
friendly:
3939
lineBefore: 2
4040
lineAfter: 2
41+
# editorUrl examples:
42+
# - PhpStorm: 'phpstorm://open?file=%%relFile%%&line=%%line%%'
43+
# - VSCode (local): 'vscode://file//path/to/project/%%relFile%%:%%line%%'
44+
editorUrl: null

playground/dead_code.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Dead code and unreachable code errors for PHPStan testing
7+
*/
8+
9+
// 1. Unreachable code after return
10+
function unreachableAfterReturn(): string
11+
{
12+
return 'hello';
13+
echo 'This is unreachable'; // Error: unreachable
14+
}
15+
16+
// 2. Unreachable code after throw
17+
function unreachableAfterThrow(): void
18+
{
19+
throw new RuntimeException('Error');
20+
echo 'Never executed'; // Error: unreachable
21+
}
22+
23+
// 3. Always true/false condition
24+
function alwaysTrueCondition(): void
25+
{
26+
$value = 'string';
27+
if (is_string($value)) { // Error: always true
28+
echo 'Always executes';
29+
}
30+
}
31+
32+
// 4. Impossible type check
33+
function impossibleCheck(int $value): void
34+
{
35+
if (is_string($value)) { // Error: impossible, $value is int
36+
echo 'Never happens';
37+
}
38+
}
39+
40+
// 5. Unused private method
41+
class ClassWithDeadCode
42+
{
43+
public function publicMethod(): void
44+
{
45+
echo 'public';
46+
}
47+
48+
private function unusedPrivateMethod(): void // Error: unused
49+
{
50+
echo 'never called';
51+
}
52+
}

playground/logic_errors.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Logic and comparison errors for PHPStan testing
7+
*/
8+
9+
// 1. Strict comparison with different types
10+
function strictComparison(): bool
11+
{
12+
return 'string' === 123; // Error: comparing different types
13+
}
14+
15+
// 2. Division by zero
16+
function divisionByZero(): float
17+
{
18+
$divisor = 0;
19+
return 100 / $divisor; // Error: division by zero
20+
}
21+
22+
// 3. Array access on non-array
23+
function arrayAccessOnString(): string
24+
{
25+
$value = 'hello';
26+
return $value['key']; // Error: invalid array access
27+
}
28+
29+
// 4. Instanceof with final class that doesn't match
30+
final class FinalClass
31+
{
32+
}
33+
34+
class OtherClass
35+
{
36+
}
37+
38+
function impossibleInstanceof(OtherClass $obj): bool
39+
{
40+
return $obj instanceof FinalClass; // Error: impossible
41+
}
42+
43+
// 5. Wrong number of arguments
44+
function expectsThreeArgs(int $a, int $b, int $c): int
45+
{
46+
return $a + $b + $c;
47+
}
48+
49+
$result = expectsThreeArgs(1, 2); // Error: missing argument
50+
51+
// 6. Duplicate array key
52+
function duplicateKeys(): array
53+
{
54+
return [
55+
'key' => 'first',
56+
'key' => 'second', // Error: duplicate key
57+
];
58+
}

playground/missing_types.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Missing type declarations for PHPStan testing
7+
*/
8+
9+
// 1. Missing return type
10+
function noReturnType() // Error at higher levels: missing return type
11+
{
12+
return 'hello';
13+
}
14+
15+
// 2. Missing parameter type
16+
function noParamType($value): string // Error at higher levels: missing param type
17+
{
18+
return (string) $value;
19+
}
20+
21+
// 3. Missing property type
22+
class MissingTypes
23+
{
24+
public $untyped; // Error at higher levels: missing property type
25+
26+
private $alsoUntyped = 'default'; // Error at higher levels
27+
28+
public function process($input) // Error: missing types
29+
{
30+
$this->untyped = $input;
31+
return $input;
32+
}
33+
}
34+
35+
// 4. Mixed type usage
36+
function usesMixed(mixed $value): mixed
37+
{
38+
return $value->someMethod(); // Error: calling method on mixed
39+
}

playground/phpstan.neon

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# PHPStan configuration for playground
2+
# Usage: cd playground && ../vendor/bin/phpstan analyze
3+
4+
includes:
5+
- ../extension.neon
6+
7+
parameters:
8+
level: 9
9+
paths:
10+
- .
11+
12+
# Friendly formatter settings
13+
friendly:
14+
lineBefore: 3
15+
lineAfter: 3
16+
editorUrl: 'vscode://file/%%relFile%%:%%line%%'

playground/type_errors.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Type-related errors for PHPStan testing
7+
*/
8+
9+
// 1. Wrong return type
10+
function getString(): string
11+
{
12+
return 123; // Error: should return string
13+
}
14+
15+
// 2. Wrong argument type
16+
function expectsInt(int $value): void
17+
{
18+
echo $value;
19+
}
20+
21+
expectsInt('not an int'); // Error: wrong argument type
22+
23+
// 3. Nullable type not handled
24+
function processString(string $value): int
25+
{
26+
return strlen($value);
27+
}
28+
29+
function mayReturnNull(): ?string
30+
{
31+
return rand(0, 1) ? 'hello' : null;
32+
}
33+
34+
processString(mayReturnNull()); // Error: might be null
35+
36+
// 4. Array type mismatch
37+
/** @param array<int, string> $items */
38+
function processStringArray(array $items): void
39+
{
40+
foreach ($items as $item) {
41+
echo $item;
42+
}
43+
}
44+
45+
processStringArray([1, 2, 3]); // Error: array of int, not string
46+
47+
// 5. Property type mismatch
48+
class TypedClass
49+
{
50+
public string $name;
51+
52+
public function __construct()
53+
{
54+
$this->name = 42; // Error: wrong type
55+
}
56+
}

playground/undefined_errors.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Undefined variable/method/class errors for PHPStan testing
7+
*/
8+
9+
// 1. Undefined variable
10+
function useUndefinedVar(): void
11+
{
12+
echo $undefinedVariable; // Error: undefined variable
13+
}
14+
15+
// 2. Undefined method
16+
class SomeClass
17+
{
18+
public function existingMethod(): void
19+
{
20+
}
21+
}
22+
23+
$obj = new SomeClass();
24+
$obj->nonExistentMethod(); // Error: undefined method
25+
26+
// 3. Undefined class
27+
$instance = new NonExistentClass(); // Error: undefined class
28+
29+
// 4. Undefined constant
30+
echo UNDEFINED_CONSTANT; // Error: undefined constant
31+
32+
// 5. Undefined property
33+
class AnotherClass
34+
{
35+
public string $definedProperty = 'hello';
36+
}
37+
38+
$another = new AnotherClass();
39+
echo $another->undefinedProperty; // Error: undefined property
40+
41+
// 6. Undefined function
42+
undefinedFunction(); // Error: undefined function

0 commit comments

Comments
 (0)