Skip to content

Commit 720409f

Browse files
committed
code-checker moved to tools
1 parent c7e5f92 commit 720409f

43 files changed

Lines changed: 1599 additions & 1513 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -1,204 +1 @@
1-
Nette PHPStan Rules
2-
*******************
3-
4-
.[perex]
5-
Rozšíření `nette/phpstan-rules` naučí [PHPStan |https://phpstan.org] lépe rozumět Nette kódu. Stačí ho nainstalovat a PHPStan začne odvozovat přesné typy tam, kde dříve znal jen obecné. Například:
6-
7-
```php
8-
class HomePresenter extends Presenter
9-
{
10-
protected function createComponentMenu(): MenuControl
11-
{
12-
return new MenuControl;
13-
}
14-
15-
public function renderDefault(): void
16-
{
17-
$menu = $this['menu']; // PHPStan nyní odvodí MenuControl
18-
$menu->setActive('home'); // bez varování o "neznámé metodě na Component"
19-
}
20-
}
21-
```
22-
23-
24-
Instalace
25-
=========
26-
27-
Nainstalujte přes Composer:
28-
29-
```shell
30-
composer require --dev nette/phpstan-rules
31-
```
32-
33-
Potřebujete PHP 8.1 nebo vyšší a PHPStan 2.1+.
34-
35-
Pokud používáte [phpstan/extension-installer |https://github.com/phpstan/extension-installer], rozšíření se zaregistruje automaticky. Jinak ho přidejte do `phpstan.neon`:
36-
37-
```neon
38-
includes:
39-
- vendor/nette/phpstan-rules/extension.neon
40-
```
41-
42-
Většina kontrol funguje bez další konfigurace. Pouze pro funkce popsané v sekci `Assety` je potřeba malý konfigurační blok v `phpstan.neon` (viz níže). Veškerá konfigurace uvedená na této stránce patří do `phpstan.neon`, nikoli do `common.neon` nebo jiných konfiguračních souborů Nette DI.
43-
44-
45-
Nativní PHP funkce
46-
==================
47-
48-
Mnoho nativních PHP funkcí má v deklarovaném návratovém typu `string|false` nebo `array|null`, ačkoli se chybová hodnota objevuje jen za podmínek, které v moderním kódu prakticky nemohou nastat: selhání `getcwd()` na funkčním filesystému, selhání `json_encode()` bez `JSON_THROW_ON_ERROR`, selhání `preg_split()` na konstantním patternu a podobně. Rozšíření tyto chybové hodnoty z návratových typů odstraní, takže PHPStan přestane vyžadovat ošetření chyb, které *nemohou* nastat.
49-
50-
Kompletní seznam je v [extension-php.neon |https://github.com/nette/phpstan-rules/blob/master/extension-php.neon].
51-
52-
53-
Closures pro runtime kontrolu typů
54-
----------------------------------
55-
56-
Běžný PHP idiom pro runtime ověření, že pole obsahuje hodnoty deklarovaného typu, používá typovanou variadickou closure volanou s operátorem spread:
57-
58-
```php
59-
/** @param string[] $items */
60-
public function setItems(array $items): void
61-
{
62-
(function (string ...$items) {})(...$items);
63-
}
64-
```
65-
66-
PHP vynutí typ `string` na každém argumentu a vyhodí `TypeError`, pokud některý prvek není string. Tělo closure je prázdné a výraz existuje pouze kvůli vedlejšímu efektu. PHPStan by jinak hlásil `expr.resultUnused`, toto pravidlo ale daný vzor rozpozná a chybu nevypíše.
67-
68-
69-
Assety
70-
======
71-
72-
V `phpstan.neon` (nikoli v konfiguraci Nette DI) nastavte mapování ID mapperů na třídy, aby PHPStan dokázal zúžit obecný typ `Asset` na konkrétní třídu:
73-
74-
```neon
75-
parameters:
76-
nette:
77-
assets:
78-
mapping:
79-
default: file # Nette\Assets\FilesystemMapper
80-
images: file
81-
vite: vite # Nette\Assets\ViteMapper
82-
custom: App\MyMapper # libovolné FQCN
83-
```
84-
85-
Hodnoty `file` a `vite` jsou zkratky pro vestavěné `FilesystemMapper` a `ViteMapper`. Jakákoli jiná hodnota se považuje za plně kvalifikovaný název vlastní třídy mapperu.
86-
87-
Po nastavení:
88-
89-
- `Registry::getMapper('vite')` vrací `ViteMapper` místo `Mapper`.
90-
- `Registry::getAsset('default:logo.png')` vrací `ImageAsset`. `tryGetAsset()` vrací `ImageAsset|null`.
91-
- `FilesystemMapper::getAsset('button.js')` a `ViteMapper::getAsset()` se zúžují stejným způsobem.
92-
93-
94-
Component Model
95-
===============
96-
97-
Rozšíření zúží návratový typ `Container::getComponent()` a `Container::offsetGet()` (tedy `$this['name']`) podle factory metod `createComponent<Name>()` deklarovaných na téže třídě.
98-
99-
```php
100-
class HomePresenter extends Presenter
101-
{
102-
protected function createComponentMenu(): MenuControl
103-
{
104-
return new MenuControl;
105-
}
106-
107-
public function renderDefault(): void
108-
{
109-
$menu = $this->getComponent('menu'); // MenuControl
110-
$menu = $this['menu']; // MenuControl
111-
}
112-
}
113-
```
114-
115-
Pokud odpovídající factory neexistuje nebo název komponenty není konstantní string, ponechá se deklarovaný návratový typ.
116-
117-
118-
Formuláře
119-
=========
120-
121-
Pokud je volání `$form->addText('name', …)`, `$form->addSelect(…)` apod. ve stejné funkci nebo metodě jako přístup k `$form['name']` (případně `$form->getComponent('name')`), rozšíření odvodí typ přístupu z odpovídajícího volání `addXxx()`:
122-
123-
```php
124-
public function createComponentSignInForm(): Form
125-
{
126-
$form = new Form;
127-
$form->addText('username', 'Username');
128-
$form->addPassword('password', 'Password');
129-
130-
$form['username']; // TextInput
131-
$form['password']; // TextInput (Password je potomek)
132-
return $form;
133-
}
134-
```
135-
136-
Pokud žádné odpovídající volání `addXxx()` neexistuje, rozšíření se stejně jako Component Model pokusí najít factory `createComponent<Name>()`.
137-
138-
139-
Vlastnosti event handlerů
140-
-------------------------
141-
142-
Formuláře data převedou na typ deklarovaný v parametru callbacku, ať jde o `stdClass`, `array` nebo vlastní DTO. Callback s užším datovým parametrem, než je deklarovaný union `array|object`, je proto v pořádku:
143-
144-
```php
145-
$form->onSuccess[] = function (Form $form, MyDto $data): void {
146-
// …
147-
};
148-
```
149-
150-
PHPStan by jinak hlásil `assign.propertyType`, protože `MyDto` je užší než `array|object`. Pravidlo tuto chybu potlačuje u vlastností `Form::$onSuccess`, `$onError`, `$onSubmit`, `$onRender`, `Container::$onValidate`, `SubmitButton::$onClick` a `$onInvalidClick`.
151-
152-
153-
Schema
154-
======
155-
156-
Rozšíření zúží návratový typ `Expect::array()` z deklarovaného unionu `Structure|Type` podle předaného argumentu:
157-
158-
```php
159-
Expect::array(); // Type
160-
Expect::array(['name' => Expect::string()]); // Structure (všechny hodnoty jsou Schema)
161-
Expect::array(['name' => Expect::string(), 'x']); // Structure|Type (Schema i ne-Schema hodnoty)
162-
```
163-
164-
Pokud argument obsahuje Schema i ne-Schema hodnoty, deklarovaný union zůstane zachován.
165-
166-
167-
Tester
168-
======
169-
170-
PHPStan po voláních metod `Tester\Assert` zúží typ proměnné. Podporované metody: `null`, `notNull`, `true`, `false`, `truthy`, `falsey`, `same`, `notSame`, `type`.
171-
172-
```php
173-
function process(?User $user): void
174-
{
175-
Assert::notNull($user);
176-
$user->getName(); // bez varování o volání na null
177-
}
178-
```
179-
180-
Arrow funkce jako void callbacky
181-
--------------------------------
182-
183-
Funkce Testeru `test()` a `Assert::exception()` přijímají callbacky typované jako `Closure(): void`, ale často se jim předávají arrow funkce ve stylu `fn () => throw new MyException`. Arrow funkce vždy vrací nějakou hodnotu, což by PHPStan jinak označil za typovou neshodu. Pravidlo tuto chybu potlačuje u následujících funkcí a metod: `test`, `testException`, `testNoError`, `Tester\Assert::exception`, `Tester\Assert::throws`, `Tester\Assert::error`, `Tester\Assert::noError`.
184-
185-
186-
Utils
187-
=====
188-
189-
**`Strings::match()`, `matchAll()`, `split()`**: návratové typy se odvodí z booleovských flagů (`captureOffset`, `unmatchedAsNull`, `patternOrder`, `lazy`):
190-
191-
```php
192-
Strings::match($s, '#(\w+)#'); // array<string>|null
193-
Strings::match($s, '#(\w+)#', captureOffset: true); // array<array{string, int<0, max>}>|null
194-
Strings::match($s, '#(\w+)#', unmatchedAsNull: true); // array<string|null>|null
195-
Strings::matchAll($s, '#(\w+)#', lazy: true); // Generator<int, array<string>>
196-
```
197-
198-
Pokud flag není konstantní hodnota, zachová se deklarovaný návratový typ.
199-
200-
**`Arrays::invoke()`** a **`Arrays::invokeMethod()`** vracejí místo deklarovaného `array` pole s typem návratové hodnoty volaného callable, resp. metody.
201-
202-
**`Helpers::falseToNull()`** zúží návratový typ tak, že odstraní `false` a přidá `null`. Z `string|false` se tedy stane `string|null`.
203-
204-
**`Html` magické metody**: `$el->setClass(…)`, `$el->addData(…)`, `$el->getHref()` a podobné se rozpoznají i bez `@method` anotací. `setXxx()` a `addXxx()` vrací `static` (fluent API), `getXxx()` vrací `mixed`.
1+
{{redirect: tools:cs:phpstan-rules}}

0 commit comments

Comments
 (0)