パーフェクトPHP デバッグ (フレームワーク サンプルコード)

NetBeans デバッグ方法

2019年06月17日 公開

2021年01月14日 更新


NetBeans デバッグ方法 (変数の値と処理の流れを調べる) オートロード

デバッグの基本的な使い方です。


デバッグ例

例 ClassLoader.php オートロード

操作

デバッグ
ClassLoader.php 27行目 $dir$this->dirs[] の値を調べる
ClassLoader.php 37行目 foreach の動きを調べる
index.php
1    <?php
2 
3    require '../bootstrap.php';
4    require '../MiniBlogApplication.php';
5 
6    $app = new MiniBlogApplication(false);
7    $app->run();
8 

ClassLoader.php (registerDir)
25    public function registerDir($dir)
26    {
27        $this->dirs[] = $dir;
28    }

ClassLoader.php (loadClass)
35    public function loadClass($class)
36    {
37        foreach ($this->dirs as $dir) {
38            $file = $dir . '/' . $class . '.php';
39            if (is_readable($file)) {
40                require $file;
41
42                return;
43            }
44        }
45    }
ブレークポイント 設定
ファイル
index.php 3 処理の流れ を確認するため (省略可)
index.php 4 処理の流れ を確認するため (省略可)
ClassLoader.php 27 -
ClassLoader.php 37 -
処理の流れ
アクション ファイル 変数の値 (他)
開始 (Ctrl+F5) index.php 3 require '../bootstrap.php';
ClassLoader.php registerDir($dir) $dir$this->dirs[] の値を調べる
続行 (F5) ClassLoader.php 27 $this->dirs[] = $dir;
変数 設定  (27行目 実行前)
ステップ・オーバー (F8) ClassLoader.php 28 }
変数 設定  (27行目 実行後)
変数の上にマウス・ポインタを置くと、変数の値が表示されます
$dir
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core"
$this->dirs[0]
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core"
$this
  ClassLoader object
続行 (F5) ClassLoader.php 27 $this->dirs[] = $dir;
($this->dirs[0] は設定済)
ステップ・オーバー (F8) ClassLoader.php 28 }
$dir
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/models"
$this->dirs[0]
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core"
$this->dirs[1]
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/models"
$this
  ClassLoader object
続行 (F5) index.php 4 require '../MiniBlogApplication.php';
ClassLoader.php loadClass($class) foreach の動きを調べる
続行 (F5) ClassLoader.php 37 foreach ($this->dirs as $dir) {
$class
  "Application"
ステップ・オーバー (F8) ClassLoader.php 38 $file = $dir . '/' . $class . '.php';
$this->dirs[0]
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core"
$this->dirs[1]
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/models"
$dir
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core"
$this
  ClassLoader object
ステップ・オーバー (F8) ClassLoader.php 39 if (is_readable($file)) {
$file
  "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core/Application.php" (注 改行はされていません)
  $file = $dir . '/' . $class . '.php';

参考
$class . '.php' が models にある場合、もう一回ループ
ステップ・オーバー (F8) ClassLoader.php 40 require $file;
ステップ・イン (F7) Application.php 9 {
ステップ・イン (F7) ClassLoader.php 42 return;
index.php 6 $app = new MiniBlogApplication(false);
終了 (Shift+F5)

注意点

基本的に、デッバグ中 URL欄 を使うことはありません
ステップ・インなどの アクション を使って、処理の流れ を進めます
例外 投稿一覧 http://mini-blog.localhost/user/user3   ('フォローする' ボタン表示)


ブレークポイント ウィンドウ (右クリック)
すべて無効化 デバッグ状態 OFF  (デバッグする処理の 直前 まで OFF)
すべて有効化 デバッグ状態 ON

  すべて無効化すべて有効化 を切り替えて、効率良くデバッグができます 参照


NetBeans IDE 8.2 バグ
変数の値 変数 ウィンドウ 参照

操作

ブレークポイント
設定 ブレークポイントを設定する行の左マージンをクリックします
解除 ブレークポイントを解除するには、行番号位置の四角い図形をクリックします
ブレークポイント ウィンドウ で右クリックし、すべて削除 等を選択することもできます
変数の値
確認 変数の上にマウス・ポインタを置くと、変数の値が表示されます
確認 (詳細) 変数 ウィンドウ でも確認できます
「マウス・ポインタを置く方法」で表示されない項目も、すべて表示されます

バグ  (変数 ウィンドウサブウィンドウ)
値を表示する サブウィンドウ取消ボタン or 閉じる を使用すると、内容が変わります
(対策: 毎回 OKボタン を使用する)
正 "C:\XAMPP\xampp_5.6.31\htdocs\mini-blog.localhost/core"
誤 "C:(改行)MPP(改行)mpp_5.6.31\htdocs\mini-blog.localhost/core"
アクション
ステップ・イン (F7) 関数コールにステップ・イン  (ステップ・オーバー (F8) と使い分けます)
ステップ・オーバー (F8) 実行文をステップ・オーバー  (ステップ・イン (F7) と使い分けます)
続行 (F5) デバッグ・セッションを続行
終了 (Shift+F5) デバッグ・セッションを終了
カーソルまで実行 (F4) カーソルまで実行
デバッグ開始
メニュー デバッグ | ファイルをデバッグ をクリックします
アイコン プロジェクト(mini-blog.localhost)をデバッグ (Ctrl+F5) アイコン をクリックします
ブレークポイント ウィンドウ (右クリック)  (上記 記述済)
すべて無効化 デバッグ状態 OFF  (デバッグする処理の 直前 まで OFF)
すべて有効化 デバッグ状態 ON
変数 ウィンドウ Superglobals
Superglobals
$_POST $_POST[_token] "117d0e6d9da8ec9e595110d7e517993901ee77ce"
$_REQUEST $_REQUEST[_token] "117d0e6d9da8ec9e595110d7e517993901ee77ce"
$_SERVER $_SERVER[REQUEST_METHOD] "POST"
$_SESSION $_SESSION[csrf_tokens/account/signup][0] "117d0e6d9da8ec9e595110d7e517993901ee77ce"
変数 ウィンドウ
変数の値 列内をクリックして、変数の値を手動で変更することもできます

便利な操作

アクション
メソッドが定義されているところにジャンプ Ctrl+B または Ctrl+左クリック
カーソルの履歴 (戻る 進む) ALT+← (矢印キー)  ALT+→ (矢印キー)
bootstrap.php
1    <?php
2 
3    require 'core/ClassLoader.php';
4 
5    $loader = new ClassLoader();
6    $loader->registerDir(dirname(__FILE__).'/core');    /* Ctrl+B または Ctrl+左クリック */
7    $loader->registerDir(dirname(__FILE__).'/models');
8    $loader->register();

registerDir上で Ctrl+B または Ctrl+左クリック をすると、ClassLoader.php 25行目 にジャンプ



ClassLoader.php
25        public function registerDir($dir)    /* ALT+← (矢印キー) */
26        {
27         $this->dirs[] = $dir;
28        }

ALT+← (矢印キー) をすると、bootstrap.php 6行目 に戻る


NetBeans デバッグ方法 (変数の値を変更して 処理の流れを変える)

エラー処理の流れを追うために、意図的にエラーを発生させます。


render404Page 実行

例 処理の流れ (ログイン画面への遷移)

Application.php (run)
173    public function run()
174    {
175        try {
176            $params = $this->router->resolve($this->request->getPathInfo());
177            if ($params === false) {
178                throw new HttpNotFoundException('No route found for ' . 
    $this->request->getPathInfo());
179            }
180
181            $controller = $params['controller'];
182            $action = $params['action'];
183
184            $this->runAction($controller, $action, $params);
185        } catch (HttpNotFoundException $e) {
186            $this->render404Page($e);
187        } catch (UnauthorizedActionException $e) {
188            list($controller, $action) = $this->login_action;
189            $this->runAction($controller, $action);
190        }
191
192        $this->response->send();
193    }

$params の値を false に変更

Application.php (render404Page)
247    protected function render404Page($e)
248    {
249        $this->response->setStatusCode(404, 'Not Found');
250        $message = $this->isDebugMode() ? $e->getMessage() : 'Page not found.';
251        $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
252
253        $this->response->setContent(<<<EOF
254<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
255"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
256<html>
257<head>
258    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
259    <title>404</title>
260</head>
261<body>
262    {$message}
263</body>
264</html>
265EOF
266        );
267    }

Application.php (isDebugMode)
83    public function isDebugMode()
84    {
85        return $this->debug;
86    }
ブレークポイント 設定
ファイル
Application.php 177 -
処理の流れ
アクション ファイル 他
開始 (Ctrl+F5) Application.php 177 変数 ウィンドウ
$params の値を false に変更する
(入力 false, 表示 0)
ステップ・オーバー (F8) Application.php 178 throw new HttpNotFoundException('No route found for ' . $this->request->getPathInfo());
ステップ・オーバー (F8) Application.php 186 $this->render404Page($e);
ステップ・イン (F7) Application.php 249 $this->response->setStatusCode(404, 'Not Found');
ステップ・オーバー (F8) Application.php 250 $message = $this->isDebugMode() ? $e->getMessage() : 'Page not found.';
ステップ・イン (F7) Application.php 85 return $this->debug;
(index.php 使用)
debug の値を true に変更する (デバッグモード)
続行 (F5) ブラウザに表示 Page not found.
 or
No route found for
(デバッグモード)
終了 (Shift+F5)

forward404 実行 (POST チェック)

例 処理の流れ (アカウント登録画面 (ユーザ登録画面) & ユーザ登録)

AccountController.php (registerAction)
25    public function registerAction()
26    {
27        if ($this->session->isAuthenticated()) {
28            return $this->redirect('/account');
29        }
30
31        if (!$this->request->isPost()) {
32            $this->forward404();
33        }
34
... 省略

Request.php (isPost)
15    public function isPost()
16    {
17        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
18            return true;
19        }
20
21        return false;
22    }

Superglobals $_SERVER['REQUEST_METHOD'] の値を "GET" に変更

Controller.php (forward404)
94    protected function forward404()
95    {
96        throw new HttpNotFoundException('Forwarded 404 page from '
97            . $this->controller_name . '/' . $this->action_name);
98    }

Application.php (run)
173    public function run()
174    {
175        try {
176            $params = $this->router->resolve($this->request->getPathInfo());
17            if ($params === false) {
178                throw new HttpNotFoundException('No route found for ' . 
    $this->request->getPathInfo());
179            }
180
181            $controller = $params['controller'];
182            $action = $params['action'];
183
184            $this->runAction($controller, $action, $params);    /* registerAction in runAction */
185        } catch (HttpNotFoundException $e) {
186            $this->render404Page($e);
187        } catch (UnauthorizedActionException $e) {
188            list($controller, $action) = $this->login_action;
189            $this->runAction($controller, $action);
190        }
191
192        $this->response->send();
193    }

Application.php (render404Page)
247    protected function render404Page($e)
248    {
249        $this->response->setStatusCode(404, 'Not Found');
250        $message = $this->isDebugMode() ? $e->getMessage() : 'Page not found.';
251        $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
252
253        $this->response->setContent(<<<EOF
254<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
255"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
256<html>
257<head>
258    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
259    <title>404</title>
260</head>
261<body>
262    {$message}
263</body>
264</html>
265EOF
266        );
267    }

Application.php (isDebugMode)
83    public function isDebugMode()
84    {
85        return $this->debug;
86    }
ブレークポイント 設定
ファイル
AccountController.php 31 -
処理の流れ
アクション ファイル 他
開始 (Ctrl+F5) ログイン画面
アカウント登録 or 新規ユーザ登録 クリック
ユーザID: user4, パスワード: password
登録ボタンクリック
AccountController.php 31 if (!$this->request->isPost()) {
ステップ・イン (F7) Request.php 17 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
変数 ウィンドウ
Superglobals $_SERVER['REQUEST_METHOD']
の値を "GET" に変更する
("POST" 以外の文字列に変更する)
ステップ・オーバー (F8) Request.php 21 return false;
ステップ・オーバー (F8) AccountController.php 32 $this->forward404();
ステップ・イン (F7) Controller.php 96 throw new HttpNotFoundException('Forwarded 404 page from '
ステップ・オーバー (F8) Application.php 186 $this->render404Page($e);
ステップ・イン (F7) Application.php 249 $this->response->setStatusCode(404, 'Not Found');
ステップ・オーバー (F8) Application.php 250 $message = $this->isDebugMode() ? $e->getMessage() : 'Page not found.';
ステップ・イン (F7) Application.php 85 return $this->debug;
(index.php 使用)
debug の値を true に変更する (デバッグモード)
続行 (F5) ブラウザに表示 Page not found.
 or
Forwarded 404 page from account/register
(デバッグモード)
終了 (Shift+F5)

redirect 実行 (トークン チェック)

例 処理の流れ (アカウント登録画面 (ユーザ登録画面) & ユーザ登録)

index.php
1    <?php
2 
3    require '../bootstrap.php';
4    require '../MiniBlogApplication.php';
5 
6    $app = new MiniBlogApplication(false);
7    $app->run();
8 

AccountController.php (registerAction)
25    public function registerAction()
26    {
27        if ($this->session->isAuthenticated()) {
28            return $this->redirect('/account');
29        }
30
31        if (!$this->request->isPost()) {
32            $this->forward404();
33        }
34
35        $token = $this->request->getPost('_token');
36        if (!$this->checkCsrfToken('account/signup', $token)) {
37            return $this->redirect('/account/signup');
38        }
39
... 省略

$token の値を変更

Controller.php (checkCsrfToken)
148    protected function checkCsrfToken($form_name, $token)
149    {
150        $key = 'csrf_tokens/' . $form_name;
151        $tokens = $this->session->get($key, array());
152
153        if (false !== ($pos = array_search($token, $tokens, true))) {
154            unset($tokens[$pos]);
155            $this->session->set($key, $tokens);
156
157            return true;
158        }
159
160        return false;
161    }

Controller.php (redirect)
105    protected function redirect($url)
106    {
107        if (!preg_match('#https?://#', $url)) {
108            $protocol = $this->request->isSsl() ? 'https://' : 'http://';
109            $host = $this->request->getHost();
110            $base_url = $this->request->getBaseUrl();
111
112            $url = $protocol . $host . $base_url . $url;
113        }
114
115        $this->response->setStatusCode(302, 'Found');
116        $this->response->setHttpHeader('Location', $url);
117    }
118

Response.php (send)
18    public function send()
19    {
20        header('HTTP/1.1 ' . $this->status_code . ' ' . $this->status_text);
21
22        foreach ($this->http_headers as $name => $value) {
23            header($name . ': ' . $value);
24        }
25
26        echo $this->content;
27    }

DbManager.php (__destruct)
109    public function __destruct()
110    {
111        foreach ($this->repositories as $repository) {
112            unset($repository);
113        }
114
115        foreach ($this->connections as $con) {
116            unset($con);
117        }
118    }
ブレークポイント 設定
ファイル
index.php 3 処理の流れ を確認するため (省略不可) & すべて無効化 のため
AccountController.php 36 $token の値を変更する
AccountController.php 37 -
Controller.php 160 -
Controller.php 115 -
Response.php 20 -
DbManager.php 111 処理の流れ を確認するため (省略不可)
処理の流れ
アクション ファイル 他
開始 (Ctrl+F5) index.php 3 require '../bootstrap.php';
ブレークポイント ウィンドウ (右クリック)
すべて無効化
続行 (F5) ブラウザに表示 ログイン画面
アカウント登録 or 新規ユーザ登録 クリック
アカウント登録画面
ユーザID: user4, パスワード: password
ブレークポイント ウィンドウ (右クリック)
すべて有効化
登録ボタンクリック
ユーザ登録
index.php 3 require '../bootstrap.php';
続行 (F5) AccountController.php 36 if (!$this->checkCsrfToken('account/signup', $token)) {
変数 ウィンドウ
$token の値を変更する
"add" + "元の値" ("元の値" 以外の文字列に変更する)
ステップ・イン (F7) Controller.php 150 $key = 'csrf_tokens/' . $form_name;
続行 (F5) Controller.php 160 return false;
続行 (F5) AccountController.php 37 return $this->redirect('/account/signup');
ステップ・イン (F7) Controller.php 107 if (!preg_match('#https?://#', $url)) {
続行 (F5) Controller.php 115 $this->response->setStatusCode(302, 'Found');
ステップ・オーバー (F8) Controller.php 116 $this->response->setHttpHeader('Location', $url);
続行 (F5) Response.php 20 header('HTTP/1.1 ' . $this->status_code . ' ' . $this->status_text);
$this->status_code
  302
$this->status_text
  "Found"
ステップ・オーバー (F8) Response.php 22 foreach ($this->http_headers as $name => $value) {
ステップ・オーバー (F8) Response.php 23 header($name . ': ' . $value);
$name
  "Location"
$value
  "http://localhost/mini-blog.localhost/web/index.php/account/signup"
続行 (F5) DbManager.php 111 foreach ($this->repositories as $repository) {
アカウント登録画面
続行 (F5) index.php 3 require '../bootstrap.php';
続行 (F5) Response.php 20 header('HTTP/1.1 ' . $this->status_code . ' ' . $this->status_text);
$this->status_code
  200
$this->status_text
  "OK"
続行 (F5) DbManager.php 111 foreach ($this->repositories as $repository) {
続行 (F5) ブラウザに表示 アカウント登録画面
終了 (Shift+F5)
Page Top
Page Bottom