【独学エンジニア備忘録】PHPのデバックツール

<h2>①Xdebug

デバック（バグの原因を見つける）作業を手伝ってくれるものはデバックツール中でもXdebugは定番。以下の特徴あり
<ul>
<li>コードにブレークポイントを設定して1行づつアプリを動かせる
<li>ブレークポイントごとに変数の中身が見れる
<li>エラーの詳細を表示
<li>VSCodeとともに使える

<h2>②PHP_CodeSniffer

プログラミングを実行せずにバグの発生、コードの可読性、コーディング規約をチェックして守れていないコードの検出と自動修正できる。
実行時の検出は難しい
<ul>
<li>ダウンロード
composerでダウンロードする。まず、composerを初期化

```composer.bash
root@291312475e1b:/var/www/html# composer init
```

するとvender/composer.jsonというファイルが出来上がる

```composer.json
{
    "name": "root/html",
    "autoload": {
        "psr-4": {
            "Root\\Html\\": "src/"
        }
    },
    "require": {}
}
```

そして以下のように修正。require-devは開発環境にのみ適用の意味。

```composer.json
{
    "name": "root/html",
    "require": {},
    "require-dev": {
        "squizlabs/php_codesniffer": "3.*"
    }
}
```

最後にインストールをして準備完了

```composer.bash
root@291312475e1b:/var/www/html# composer install
```

これでPHP_CodeSnifferの使用できるようになった。実際の使い方はファイルの指定を行ってPHPCodeSnifferを呼び出すだけ。以下公式ドキュメント参照
https://github.com/squizlabs/PHP_CodeSniffer

```composer.bash
root@291312475e1b:/var/www/html# phpcs ファイル名
#ドキュメント全体をチェックするときは
# phpcs フォルダ名
#例えばコードをPSR-12のstandardに照らし合わせる場合は以下のようなコマンド実行
#phpcs --standard=PSR12 ファイル名
```

試しに、以下のようなファイルのコードがPSR-12に違反しているか確認してみる


```example.php
<?php
const price = 100;

if($v === 1) echo 'hello';
/*以下コマンドでPHPCodeSniffer実行
./vendor/bin/phpcs --standard=PSR12 example.php
以下実行結果
FILE: /var/www/html/example.php
-----------------------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 3 LINES
-----------------------------------------------------------------------------------
 1 | ERROR | [x] Header blocks must be separated by a single blank line
<?phpの後に1行開けていない
 2 | ERROR | [ ] Class constants must be uppercase; expected PRICE but found price
定数定義のときは大文字でなければいけない
 4 | ERROR | [x] Expected 1 space(s) after IF keyword; 0 found
IFのあとに1つ半角スペースが必要
 4 | ERROR | [x] Inline control structures are not allowed
改行が必要

-----------------------------------------------------------------------------------
PHPCBF CAN FIX THE 3 MARKED SNIFF VIOLATIONS AUTOMATICALLY
-----------------------------------------------------------------------------------

Time: 220ms; Memory: 6MB
*/
```

色々なオプションが付与できるが毎回書くのも面倒なのでxmlファイルに設定しておく。
https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset

```phpcs.xml
<?xml version="1.0"?>
<ruleset name="Custom PSR12">
<!--ルール名をセット -->
  <description>A custom psr12</description>
　<!--どういう設定かを記述 -->
  <file>./</file>
　<!--チェックするファイルやディレクトリを記述。今回はワーキングディレクトリ以下すべてを指定 -->
  <exclude-pattern>./vender/*</exclude-pattern>
　<!--チェックから除外するファイルやディレクトリを記述。今回はcomposerでダウンロードしたファイルは無視 -->
  <arg name="colors"/>
  <arg value="s"/>
　　<!--オプションを指定。今回は色を付けるオプションと何の違反をしているかの記述するオプションを指定 -->
  <rule ref="PSR12"/>
　　<!--規約を指定 -->
</ruleset>
```

設定後に以下ファイルのコードをチェック

```example.php
<?php

const price = 100;

if ($v === 1) echo 'hello';
```

```phpcs.bash
#以下コマンドでPHPCodeSniffer実行
root@291312475e1b:/var/www/html# ./vendor/bin/phpcs --standard=phpcs.xml example.php
```

以下実行結果。エラーに色が付いている、何の規約に違反しているかが書いてある。
![スクリーンショット 2021-11-07 8.48.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661879/84bb5a96-fc7b-76e4-55a5-29a5e19051ca.png)

余計なルールを無効化にすることも可能。例として定数が小文字でもいいようにする。

```phpcs.xml
<?xml version="1.0"?>
<ruleset name="Custom PSR12">
  <description>A custom psr12</description>

  <file>./</file>
  <exclude-pattern>./vender/*</exclude-pattern>
  <arg name="colors"/>
  <arg value="s"/>
  <rule ref="PSR12">
    <exclude name="Generic.NamingConventions.UpperCaseConstantName.ClassConstantNotUpperCase"/>
　<!--ルール名を指定 -->
  </rule>
</ruleset>
```

![スクリーンショット 2021-11-07 8.55.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661879/b9242f00-a60c-84ec-500c-10b68542ed3f.png)

もう少し楽な方法としてcompserで楽にできるようにする。composer.jsonにスクリプトを設定。phpcsとコマンドを打つと””内のコマンドを実行できるようになる。

```composer.json
{
    "name": "root/html",
    "require": {},
    "require-dev": {
        "squizlabs/php_codesniffer": "3.*"
    }
    "scripts": {
        "phpcs": "./vendor/bin/phpcs --standard=phpcs.xml"
    }
}
```

```phpcs.bash
#以下コマンドでPHPCodeSniffer実行
root@291312475e1b:/var/www/html# composer phpcs example.php 
```

<h2>③PHPStan

以下の機能がある。似たようなものにphp phanがある
<ul>
<li>未定義の変数
<li>関数の引数の数
<li>型の不備

composerからインストール。下記参照
https://github.com/phpstan/phpstan

```composer.bash
root@291312475e1b:/var/www/html# composer require --dev phpstan/phpstan
```
試しに以下のファイルを読み込ませてみる

```examole.php
<?php

$argString = 'yoshida';

function sayHello(string $argString, $name):void{
    echo 'hello' . $argString . PHP_EOL;
}
```

```phpstan.bash
root@291312475e1b:/var/www/html# ./vendor/bin/phpstan analyse example.php 
```

![スクリーンショット 2021-11-07 17.43.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661879/26052021-80f2-b366-2fc7-a7876e03641c.png)
どうやら構文エラーでないため、OKがでている。オプションにレベルが設定ができるようなので試しに最大の9で再実行するとエラーになった。
関数の引数の型と関数の返り値の型が宣言されていない、あと関数の引数の数があっていないからと思われる。

```phpstan.bash
root@291312475e1b:/var/www/html# ./vendor/bin/phpstan analyse -l 9 example.php 
```

![スクリーンショット 2021-11-07 17.46.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661879/8f064ad1-c284-2dd7-e5c8-8cd6796e14e0.png)

レベルやパスの設定をphpstan.neonで一括設定できる。以下設定内容（スペースとタブが混在しているとエラーになるので注意）。

```phpstan.neon
parameters:
  level: 9
  paths:
    - .
  excludePaths:
    - vendor

```

levelはコードレベルチェック、pathsは対象のディレクトリを指定、excludePathsは指定したディレクトリの中で無視したいディレクトリを選択できる。もしエラーを無視したい場合はコードに以下を記載する。

```ignore.php
function () {
	/** @phpstan-ignore-next-line */
	echo $foo;

	echo $foo; /** @phpstan-ignore-line */

	/* @phpstan-ignore-next-line */
	echo $foo;

	echo $foo; /* @phpstan-ignore-line */

	// @phpstan-ignore-next-line
	echo $foo;

	echo $foo; // @phpstan-ignore-line
};
```


最後に、コマンドが長いのでcomposerのスクリプトオブジェクトにコマンドを登録する。

```composer.json
"phpstan": "./vendor/bin/phpstan analyse"
```

```phpmd.bash
#以下コマンドでPHPStan実行可能
root@291312475e1b:/var/www/html# composer phpstan
```

<h2>④PHPMD

以下の機能がある
<ul>
<li>バグの検知
<li>汚いコードの検知
<li>複雑なコードの検知
<li>使用していない引数や関数の検知

以下のコードをcomposer.jsonのrequire-devに追記

```composer.json
"phpmd/phpmd" : "@stable"
```

すでにcomposer.lockが存在（既にcomposer installを実行した後）は以下のコマンドで追記した機能をインストール

```
root@291312475e1b:/var/www/html# composer update
#以下ヘルプを出すコマンド
root@291312475e1b:/var/www/html# ./vendor/bin/phpmd --help
Mandatory arguments:
1) A php source code filename or directory. Can be a comma-separated string
2) A report format
3) A ruleset filename or a comma-separated string of rulesetfilenames

Example: phpmd /path/to/source format ruleset

Available formats: ansi, baseline, checkstyle, github, html, json, sarif, text, xml.
Available rulesets: cleancode, codesize, controversial, design, naming, unusedcode.

Optional arguments that may be put after the mandatory arguments:
--minimumpriority: rule priority threshold; rules with lower priority than this will not be used
--reportfile: send report output to a file; default to STDOUT
--suffixes: comma-separated string of valid source code filename extensions, e.g. php,phtml
--exclude: comma-separated string of patterns that are used to ignore directories. Use asterisks to exclude by pattern. For example *src/foo/*.php or *src/foo/*
--strict: also report those nodes with a @SuppressWarnings annotation
--ignore-errors-on-exit: will exit with a zero code, even on error
--ignore-violations-on-exit: will exit with a zero code, even if any violations are found
--generate-baseline: will generate a phpmd.baseline.xml next to the first ruleset file location
--update-baseline: will remove any non-existing violations from the phpmd.baseline.xml
--baseline-file: a custom location of the baseline file
```

コマンドの形式は　phpmd [ファイル名　or ディレクトリ] [レポート形式] [ルールセットファイル]
レポート形式はansi、html、json、text、xmlから選択。
ルールセットは以下から選択。ファイルが./vendor/phpmd/phpmd/src/main/resources/rulesets/に存在する。それぞれのルールの詳しい解説は以下リンク参照
https://phpmd.org/rules/index.html

子ルールというものが存在する。
cleancode：
codesize：
controversial：
design：
naming：
unusedcode：


試しに以下のコードをチェックしてみる。

 ```example.php
<?php

function sayHello($arg_string){
    $s = 'world';
    echo 'hello' . $arg_string . PHP_EOL;
}
```

```phpmd.bash
root@291312475e1b:/var/www/html# ./vendor/bin/phpmd example.php text cleancode,codesize,controversial,design,naming,unusedcode
/var/www/html/example.php:3     The parameter $arg_string is not named in camelCase.
/var/www/html/example.php:3     The variable $arg_string is not named in camelCase.
/var/www/html/example.php:4     Avoid variables with short names like $s. Configured minimum length is 3.
/var/www/html/example.php:4     Avoid unused local variables such as '$s'.
```

以下のオプションがよく使う。
--suffixes：拡張子を設定。phpなど。
--exclude：検査対象からはずすディレクトリを設定

続いて、ルールセットファイルの作成

```ruleset.xml
<?xml version="1.0"?>
<ruleset name="PHPMD rule set"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
                       http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="
                       http://pmd.sf.net/ruleset_xml_schema.xsd">
  <description>

  </description>

  <rule ref="rulesets/codesize.xml" />
  <rule ref="rulesets/cleancode.xml" />
  <rule ref="rulesets/controversial.xml" />
  <rule ref="rulesets/design.xml" />
  <rule ref="rulesets/naming.xml" />
  <rule ref="rulesets/unusedcode.xml" />
</ruleset>
```
ruleタグに設定したい親ルールを設定する。親ルールの中で無視したい子ルールがあったら
<exclude name = "子ルール名" />をruleタグに追加する。

最後に、コマンドが長いのでcomposerのスクリプトオブジェクトにコマンドを登録する。

```composer.json
"phpmd": "./vendor/bin/phpmd . text rulesets.xml --suffixes php --exclude vendor"
```

```phpmd.bash
#以下コマンドでPHPM実行可能
root@291312475e1b:/var/www/html# composer phpmd
```