Psalm
で Cannot locate
エラー
composer require psalm/phar
でインストールしたphar
版psalm
を実行すると、Notice: Uninitialized string offset: 0 ... command_functions.php ...
とCannot locate
エラーが出るようになりました。
以前までは動いていたと思ったのですが、気付いたらエラーが出ていました。特に Psalm の issues にも上がっておらず、ググりまくっても解決策が見つからなかったので、自分のググラビリティ/備忘録として。
TL; DR
psalm
のコマンド引数で、空のオプションを渡していませんか。
$ use_alter=''
$ ./vendor/bin/psalm \
--config="$(pwd)/tests/conf/psalm.xml" \
--root="$(pwd)" \
"$use_alter" # <--- !! w/quote
Notice: Uninitialized string offset: 0 in phar:///workspaces/SampleApp/vendor/psalm/phar/psalm.phar/src/command_functions.php on line 178
Notice: Uninitialized string offset: 0 in phar:///workspaces/SampleApp/vendor/psalm/phar/psalm.phar/src/command_functions.php on line 184
Notice: Uninitialized string offset: 0 in phar:///workspaces/SampleApp/vendor/psalm/phar/psalm.phar/src/command_functions.php on line 202
Cannot locate
クォートで変数を囲うと、変数の中身が空の場合でもオプションとして渡してしまうので、クォートせずに指定するか if
文で分岐します。
$ use_alter=''
$ ./vendor/bin/psalm \
--config="$(pwd)/tests/conf/psalm.xml" \
--root="$(pwd)" \
$use_alter # <--- !! w/out quote
Scanning files...
Analyzing files...
░░░
------------------------------
No errors found!
------------------------------
Checks took 5.92 seconds and used 171.358MB of memory
Psalm was able to infer types for 100% of the codebase
TS; DR
各種テストを実行するシェル・スクリプトで、psalm
の自動補完/修正機能オプション --alter
を条件によって付けたり付けなかったりしたかったので、変数にオプションを入れて指定していました。
# !/bin/bash
...
# psalm の追加オプション指定
use_alter=''
isFlagSet 'psalter' && {
use_alter='--alter'
}
# psalm の実行
./vendor/bin/psalm \
--config=$path_file_conf_psalm \
--root=$path_dir_parent \
$use_alter || {
echo >&2 'Psalm check failed.'
}
...
あるときから、シェル・スクリプトの静的解析ツールの「ShellCheck」を使うようになりました。
この shellcheck
の解析内容には「変数をダブル・クォーテーションで囲う」(SC2086)と言うルールがあります。これはシェルの場合、変数内にスペースが含まれていた場合、クォーテーションで囲わないと複数の引数として展開してしまうためです。
$ hoge='fuga piyo'
$ ./myCommand $hoge #<- ./myCommand 'fuga' 'piyo' と同等
$ ./myCommand "$hoge" #<- ./myCommand 'fuga piyo' と同等
このことは、「スペース入りディレクトリのあるパス」を扱う時など意図しない(見つけづらい)エラーを起こします。
「まぁ、そうだよな」と、盲目的に修正して(変数をクォートで囲って)いたのですが、逆の**「引数の値が空でも『空の値』として渡してしまう」と言うパターン**を失念しておりました。このことが原因でエラーが発生していたのですが、気づくのに時間がかなりかかってしまいました。
$ # NG
$ ./vendor/bin/psalm \
--config="${path_file_conf_psalm}" \
--root="${path_dir_app_root}" \
"$use_alter"
Notice: Uninitialized string offset: 0 in phar:///workspaces/SampleApp/vendor/psalm/phar/psalm.phar/src/command_functions.php on line 178
Notice: Uninitialized string offset: 0 in phar:///workspaces/SampleApp/vendor/psalm/phar/psalm.phar/src/command_functions.php on line 184
Notice: Uninitialized string offset: 0 in phar:///workspaces/SampleApp/vendor/psalm/phar/psalm.phar/src/command_functions.php on line 202
Cannot locate
$ # OK
$ ./vendor/bin/psalm \
--config="${path_file_conf_psalm}" \
--root="${path_dir_app_root}" \
$use_alter
Scanning files...
Analyzing files...
░░░
------------------------------
No errors found!
------------------------------
Checks took 5.92 seconds and used 171.358MB of memory
Psalm was able to infer types for 100% of the codebase
$ ./vendor/bin/psalm --version
Psalm 4.3.1@2feba22a005a18bf31d4c7b9bdb9252c73897476
$ php -v
PHP 7.3.25 (cli) (built: Dec 11 2020 09:22:30) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans