LoginSignup
14
14

More than 5 years have passed since last update.

phpdbgのバックトレースが読みにくいのでコマンドを自作する

Last updated at Posted at 2016-05-04

.phpdbginitという名前のファイルをカレントディレクトリに置いておくと、phpdbg起動時に読み取って勝手に設定してくれる。
ブレークポイントの設定 (break 関数名)などを書くのが定番だけど、関数を作ってregisterしておくこともできて、適当にbtっていうスタックトレースを表示する関数を作ってみた。

こんな風に <: 〜 :>でくくった部分はPHPとして実行され、関数の登録ができる。

.phpdbginit
<:
function bt() {
    $bt = debug_backtrace();
    foreach ($bt as $i => $trace) {
        echo "$i => ";
        if (isset($trace['class'])) {
            echo "\033[36m$trace[class]\033[m$trace[type]";
        }
        echo "\033[32m$trace[function]\033[m(";
        $args = [];
        foreach ($trace['args'] as $arg) {
            switch ($type = gettype($arg)) {
                case 'resource':
                    $args[] = 'resource<' . get_resource_type($arg) . '>';
                    break;
                case 'object':
                    $args[] = get_class($arg);
                    break;
                case 'array':
                    $j = 0;
                    $itype = null;
                    $isArray = true;
                    $size = count($arg);
                    if (!$size) {
                        $args[] = '[]';
                        break;
                    }
                    foreach ($arg as $i => $val) {
                        if ($i !== $j++) {
                            $isArray = false;
                        }
                        if (is_scalar($val)) {
                            $thistype = gettype($val);
                        } elseif (is_array($val)) {
                            $thistype = 'array';
                        } elseif (is_object($val)) {
                            $thistype = get_class($val);
                        } elseif (is_resource($val)) {
                            $thistype = 'resource<' . get_resource_type($val) . '>';
                        } else {
                            $thistype = 'mixed';
                        }
                        if (!$itype) {
                            $itype = $thistype;
                        } elseif ($itype !== $thistype) {
                            $itype = 'mixed';
                            break;
                        }
                    }
                    if ($isArray) {
                        $args[] = $itype . '[' . $size . ']';
                    } else {
                        $args[] = $itype . '{' . $size . '}';
                    }
                    break;
                default:
                    $args[] = json_encode($arg, 448);
                    break;
            }
        }
        echo implode(", ", $args);
        if (isset($trace['file'])) {
            $file = basename($trace['file']);
        } else {
            $file = '';
        }
        echo "):\033[33m$file\033[m:\033[36m$trace[line]\033[m";
        echo PHP_EOL;
    }
}
:>
register bt

色付は趣味。

標準にbackというコマンドがあってバックトレースを表示してくれるんだけど、引数も全部キャプチャしてvar_dumpするので、複雑な引数を渡されると、訳がわからないことになる。

// 凄い長さで続く
9,[] => 32,[] => Symfony\Component\Console\Formatter\OutputFormatter Object ([] => 1,[] => Array ([error] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 37,[unset] => 39),[] => Array ([set] => 41,[unset] => 49),[] => Array ()),[info] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 32,[unset] => 39),[] => ,[] => Array ()),[comment] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 33,[unset] => 39),[] => ,[] => Array ()),[question] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 30,[unset] => 39),[] => Array ([set] => 46,[unset] => 49),[] => Array ()),[highlight] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 31,[unset] => 39),[] => ,[] => Array ()),[warning] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 30,[unset] => 39),[] => Array ([set] => 43,[unset] => 49),[] => Array ())),[] => Symfony\Component\Console\Formatter\OutputFormatterStyleStack Object ([] => Array (),[] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => ,[] => ,[] => Array ())))),[] => Resource id #78,[] => 32,[] => Symfony\Component\Console\Formatter\OutputFormatter Object ([] => 1,[] => Array ([error] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 37,[unset] => 39),[] => Array ([set] => 41,[unset] => 49),[] => Array ()),[info] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 32,[unset] => 39),[] => ,[] => Array ()),[comment] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 33,[unset] => 39),[] => ,[] => Array ()),[question] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 30,[unset] => 39),[] => Array ([set] => 46,[unset] => 49),[] => Array ()),[highlight] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 31,[unset] => 39),[] => ,[] => Array ()),[warning] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => Array ([set] => 30,[unset] => 39),[] => Array ([set] => 43,[unset] => 49),[] => Array ())),[] => Symfony\Component\Console\Formatter\OutputFormatterStyleStack Object ([] => Array (),[] => Symfony\Component\Console\Formatter\OutputFormatterStyle Object ([] => ,[] => ,[] => Array ()))))) at /Users/hiraku/src/github.com/hirak/composer/vendor/symfony/console/Application.php:123
frame #13: Composer\Console\Application->run() at /Users/hiraku/src/github.com/hirak/composer/src/Composer/Console/Application.php:99
frame #14: {main} at /Users/hiraku/src/github.com/hirak/composer/bin/composer:44

上記の自作btであれば、引数はオブジェクトならクラス名だけ表示する感じで省略するので、大分読みやすくなる。

phpdbg> bt
0 => bt():RemoteFilesystem.php:99
1 => Composer\Util\RemoteFilesystem->getContents("packagist.jp", "https://packagist.jp/packages.json", false):ComposerRepository.php:645
2 => Composer\Repository\ComposerRepository->fetchFile("https://packagist.jp/packages.json", "packages.json"):ComposerRepository.php:462
3 => Composer\Repository\ComposerRepository->loadRootServerFile():ComposerRepository.php:256
4 => Composer\Repository\ComposerRepository->hasProviders():Pool.php:99
5 => Composer\DependencyResolver\Pool->addRepository(Composer\Repository\ComposerRepository, array):Installer.php:359
6 => Composer\Installer->doInstall(Composer\Repository\InstalledFilesystemRepository, Composer\Repository\CompositeRepository, Composer\Repository\PlatformRepository, array):Installer.php:215
7 => Composer\Installer->run():UpdateCommand.php:172
8 => Composer\Command\UpdateCommand->execute(Symfony\Component\Console\Input\ArgvInput, Symfony\Component\Console\Output\ConsoleOutput):Command.php:259
9 => Symfony\Component\Console\Command\Command->run(Symfony\Component\Console\Input\ArgvInput, Symfony\Component\Console\Output\ConsoleOutput):Application.php:844
10 => Symfony\Component\Console\Application->doRunCommand(Composer\Command\UpdateCommand, Symfony\Component\Console\Input\ArgvInput, Symfony\Component\Console\Output\ConsoleOutput):Application.php:192
11 => Symfony\Component\Console\Application->doRun(Symfony\Component\Console\Input\ArgvInput, Symfony\Component\Console\Output\ConsoleOutput):Application.php:209
12 => Composer\Console\Application->doRun(Symfony\Component\Console\Input\ArgvInput, Symfony\Component\Console\Output\ConsoleOutput):Application.php:123
13 => Symfony\Component\Console\Application->run(null, Symfony\Component\Console\Output\ConsoleOutput):Application.php:99
14 => Composer\Console\Application->run():composer:44

とりあえず満足した。

14
14
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
14
14