もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

psalmを試す

はじめに。

こんばんは。

今回は以下の本で紹介されていた psalm を試してみます。

本題

勢いでsymfonyアドベントカレンダーに登録してしまったんで、symfonyプロジェクトでちょろっとやってみようと思います。 (symfonyは特に使いませんが...)

1. install

$ symfony new --full psalm_example --version lts
$ cd psalm_example
$ ./bin/console -V
Symfony 4.4.33 (env: dev, debug: true)

$ composer require --dev vimeo/psalm

$ ./vendor/bin/psalm --init

2. 設定ファイル作成

<?xml version="1.0"?>
<psalm
    errorLevel="1" ← 1に変更
    resolveFromConfigFile="true"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
    <projectFiles>
        <directory name="src" />
        <ignoreFiles>
            <directory name="vendor" />
            <file name="src/Kernel.php" /> ← 追加
        </ignoreFiles>
    </projectFiles>
</psalm>

3. わざとエラー出してみる

<?php

namespace Kojirock\PsalmExample;

class Example
{
    /**
     * 数値を文字列に変換する
     * @param int $num
     * @return string
     */
    public static function example1(int $num): string
    {
        return (string)$num;
    }
}

$example1Result = Example::example1(100);
Example::example1($example1Result);
$  ./vendor/bin/psalm 
Scanning files...
Analyzing files...

ERROR: InvalidScalarArgument - src/Controller/SampleController.php:18:27 - Argument 1 of Kojirock\PsalmExample\Example::example1 expects int, string provided (see https://psalm.dev/012)
        Example::example1($example1Result);

int型を期待している引数に文字列型を渡してるのでエラーになりました。

// 連番の添字の配列として指定
/** @var non-empty-list<int> $example3 */
$example3 = Example::example3();
if (!$example3['example']) {
    $example3['example'] = 'aaa';
}


ERROR: InvalidArrayOffset - src/Controller/SampleController.php:20:14 - Cannot access value on variable $example3 using offset value of 'example', expecting int (see https://psalm.dev/115)
        if (!$example3['example']) {

連番の配列として指定しているのに連想配列的に扱っていることでエラーになりました。

/** @var array{0: int, 1: string} $example3 */
$example3 = Example::example3();
$example3[0] = 1;
$example3[1] += 2;
$ ./vendor/bin/psalm 
Scanning files...
Analyzing files...

E

ERROR: InvalidOperand - src/Controller/SampleController.php:20:9 - Cannot perform a numeric operation with a non-numeric type string (see https://psalm.dev/058)
        $example3[1] += 2;

配列の1番目は文字列型に指定しているのに、足し算をしようとしてエラーになりました。

$this->plus(1, 9);

/**
 * @param 1|2|3 $a
 * @param 4|5|6 $b
 * @return int
 */
private function plus(int $a, int $b): int
{
    return $a + $b;
}
$ ./vendor/bin/psalm 
Scanning files...
Analyzing files...

E

ERROR: InvalidArgument - src/Controller/SampleController.php:21:24 - Argument 2 of App\Controller\SampleController::plus expects 4|5|6, 9 provided (see https://psalm.dev/004)
        $this->plus(1, 9);

4〜6までの数値を期待していたのに、9が渡されたためエラーになりました。

終わりに

クラスとかメソッドとかも色々できるみたいですが、そのあたりはphpStormで開発してたらなんとかなりそうな気がしました。

ただ、比較的レガシーなコードや、色んな人が触ってジェンガみたいになっているコードなど、そういったきつめのコードに対して、 psalm を使って少しずつ紐を解きほぐすようなことができるかもと思いました。

やっぱりそういうコードは配列が多用されてたりするから、そこでは結構旨味ありそうだと感じました。

現場からは以上です。