LoginSignup
0
0

More than 3 years have passed since last update.

【PHP】Phan の "PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace" エラー時注意点

Last updated at Posted at 2020-07-24

Phan で静的コード解析すると「PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace MyClass」エラーが出る。

特に Symfony の Component など、composer 経由で autoload したパッケージを use で宣言した際にも出る。

Phanのエラー
PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace MyClass (\MyVendor\MyPackage\MyNameSpace\MyClass)

「phan PhanUnreferencedUseNormal Possibly zero references to use statement for classlike/namespace」でググっても「何か違う」記事や Issue しか出てこなかったので、自分のググラビリティとして。

TL; DR

エラー自体は「ソースコード冒頭の use ステートメント(声明)で宣言されるも、そのファイル内で使われている形跡がなさげ」という意味です。

まずは該当するライブラリ、つまり use 文のクラス/オブジェクトのインスタンスが、そのファイル中で本当に使われているか確認します。

使われているのにエラーが出る場合は「名前空間付きのライブラリか」を確認します。use \Hoge といったグローバル空間に設置されるタイプのクラスだったり PSR-0 で読み込まれているタイプのクラスの場合は、Phan の設定でパッケージを指定する必要があります。

例えば、パッケージが ./vendor/my_vendor/my_package に設置されている場合は、Phan の設定ファイルは以下のようになります。

./path/to/phan.php
<?php

return [
    // Phan 解析時に読み込みたいパッケージのディレクトリ
    'directory_list' => [
        'src',
        'vendor/my_vendor/my_package',
    ],
    // 静的解析時に「解析対象から除外」したいディレクトリ
    'exclude_analysis_directory_list' => [
        'vendor/'
    ],
];

次に、Phan を呼び出す時に config-file オプションで設定ファイルを指定します。

$ ./vendor/bin/phan --config-file ./path/to/phan.php

最後に use 文の「あり」「なし」でテストしてみます。PSR-0 タイプのライブラリの場合は use 文を削除が必要になります。

TS; DR

「この PHP がテンプレートエンジンのくせに慎重すぎる」シリーズに啓示を受けて、プロジェクトの開始時から静的解析ツールを使うようになりました。

どの静的解析ツールも基本中の基本は同じ確認をしてくれます。しかし、各々に解析する目線が異なっており、片方ではエラーが出なくても、もう片方でエラーが出ることが多々あります。口うるさく感じるものの、リファレンスを読むとそれなりの理由があり、思い込みや決めつけが強くポカが多い自分にはいいポカヨケになっています。

そんな中、とある俺様パッケージ開発中に、ユニットテストをパスしたのでいよいよ解析ツールからのエラー潰し込みに入ったものの、表題のエラーで予想外の時間を消費してしまいました。

ネットで調べても「Symfony 形式コメント対応 Phan プラグインを入れろ」だの、Symfony のコメント記法は独特だから解析できないなど、何か求めている情報とは違うようです。盲目的に試してみるも、効果なし。

一晩置いたら、エラー・メッセージに理由が書いてありました。。。

  • PhanUnreferencedUseNormal
    • 「Phan です。use が普通に参照されていませんエラー」という意味。
  • Possibly zero references to use statement for classlike/namespace MyClass
    • /クラス風の/俺様名前空間/MyClass のための use 声明文に対して参照ナッシングの可能性あり」という意味。

落ち着いてエラー内容を読めばその通りなのですが、静的解析のエラーを1つ1つ潰していたら、何か麻痺していたようです。叱られる時に「あの時も。。。」と連続して色々注意されると、結局何を注意されていたのかわからずトンチンカンな行動を取るのと似ています。とほほ。。。

このエラーは、実際には俺様クラスだけでなく、Symfony の HttpClient コンポーネントでも出ていました。きっかけは、本体クラスから汎用メソッドを Trait 化した時です。

メソッドの引数でクラス名で型宣言する場合、use 文で利用するクラスを宣言しておかないと、静的解析ツールから叱られます。

SampleTrait.php
<?php

declare(strict_types=1);

namespace \MyVendor\MyPackage\MyNameSpace;

use \Symfony\Component\HttpClient\HttpClient;

trait Sample
{
    public function requestUrlAsGet(HttpClient $client_http, string $url_target): array
    {
        $response = $client_http->request('GET', $url_target);
        return $response->toArray();
    }
}

実際には Trait を利用する先で use 宣言していればスクリプトは動くことは動きます。

しかし、ダイレクトに Trait ファイルを見た時に「なんじゃ、この降って湧いたようなクラスは」とならないように「このファイルで使うクラスを予め言っておくよ」と宣言しておけということです。

問題は、使っていないくせに「使うよ」と宣言されると、「どこ?どこ?」となってしまうので、無駄な宣言に対しても厳しいということです。

未来の俺よ、またここに来たらまずはもちつけ。落ち着いてエラーを読めばわかる。エラーの内容を読んで理解する前にググるな。orz

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0