[PHPStan] Consider adding something like array<Foo> to the PHPDoc. が Level=max で発生する場合の対処法
💡 Consider adding something like array<Foo>
to the PHPDoc.
Function
myFunction()
has parameter$hoge
with no value type specified in iterable type array.
PHPStan を実行すると no value type specified in iterable type array.
と --level=max
で叱られる。「PHPDoc に array<Foo>
っぽいものを書け」と言われるも、何をいっているのか分からない。
------ ------------------------------------------------------------------
Line classes/MyClass.php
------ ------------------------------------------------------------------
9 Property KEINOS\Sample\MyClass::$dummy type has no value type
specified in iterable type array.
💡 Consider adding something like array<Foo> to the PHPDoc.
You can turn off this check by setting
checkMissingIterableValueType: false in your phpstan.neon.
------ ------------------------------------------------------------------
例えば、以下のように @param
で array
と定義しつつ、引数の型宣言も array
と定義しているのに叱られる。
/**
* myDemoFunction
*
* @param array $data
* @return string
*/
function myDemoFunction(array $data): string
{
...
}
さらに「Consider adding something like "array<Foo>" to the PHPDoc.」とググってみてもピンと来ない。
TL; DR
Consider adding something like ??????<Foo> to the PHPDoc.
とは
「?????? を構成する要素の型が不明確なので PHPDoc で明示してね」という意味。
つまり、PHPDoc コメントに @param array
と引数の型宣言を array
と指定しても、その配列の中身である各要素が、どのように構成されているかわからない状態であるということです。(詳しくは TS; DR)
配列の各要素が key
は int
型、値は string
型で構成されている場合は、array<int,string>
と下記のように記載します。この型<キーの型, 値の型>
の記法を「ジェネリクス記法」と呼びます。
以下が修正例の diff
(差分)です。-
が修正前、+
が修正後です。
/**
* myDemoFunction
*
- * @param array $data
+ * @param array<int,string> $data
* @return string
*/
function myDemoFunction(array $data): string
{
...
}
同様に、クラスのプロパティが array
で、要素のキーが int
で値がさらに array
(多次元配列)の場合は、PHPDoc 形式の @var
でその旨を指定してあげます。
class MyClass
{
/** @var array<int,array<string,string>> */
private array $dummy;
public function setValue(string $key, string $value)
{
$len_key = 8; //8byte
$hash_str = substr(hash('sha256', $key), 0, $len_key);
$hash_int = intVal(hexdec($hash_str));
// $this->dummy のキーは int, 値は array、値の array は string => string
// ∴ PHPDoc の型宣言は array<int,array<string,string>> となる
$this->dummy[$hash_int] = [
'key' => $key,
'value' => $value,
];
}
}
TS;DR
no value type specified in iterable type array.
の説明
iterable type
とは「foreach
でループ可能な型」を言います。今回の例では array
なので、itterable type
とは「配列」のことを指します。
そして value type
は「値の型」です。no value type specified
とは「値の型が指定されていません」という意味になります。
総合すると、「iterable
な array
の、value
の type
が指定されていません」という意味です。日本語でいうと「foreach
ループをした際の、各々の値(要素)の型が明記されていない状態である」と PHPStan が型々言っているのです。
関数/メソッドの引数と返り値、そしてオブジェクトのプロパティは比較的に型がつけやすいところですが、現状で無法地帯な箇所があります。
そうです、配列の内部構造です。実際のところ、PHPDocに
@param array
や@return array
と書くことはmixed
と書くのとあまり大きな違いはありません。(「array shapes記法(Object-like arrays)と旧PSR-5記法で型をつける」 @ Qiita より)
つまり、下記のように PHPDoc に引数の型を記載したとしても、問題は同じということです。
$items[] = new Foo(1);
$items[] = new Foo(2);
$items[] = new Foo(3);
/**
* @param array $items
* @return string
*/
function myFunc(array $items): string
foreach($items as $item){
// ここで $items が配列というのはわかっていても、
// $item が「文字列」「配列」「クラスオブジェクト」 etc.
// どの型なのか、全体を見ないとわからない。
}
return $result;
}
では、どうやって子要素を指定してあげればいいのでしょうか。
phpDocumentor や PhpStorm を含めた複数の処理系がサポートする PHPDoc のデファクトな仕様では
Book[]
のように記述することで[new Book("a"), new Book("b"), new Book("c")]
のような Book クラスのオブジェクトだけが並んだ配列を表現することができます。
.../** * @return Books[] */ function getBook(): array { // ... }
(「array shapes記法(Object-like arrays)と旧PSR-5記法で型をつける」 @ Qiita より)
では、以下のように @param Foo[] $items
と指定すれば良い気がします。
$items[] = new Foo(1);
$items[] = new Foo(2);
$items[] = new Foo(3);
/**
* @param Foo[] $items
* @return string
*/
function myFunc(array $items): string
foreach($items as $item){
// ここで $items が配列というのはわかっていて、
// $item が Foo クラスのオブジェクトとわかっていても
// $item が Iterable(foreach 可能か)は、全体を
//見ないとわからない。
}
return $result;
}
しかし、上記のように記載しても PHPStan のワーニングは回避できません。
この記法には弱点があります。PHPには複数のイテレータがありますが、
[]
は飽くまで配列を表すので、ジェネレータやArratIterator
、あるいはその他のコレクションクラスなどは表現できないのです。(「array shapes記法(Object-like arrays)と旧PSR-5記法で型をつける」 @ Qiita より)
💡 Consider adding something like array<Foo> to the PHPDoc.
の説明
先のワーニングの後にサジェスチョンされている 💡 Consider adding something like array<Foo> to the PHPDoc.
は、「PHPDoc に array<Foo>
っぽい何かを追記することを検討してください」という意味です。
では「array<Foo>
っぽい何か」("something like array<Foo>
")とは「A型 < B型 >」の形式で「親要素の型<子要素の型>」と「何か指定してください」という意味です。つまり、array<Foo>
の場合は「配列で、各要素は Foo
クラスである」ということを意味します。
従来記法では値の型のみを指定できましたが、ジェネリクス記法はキーと値の型を同時に指定できます。
/** * @return ArraryObject<int, Book> */ function getBook(): array { // ... }
(「array shapes記法(Object-like arrays)と旧PSR-5記法で型をつける」 @ Qiita より)
このジェネリクス記法でやっと --level=max
で PHPStan を実行してもワーニングが表示されなくなりました。 🙏
具体例
$ ./vendor/bin/phpstan analyse src --level=max
1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
------ -------------------------------------------------------------------------
Line functions.php
------ -------------------------------------------------------------------------
12 Function KEINOS\MyApp\myDemoFunction() has parameter $data with no
value type specified in iterable type array.
💡 Consider adding something like array<Foo> to the
PHPDoc.
You can turn off this check by setting
checkMissingIterableValueType: false in your
phpstan.neon.
12 Function KEINOS\MyApp\myDemoFunction() return type has no value type
specified in iterable type array.
💡 Consider adding something like array<Foo> to the
PHPDoc.
You can turn off this check by setting
checkMissingIterableValueType: false in your
phpstan.neon.
------ -------------------------------------------------------------------------
[ERROR] Found 2 errors
<?php
declare(strict_types=1);
namespace KEINOS\MyApp;
/**
* myDemoFunction
*
* @param array $data
* @return array
*/
function myDemoFunction(array $data): array
{
$result = [];
foreach($data as $item){
// ここで $item の型がわからない
$result[] = $item;
}
// $result の型も不明
return $result;
}
<?php
declare(strict_types=1);
namespace KEINOS\MyApp;
/**
* myDemoFunction
*
* @param array<int,string> $data
* @return array<int,string>
*/
function myDemoFunction(array $data): array
{
$result = [];
foreach($data as $item){
// $item は key=int型、value=string型なのが宣言されている
$result[] = $item;
}
// $result の方も key=int型、value=string型なのが宣言されている
return $result;
}
$ ./vendor/bin/phpstan --version
PHPStan - PHP Static Analysis Tool 0.12.17
$ php --version
PHP 7.4.4 (cli) (built: Mar 19 2020 22:02:49) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Xdebug v2.9.3, Copyright (c) 2002-2020, by Derick Rethans
参考文献
- array shapes記法(Object-like arrays)と旧PSR-5記法で型をつける @ Qiita
- PSR-5ジェネリクス記法についての個人的見解 | PhpStormに実装されてない未来のPHPDocとPSR-5ジェネリクス記法 @ Qiita
Author And Source
この問題について([PHPStan] Consider adding something like array<Foo> to the PHPDoc. が Level=max で発生する場合の対処法), 我々は、より多くの情報をここで見つけました https://qiita.com/KEINOS/items/00139d2d9f9c11c6aa15著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .