Skip to content

Commit 83677d5

Browse files
Tag version 0.1.0
1 parent e5abb30 commit 83677d5

23 files changed

+1121
-2
lines changed

.github/workflows/all_tests.yml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: "All Tests"
2+
3+
on:
4+
pull_request:
5+
push:
6+
7+
jobs:
8+
test:
9+
name: "Run all checks for all supported PHP versions"
10+
11+
runs-on: "ubuntu-22.04"
12+
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
php-version:
17+
- "8.0"
18+
- "8.1"
19+
- "8.2"
20+
- "8.3"
21+
22+
steps:
23+
- name: "Checkout"
24+
uses: "actions/checkout@v4"
25+
26+
- name: "Install PHP"
27+
uses: "shivammathur/setup-php@v2"
28+
with:
29+
php-version: "${{ matrix.php-version }}"
30+
tools: composer
31+
32+
- name: Get composer cache directory
33+
id: composercache
34+
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
35+
36+
- name: Cache dependencies
37+
uses: actions/cache@v4
38+
with:
39+
path: ${{ steps.composercache.outputs.dir }}
40+
key: "php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}"
41+
restore-keys: "php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}"
42+
43+
- name: "Install composer dependencies"
44+
run: "COMPOSER_ROOT_VERSION=dev-main composer install --no-interaction --no-progress"
45+
46+
- name: "Run tests"
47+
run: "composer tests"

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/vendor/
2+
composer.lock
3+
.phpunit.cache
4+
.idea

README.md

+102-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,102 @@
1-
# attributes
2-
Attributes used for static analysis
1+
# PHP Static Analysis Attributes
2+
3+
[![Continuous Integration](https://github.com/php-static-analysis/attributes/workflows/All%20Tests/badge.svg)](https://github.com/php-static-analysis/attributes/actions)
4+
[![Latest Stable Version](https://poser.pugx.org/php-static-analysis/attributes/v/stable)](https://packagist.org/packages/php-static-analysis/attributes)
5+
[![PHP Version Require](http://poser.pugx.org/php-static-analysis/attributes/require/php)](https://packagist.org/packages/php-static-analysis/attributes)
6+
[![License](https://poser.pugx.org/php-static-analysis/attributes/license)](https://github.com/php-static-analysis/attributes/blob/main/LICENSE)
7+
[![Total Downloads](https://poser.pugx.org/php-static-analysis/attributes/downloads)](https://packagist.org/packages/php-static-analysis/attributes/stats)
8+
9+
Since the release of PHP 8.0 more and more libraries, frameworks and tools have been updated to use attributes instead of annotations in PHPDocs.
10+
11+
However, static analysis tools like PHPStan or Psalm or IDEs like PHPStorm or VS Code have not made this transition to attributes and they still rely on annotations in PHPDocs for a lot of their functionality.
12+
13+
This library aims to provide a set of PHP attributes which could replace the most commonly used annotations accepted by these tools and will aim to provide related repositories with the extensions or plugins that would allow these attributes to be used in these tools.
14+
15+
In particular, these repositories are:
16+
17+
- [PHPStan extension](https://github.com/php-static-analysis/phpstan-extension)
18+
- [Psalm plugin](https://github.com/php-static-analysis/psalm-plugin)
19+
- [RectorPHP rules to migrate annotations to attributes](https://github.com/php-static-analysis/rector-rule)
20+
21+
## PHPStorm
22+
A plugin that fully supports these attributes will need to be created. Until this is ready you can get partial support by installing PHPStan, our PHPStan extension and enabling PHPStan support in PHPStorm (as described [here](https://www.jetbrains.com/help/phpstorm/using-phpstan.html)). You will then be able to see errors and messages related to these attributes in your code.
23+
24+
Alternatively install Psalm, our Psalm extension and enable Psalm support in PHPStorm (as described [here](https://www.jetbrains.com/help/phpstorm/using-psalm.html))
25+
26+
## VS Code Support
27+
An extension that fully supports these attributes will need to be created. Until this is ready you can get partial support by installing PHPStan, our PHPStan extension and a VS Code extension that supports PHPStan (for example [this one](https://github.com/SanderRonde/phpstan-vscode)). When you enable the extension you will be able to see errors and messages related to these attributes in your code.
28+
29+
Alternatively install Psalm, our Psalm extension and a VS Code extension that supports Psam (for example [this one](https://github.com/psalm/psalm-vscode-plugin))
30+
31+
## Example
32+
33+
In order to show how code would look with these attributes, we can look at the following example. This is how a class looks like with the current annotations:
34+
35+
```php
36+
<?php
37+
38+
class ArrayAdder
39+
{
40+
/** @var array<string> */
41+
private array $result;
42+
43+
/**
44+
* @param array<string> $array1
45+
* @param array<string> $array2
46+
* @return array<string>
47+
*/
48+
public function addArrays(array $array1, array $array2): array
49+
{
50+
$this->result = $array1 + $array2;
51+
return $this->result;
52+
}
53+
}
54+
```
55+
56+
And this is how it would look like using the new attributes:
57+
58+
```php
59+
<?php
60+
61+
use PhpStaticAnalysis\Attributes\Type;
62+
use PhpStaticAnalysis\Attributes\Param;
63+
use PhpStaticAnalysis\Attributes\Returns;
64+
65+
class ArrayAdder
66+
{
67+
#[Type('array<string>')]
68+
private array $result;
69+
70+
#[Param(array1: 'array<string>')]
71+
#[Param(array2: 'array<string>')]
72+
#[Returns('array<string>')]
73+
public function addArrays(array $array1, array $array2): array
74+
{
75+
$this->array = $array1 + $array2;
76+
return $this->array;
77+
}
78+
}
79+
```
80+
81+
## Installation
82+
83+
To use these attributes, require this library in Composer:
84+
85+
```
86+
composer require php-static-analysis/attributes
87+
```
88+
89+
And then install any needed extensions/plugins for the tools that you use.
90+
91+
## List of implemented attributes
92+
93+
These are the available attributes and their corresponding PHPDoc annotation:
94+
95+
| Attribute | PHPDoc Annotation |
96+
|---|-------------------|
97+
| [IsReadOnly](doc/IsReadOnly.md) | `@readonly` |
98+
| [Param](doc/Param.md) | `@param` |
99+
| [Returns](doc/Returns.md) | `@return` |
100+
| [Template](doc/Template.md) | `@template` |
101+
| [Type](doc/Type.md) | `@var` |
102+

composer.json

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"name": "php-static-analysis/attributes",
3+
"description": "Attributes used instead of PHPDocs for static analysis tools",
4+
"type": "library",
5+
"license": "MIT",
6+
"autoload": {
7+
"psr-4": {
8+
"PhpStaticAnalysis\\Attributes\\": "src/"
9+
}
10+
},
11+
"authors": [
12+
{
13+
"name": "Carlos Granados",
14+
"email": "[email protected]"
15+
}
16+
],
17+
"minimum-stability": "dev",
18+
"prefer-stable": true,
19+
"require": {
20+
"php": ">=8.0"
21+
},
22+
"require-dev": {
23+
"php-static-analysis/phpstan-extension": "dev-main",
24+
"php-static-analysis/psalm-plugin": "dev-main",
25+
"phpstan/extension-installer": "^1.3",
26+
"phpstan/phpstan": "^1.8",
27+
"phpunit/phpunit": "^9.0",
28+
"symplify/easy-coding-standard": "^12.1",
29+
"vimeo/psalm": "^5"
30+
},
31+
"scripts": {
32+
"phpstan": "phpstan analyse",
33+
"phpstan-debug": "phpstan analyse --xdebug --debug",
34+
"ecs": "ecs",
35+
"ecs-fix": "ecs --fix",
36+
"phpunit": "phpunit",
37+
"psalm": "psalm",
38+
"tests": [
39+
"@ecs",
40+
"@phpstan",
41+
"@phpunit",
42+
"@psalm"
43+
]
44+
},
45+
"config": {
46+
"allow-plugins": {
47+
"phpstan/extension-installer": true
48+
},
49+
"sort-packages": true
50+
},
51+
"suggest": {
52+
"php-static-analysis/phpstan-extension": "PHPStan extension to read static analysis attributes",
53+
"php-static-analysis/psalm-plugin": "Psalm plugin to read static analysis attributes",
54+
"php-static-analysis/rector-rule": "RectorPHP rule to convert PHPDoc annotations to static analysis attributes"
55+
}
56+
}

doc/IsReadOnly.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# `IsReadOnly` Attribute
2+
3+
This attribute is the equivalent of the `@readonly` annotation for class properties.
4+
5+
We could not use `ReadOnly` for the name of this attribute because `readonly` is a reserved word in PHP.
6+
7+
## Arguments
8+
9+
The attribute accepts no arguments.
10+
11+
## Example usage
12+
13+
```php
14+
<?php
15+
16+
use PhpStaticAnalysis\Attributes\IsReadOnly;
17+
18+
class IsReadOnlyExample
19+
{
20+
#[IsReadOnly]
21+
public string $name;
22+
23+
...
24+
}
25+
```

doc/Param.md

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# `Param` Attribute
2+
3+
This attribute is the equivalent of the `@param` annotation. It can be used on class methods or on regular functions.
4+
5+
## Arguments
6+
7+
The attribute accepts one or more strings which describes the types of the parameters. The attribute itself does not have a knowledge of which types are valid and which are not and this will depend on the implementation for each particular tool.
8+
9+
We expect that the attribute will be able to accept both basic types like `string` or `array` and more advanced types like `array<string>` or `Collection<int>`. We aim to accept all the types accepted by static analysis tools for the `@param` annotation.
10+
11+
The arguments can be named arguments and the type is applied to the parameter with the same name in the function or the class.
12+
13+
You can also pass an unnamed argument with a string that contains both the type and the name of the parameter, but we recommend using named arguments.
14+
15+
If the function or method has more than one parameter, the types for the different parameters can either be declared as a list of strings for a single `Param` attribute or as a list of `Param` attributes (or even a combination of both, though we don't expect this to be actually used).
16+
17+
If any of the parameters is variadic, the `...` operator needs to be listed with the type, not the argument name.
18+
19+
## Example usage
20+
21+
```php
22+
<?php
23+
24+
use PhpStaticAnalysis\Attributes\Param;
25+
26+
class ParamExample
27+
{
28+
// Single parameter
29+
#[Param(param: 'string[]')]
30+
public function methodParamWithName(array $param)
31+
{
32+
}
33+
34+
// Single parameter with unnamed argument
35+
#[Param('string[] $param')]
36+
public function methodParamWithoutName(array $param)
37+
{
38+
}
39+
40+
// Multiple params listed in a single attribute
41+
#[Param(
42+
param1: 'string[]',
43+
param2: 'string[]',
44+
)]
45+
public function severalMethodParamsWithName(array $param1, array $param2)
46+
{
47+
}
48+
49+
// Multiple params listed in multiple attributes
50+
#[Param(param1: 'string[]')]
51+
#[Param(param2: 'string[]')]
52+
public function multipleMethodParamsWithName(array $param1, array $param2)
53+
{
54+
}
55+
56+
// variadic parameter
57+
#[Param(params: 'string ...')]
58+
public function variadicMethodParam(...$params)
59+
{
60+
}
61+
}
62+
```

doc/Returns.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# `Returns` Attribute
2+
3+
This attribute is the equivalent of the `@return` annotation. It can be used on class methods or on regular functions.
4+
5+
We could not use `Return` for the name of this attribute because `return` is a reserved word in PHP.
6+
7+
## Arguments
8+
9+
The attribute accepts a string which describes the type of the value returned by the function or method. The attribute itself does not have a knowledge of which types are valid and which are not and this will depend on the implementation for each particular tool.
10+
11+
We expect that the attribute will be able to accept both basic types like `string` or `array` and more advanced types like `array<string>` or `Collection<int>`. We aim to accept all the types accepted by static analysis tools for the `@return` annotation.
12+
13+
## Example usage
14+
15+
```php
16+
<?php
17+
18+
use PhpStaticAnalysis\Attributes\Returns;
19+
20+
class ReturnsExample
21+
{
22+
#[Returns('Array<string>')]
23+
public function getNames(): array
24+
{
25+
...
26+
}
27+
}
28+
```

doc/Template.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# `Template` Attribute
2+
3+
This attribute is the equivalent of the `@template` annotation. It can be used on class methods or on regular functions. It can also be applied to a class, trait or interface.
4+
5+
## Arguments
6+
7+
The attribute accepts one string that defines the name of the type variable and an optional string that defines its type. The attribute itself does not have a knowledge of which type variables are valid and which are not and this will depend on the implementation for each particular tool.
8+
9+
We aim to accept all the type variables accepted by static analysis tools for the `@template` annotation.
10+
11+
If the function, method or class has more than one type variable, you can add a list of `Template` attributes.
12+
13+
## Example usage
14+
15+
```php
16+
<?php
17+
18+
use Exception;
19+
use PhpStaticAnalysis\Attributes\Template;
20+
21+
#[Template('T')]
22+
class TemplateExample
23+
{
24+
// Single type variable
25+
#[Template('T')]
26+
public function methodWithTemplate(array $param)
27+
{
28+
}
29+
30+
// Type variable with a type
31+
#[Template('T', Exception::class)]
32+
public function methodWithTemplate(array $param)
33+
{
34+
}
35+
36+
// Multiple type varibles listed in multiple attributes
37+
#[Template('T1')]
38+
#[Template('T2')]
39+
public function multipleMethodTemplates(array $param1, array $param2)
40+
{
41+
}
42+
}
43+
```

0 commit comments

Comments
 (0)