Xdebug3 var_dumpもきれいに表示したいしデバッグもしたいし、というときの設定

Xdebugがバージョン3になってました。

https://xdebug.org/

環境は、Windows+PHPStorm+PHP7.4(Xampp)です。

PHP7.2→PHP7.4 にしたくて、Xamppを新しくし、Xdebugを設定しなおして気づきました。

まず、PHPStormでデバッグできず、ちょっとはまりました。

注意点は

①PHPStormのバージョンが2020.3以降じゃないとXdebug3に対応していない
②ポート番号がデフォルト9003になっている

です。

さて、表題の話なんですが、まず、デバッグしたいために最初は次のようにphp.iniを設定していました。

zend_extension = D:\xampp2\php\ext\php_xdebug-3.0.1-7.4-vc15-x86_64.dll
xdebug.remote_enable=1
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9001
xdebug.var_display_max_children=-1
xdebug.var_display_max_data=-1
xdebug.var_display_max_depth=-1
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9001
xdebug.mode = debug

最後のxdebug.modeがポイントです。

xdebug.mode = debug

にしないとPHPStormでデバッグできません。(ほかのIDEで試してないのでほかのIDEでどうかわかりません。)

しかし、このままにしておくと、PHPerは必ず使うであろう、var_dump関数の実行結果が美しく表示されません。

きれいに表示されないvar_dumpの結果
きれいに表示されないvar_dumpの結果

こんなん見てられないし、辛いですよね~(>_<)


xdebug.mode = develop

にすると、美しく整形されて表示されます。developがデフォルトだそうです。

美しく出力されたvar_dumpの結果。これならだれでもわかるね!⊂(^-^)⊃

しかし、このままではデバッグできません。

一体どうして…。

と、ぼんやりXdebugの作者のDerickさんのTwitterを見ていたら

Xdebug3のModeについて説明動画があるじゃないですか!!!

Xdebugを作ってくれているだけでもありがたいのに、動画まで…。その優しさに涙が溢れますね…。(>_<)

というわけで、上記を見ると、modeが二つ平行で設定できることがわかります。

xdebug.mode = develop,debug

上記のように設定すると、var_dumpも美しく出力され、デバッグもできました!⊂(^-^)⊃

ちな、Xdebug関係のphp.iniの設定を下記に書いておきます。(私はデバッグのポートを9001で運用しています。)

[xdebug]
zend_extension = D:\xampp2\php\ext\php_xdebug-3.0.1-7.4-vc15-x86_64.dll
xdebug.remote_enable=1
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9001
xdebug.var_display_max_children=-1
xdebug.var_display_max_data=-1
xdebug.var_display_max_depth=-1
xdebug.client_host = 127.0.0.1
xdebug.client_port = 9001
xdebug.mode = develop,debug

php.iniを変更した後は、Webサーバーの再起動を忘れないように!

ありがとう、Derickさん!ロンドンいろいろ大変そうですが、がんばってください。

Smartyでクラス定数を使いたい

表題みたいなことがあります。

下は 物凄く雑ですがクラス定数を宣言

namespace Mental;

class Menhealer {
    const YABAI = 1; 
    const MURI = 2;
    const MOUIYA = 3;
    const KIDUITE = 4;
    const WAKATTEYO = 5;
}

これをSmarty側で呼び出す方法は以下です

{"Mental\Menhealer::YABAI"|constant}

if文だとこう書くらしいです。

{if $menhealer === constant("Mental\Menhealer::KIDUITE"}
    努力はしている
{/if}

クラス定数使うとわかりやすいですが、Smartyだと今のところuseが使えないのもあって長くなるのが難点ですね。

WordPress高速化に使えるプラグイン

会社のWordpressサイトをPageSpeed Insightsでしらべてみたところ、点数がとても低いので対策しました。

いろいろ調査して試してみたところ、AutoptimizeとWP Fastest Cacheという2つのプラグインが応答速度改善に効果がありました。

基本的にAutoptimizeでできることはAutoptimizeに任せていますが、これだけだとページのロードが遅いです。
ページをキャッシュしてロードを早くするためにWP Fastest Cacheを使っています。

Autoptimize/WP Fastest Cacheは下記のように設定しました。

Autoptimize

WP Fastest Cache

PHPUnit require_once地獄からの脱出 2 autoloadを使うんや編

前回、PHPUnit require_once地獄からの脱出 1 まずはrequire_onceでテスト元のファイルをどう読み込むか編 で大分長々と書きましたが、PHPUnitでテストファイルからrequire_onceでテスト元のファイルを読みだすのが面倒だという話です。

どうすればいいのかといいますと、phpunit.xmlを下記のように書き換えます。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit
        bootstrap = "vendor/autoload.php"
        colors = "true">
</phpunit>

下記が肝心の部分です。

bootstrap = "vendor/autoload.php"

ついでに、色がつくようにしています。

colors = "true"

緑の光あれ。

MonkeyTest.phpから、

require_once “class/Monkey.php”;

を消してみます。

<?php

use MonkeyWorld\Monkey; //追加
use PHPUnit\Framework\TestCase;

class MonkeyTest extends TestCase
{

    public function testScream()
    {
        $monkey = new Monkey();
        ob_start();
        $monkey->scream();
        $actual = ob_get_clean();
        $expected = 'ウキー!!!';
        $this->assertEquals($expected, $actual);
    }

}

testScreamを実行してみます。

OKです!緑の色もついて、みやすいですね!( ˊᵕˋ )

テスト元のMonkey.php に talkToChimpanzee()というメソッドが追加されました。

<?php
namespace MonkeyWorld;

class Monkey
{

    public function scream(){
        echo "ウキー!!!";
    }

    public function talkToChimpanzee(){
        Chimpanzee::talk();
    }

MonkeyTest.phpもtalkToChimpanzeeをテストできるように書き換えます。

use PHPUnit\Framework\TestCase;

class MonkeyTest extends TestCase
{

    public function testScream()
    {
        $monkey = new Monkey();
        ob_start();
        $monkey->scream();
        $actual = ob_get_clean();
        $expected = 'ウキー!!!';
        $this->assertEquals($expected, $actual);
    }

   public function testTalkToChimpanzee()
    {

        $monkey = new Monkey();
        ob_start();
        $monkey->talkToChimpanzee();
        $actual = ob_get_clean();
        $expected = 'こんにちは。おいらチンパンジーだよ。';
        $this->assertEquals($expected, $actual);

    }
}

今度はMonkeyTest.phpのMonkeyTest.classをテストとして実行してみます。

OKですね!

ちなみに、上記はPHPStormから実行していますが、コマンドプロンプトから実行すると、次のようになります。

phpunitの後に引数をつけずに、


phpunit tests/MonkeyTest.php

とするだけです 。

PHPUnitの設定ファイル、phpunit.xmlで実行の初期に

ところで、実験的にclass/Hoge.phpというやつを追加します。

<?php

class Hoge
{

    public function talk(){
        print "おいらHogeクラスです";
    }
}

こいつには、namespaceの宣言がないことに注意してください。

Monkey.phpにtalkToHogeというメソッドを追加します。

<?php
namespace MonkeyWorld;

class Monkey
{

    public function scream(){
        echo "ウキー!!!";
    }

    public function talkToChimpanzee(){
        Chimpanzee::talk();
    }

    public function talkToHoge(){
        Hoge::talk();
    }
}

MonkeyTest.phpに次のテストメソッドを足します。


    public function testTalkToHoge()
    {

        $monkey = new Monkey();
        ob_start();
        $monkey->talkToHoge();
        $actual = ob_get_clean();
        $expected = 'おいらHogeクラスです';
        $this->assertEquals($expected, $actual);

    }

MonkeyTestクラスを実行します。

Error : Class 'MonkeyWorld\Hoge' not found
D:\xampp\htdocs\autoloadSample\class\Monkey.php:16
D:\xampp\htdocs\autoloadSample\tests\MonkeyTest.php:38

というエラーが出て、実行が失敗したみたいです。(>_<)

というか、そもそも普通にこれはブラウザからPHPを実行しても実行できません。最初のサンプルでも使った、トップディレクトリにあるhoge.phpを実行します。

ディレクトリ・ファイル構成

hoge.phpは次の通りです。

<?php

require_once "vendor/autoload.php";

use MonkeyWorld\Monkey;
require_once "class/Hoge.php";

$monkey = new Monkey();
$monkey->scream();
echo "<br>";

$monkey->talkToChimpanzee();
$monkey->talkToHoge();

これを実行すると次のようになります。

 Fatal error: Cannot declare class Hoge, because the name  is already in use in D:\xampp\htdocs\autoloadSample\class\Hoge.php on  line 3

というエラーが出て実行できません。

あんまり深堀りできてないですが、これ、Hogeクラスが重複してますよってエラーなんですよね。なんででしょうか。わかる人、教えてください。m(_ _)m

仕方ないので、Hoge.phpに次のようにnamespaceをつけます。

<?php
namespace MonkeyWorld;

class Hoge
{

    public function talk(){
        print "おいらHogeクラスです";
    }
}

すると、エラーもなく実行できるようになります。

hoge.phpの実行結果↓

PHPUnitの実行結果↓

namespaceは大変大事ですね。

ちなみに、autoloadで読み込むnamespaceの指定については、下記の記事をご参考にしてみてください。

PHP require_onceを使わない、 autoloadを使ってクラスを読み込む方法 

PHPUnit require_once地獄からの脱出 1 まずはrequire_onceでテスト元のファイルをどう読み込むか編

前回、PHPUnit require_once地獄から脱出したい!という理由で、autoloadについて紹介しました。

まぁ、まだあわてるような時間じゃない。( ˊᵕˋ )  本題のPHPUnitで使うのがどうやるかって話をゆっくりとしていきます。

ということで、そもそもPHPUnitというかPHPでのファイル読み込みがどうなっているかを書いておきたいと思います。

require_once地獄は、結局はファイルが思うように読み込みできずに 次のエラーが出てしまう地獄です。

Warning: require_once(class/Monkey.php): failed to open stream: No such file or directory in...

なぜこうなってしまうのかをサンプルを使って紐といていきます。

というわけで、まずは、前回の「PHP require_onceを使わない、 autoloadを使ってクラスを読み込む方法」で使ったのと同じサンプルを使います。

下記に、tests/MonkeyTest.phpというディレクトリとphpファイルを置きました。

MonkeyTest.phpの中身は下記の通り。

<?php

use PHPUnit\Framework\TestCase;

require_once "../class/Monkey.php";

class MonkeyTest extends TestCase
{

    public function testScream()
    {
        $monkey = new Monkey();
        ob_start();
        $monkey->scream();
        $actual = ob_get_clean();
        $expected = 'ウキー!!!';
        $this->assertEquals($expected, $actual);
    }
}

require_once “../class/Monkey.php”;

にご注目ください。MonkeyTest.phpから見て、テスト元のファイルである、Monkey.phpを相対パスで指定しています。

テスト元のファイル、Monkey.phpは次の通りです。

<?php
namespace MonkeyWorld;

class Monkey
{

    public function scream(){
        echo "ウキー!!!";
    }
}

で、Webサーバーにインストール済みのPHPUnitを走らせます。
PHPStormのPHPUnitを走らせる設定は、下記の場所にあります。 
ファイル→Settings→Languages&Frameworks→PHP→Test Frameworks

ここでは、私はWindows10でXamppを使って開発してますんで、ここにすでにインストールしてあったphpunitのpharファイルを使います。

D:\xampp\php\phpunit.phar

pharファイルとは、かみ砕いていうと、Windowsで言うexeファイルみたいなものです。これを実行するとPHPUnitが実行できるというわけです。

PHPStormからは、下記の赤丸の部分にある、再生みたいな緑の三角のボタンをクリックで、テストがメソッド単位で実行できます。(PHPStorm使ってないよ!という方は後でコマンドプロンプトからやる方法書いてますので、スルーしてください。)

クリックすると下記のような画面が開いて、MonkeyTest.testScream の実行の設定をしてください、と出ます。

Interpreterとは、PHPの実行環境です。

ここではサンプルなので、次のように指定しておきます。

Use alternative configuration fileを指定しないと、
Error:Path to conficuration file should be specified in … というエラーが出てダメだったので、図の下にあるように、phpunit.xmlを適当に作ります。

下記がphpunit.xmlです。ちなみに、このファイルはPHPUnitをどう実行するかを決めるとても大切なファイルです。あとでちゃんとやりますが、ここではもうこれ以上設定をなくせないぐらいのミニマムな設定で、とりあえずおいておきます。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
</phpunit>

phpunit.xmlはディレクトリのトップにおきます。

やっと、MonkeyTestのtestScream()を実行することができます!

(;゚∀゚)=3ハァハァ、ここまで長かった…。

Shift+F10でテストが実行できます。

すると、残念!

Warning: require_once(../class/Monkey.php): failed to open stream: No such file or directory in D:\xampp\htdocs\autoloadSample\tests\MonkeyTest.php on line 7
Call Stack:
0.0087 898656 1. {main}() D:\xampp\php\phpunit.phar:0
0.0965 10543104 2. PHPUnit\TextUI\Command::main() D:\xampp\php\phpunit.phar:660
0.0965 10551968 3. PHPUnit\TextUI\Command->run() phar://D:/xampp/php/phpunit.phar/phpunit/TextUI/Command.php:69
0.0986 10557432 4. PHPUnit\TextUI\TestRunner->getTest() phar://D:/xampp/php/phpunit.phar/phpunit/TextUI/Command.php:81
0.0992 10595224 5. PHPUnit\Framework\TestSuite->addTestFiles() phar://D:/xampp/php/phpunit.phar/phpunit/Runner/BaseTestRunner.php:81
0.0992 10595224 6. PHPUnit\Framework\TestSuite->addTestFile() phar://D:/xampp/php/phpunit.phar/phpunit/Framework/TestSuite.php:340
0.0992 10595224 7. PHPUnit\Util\FileLoader::checkAndLoad() phar://D:/xampp/php/phpunit.phar/phpunit/Framework/TestSuite.php:267
0.0992 10595432 8. PHPUnit\Util\FileLoader::load() phar://D:/xampp/php/phpunit.phar/phpunit/Util/FileLoader.php:40
0.0994 10623056 9. include_once('D:\xampp\htdocs\autoloadSample\tests\MonkeyTest.php') phar://D:/xampp/php/phpunit.phar/phpunit/Util/FileLoader.php:49

上記のようなエラーが出て、../class/Monkey.php が読み込めませんでした、と出ますね。

これは、コマンドプロンプトでPHPUnitを次のように走らせた場合と同じです。

D:\xampp\htdocs\autoloadSample>phpunit testScream tests/MonkeyTest.php

( テストをメソッド単位で走らせるには、メソッド名をファイル名の前に置きます。)

つまり、PHPUnitはプロジェクトのトップ(ここではD:\xampp\htdocs\autoloadSample)で実行されているので、MonkeyTest.phpで指定するテスト元のファイルの指定は一番最初に実行されるので、Monkey.phpの読み込み指定は、プロジェクトのトップから行わないといけないわけですね。

それでは、次のようにMonkeyTest.phpを変更します。


<?php

use PHPUnit\Framework\TestCase;

require_once "class/Monkey.php"; //書き換え

class MonkeyTest extends TestCase
{

    public function testScream()
    {
        $monkey = new Monkey();
        ob_start();
        $monkey->scream();
        $actual = ob_get_clean();
        $expected = 'ウキー!!!';
        $this->assertEquals($expected, $actual);
    }
}

Shift + F10で実行します。


Testing started at 12:37 …
D:\xampp\php\php.exe D:\xampp\php\phpunit.phar --configuration D:\xampp\htdocs\autoloadSample\phpunit.xml --filter "/(MonkeyTest::testScream)( .*)?$/" --test-suffix MonkeyTest.php D:\xampp\htdocs\autoloadSample\tests --teamcity
PHPUnit 8.5.8 by Sebastian Bergmann and contributors.
Error : Class 'Monkey' not found
D:\xampp\htdocs\autoloadSample\tests\MonkeyTest.php:12
Time: 98 ms, Memory: 12.00 MB
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
Process finished with exit code 2

エラーですね…。

「結局、Class ‘Monkey’ not found って出ますけど!なんなんですか!!!」

まぁまぁ、まだあわてるような時間じゃないって冒頭に言いましたね。( ˊᵕˋ )

テスト元のファイル、Monkey.phpをよく見てみると

<?php
namespace MonkeyWorld;

class Monkey
{

    public function scream(){
        echo "ウキー!!!";
    }
}
namespace MonkeyWorld;

ってなってるんですよね。前回の投稿、PHP require_onceを使わない、 autoloadを使ってクラスを読み込む方法 で、MonkeyクラスはMonkeyWorldというnamespaceの中のクラスになっていたのでした。

というわけで、次のようにMonkeyTest.phpを書き換えます。

<?php

use MonkeyWorld\Monkey; //追加
use PHPUnit\Framework\TestCase;

require_once "class/Monkey.php";

class MonkeyTest extends TestCase
{

    public function testScream()
    {
        $monkey = new Monkey();
        ob_start();
        $monkey->scream();
        $actual = ob_get_clean();
        $expected = 'ウキー!!!';
        $this->assertEquals($expected, $actual);
    }
}

Shift+F10で実行します。

Time: 97 ms, Memory: 12.00 MB
OK (1 test, 1 assertion)
Process finished with exit code 0

となって、やっとOKが出ました!⊂(^-^)⊃

コマンドプロンプトからも実行します。

OKです!!

しかし、上記は上記のようにやって事なきを得ましたが、実際は例えばクラスからほかのクラスを読み込んだり、実際に動作するプログラムでの実行時に読み込まれるファイルがいっぱいあったりして、それらをrequire_onceでファイルパスを考えてどうにかするのはかなり大変なのです。

そこで、autoloadが活躍します。が、長くなったので続きます…。

間違いなどありましたら、お気軽にご指摘ください。

秋の山って気持ちいいですね!

次回はこちら↓