大変に今更ながらxdebugの「リモートデバッグ」とは何か

コネクションコールバックが〜とかポートが〜とか。
いんたーねっとに転がっている「xdebug.iniに、こんな風に書いてくれよな!!」というのを丸呑みしている日々が、続いておりました・・・(恥)

で、「なんかdockerでリモートデバッグが動かないよ〜><」というのを、妥協して怠惰に目を瞑って過ごしていたのですが、この記事と出会い。

blog.shin1x1.com

見事に問題が解消されました嬉しい・・・!

これをきっかけに、「そもそもどういう仕組で、クライアントに「デバッグ」な情報を送っているのかな〜」というのを、整理したいなと思ったのでした。

全体感

なんてことはない、公式のドキュメントのこの図が1番わかりやすい・・・・ dbgp

さて、この記事を読むのが良いです。 Xdebug: Documentation

DBGp

Xdebugは、コードを評価してクライアントと相互にやりとりをしながらデバッグをしていくことを可能にするよ!」「そのやりとりに使われるのが、 DBGp っていうプロトコルなのさ!」みたいなことが書いてあります。

詳細には、こっちで書かれていますね。 Xdebug: Documentation - Protocol - DBGp

クライアント

f:id:o0h:20171029135641p:plain こんなにも・・・!

設定項目について

ここが「1番実用的な知識」であり、今このようなメモを残すきっかけとなった本題です。

In order to enable Xdebug's debugger you need to make some configuration settings in php.ini. These settings are xdebug.remote_enable to enable the debugger, xdebug.remote_host and xdebug.remote_port to configure the IP address and port where the debugger should connect to. There is also a xdebug.remote_connect_back setting that can be used if your development server is shared with multiple developers.

ってことだから、ココらへんを見る。

remote_enable

「クライアントに接続しにいかせるやつ、いる?」のOn/Off。
「もし接続が確立できなかったら、この値がOffになっているものとして扱うよ〜」と書いてある、まぁそうですよね。

remote_host

「接続しに行ってOKなクライアントはどこ!?」の項目。「ここからの通信だけでDBGpでの交渉を許可する」、ってことであっているのかな・・?

書き方は

you can either use a host name, IP address, or 'unix:///path/to/sock' for a Unix domain socket

です。

remote_connect_back

「接続してきたホストにXGDp接続をしにいくか」。
何かというと「remote_host設定に関わらず(すなわち、設定値を無視して or 設定されていなくても )、リクエスト元をリモートデバッグクライアントとみなして通信しに行く」。

個人的には、 ローカル開発ならコレ使えばいいかな〜と思っていたので、前に晒したDockerfileではremote_hostでなくてこっちをenableにしているのだけど。どうなんだろう〜

もしくは、「チームで利用するリモートの開発サーバー」とかはこれ使う感じかと

There is also a xdebug.remote_connect_back setting that can be used if your development server is shared with multiple developers.

remote_port

「接続を試みるポート」。
例えば 「macでPHPStormを使っていてDockerコンテナのPHPでリモートデバッグをする」といった場合、「コンテナからmac(ホストマシン)の9000番に接続が来る」と・・・

remote_mode

これ知らなかった。「いつ有効にする(接続を返しに行く)か?」みたいなところ、かな・・?

Allowed values for this setting are "req" (the default) which makes the debugger initiate a session as soon as a script is started, or "jit" when a session should only be initiated on an error.

stormにも記事がある。 https://blog.jetbrains.com/jp/2013/12/19/343blog.jetbrains.com

remote_autostart

本来は「特定のパラメータ名」を付与したリクエストが来たときのみリモートデバッギングが始まるところを、この設定がOnになっていると「自動的に始まる」というもの。 冒頭で紹介した記事中でも、autostartが有効化されています。

ideky

「特定のパラメータ名」の設定がこれ!
例えば idekey=session_nameだった場合、

simply add XDEBUG_SESSION_START=session_name as parameter to the URL. Instead of using a GET parameter, you can also set XDEBUG_SESSION_START as a POST parameter, or through a cookie.

ということです。

要するに、 http://blog.example.com/post/100デバッグしたいときには、 http://blog.example.com/post/100?XDEBUG_SESSION_START=session_name というようにパラメータを付与してリクエストをする必要があるということです。

それによってXDEBUG_SESSION 情報がCookieに保持されます。

GET/POSTで値を渡された or セッション情報が記録されている場合のみ、デバッグセッションに入るといったことです。
※ HTTP Debug Sessionsのセクションを参照してください

先の autostartが有効化されていたら、 even if the GET/POST/COOKIE variable was not presentデバッグが始まるよ〜!となります。

関連: remote_cookie_expire_time

全員集合!設定項目

リモートデバッグのみでなく、Xdebug全体の設定項目についてはこちらに。 https://xdebug.org/docs/all_settingsxdebug.org

assertを使いこなす(こなしたい)

もちろんコレ!のインスパイア!!

speakerdeck.com

 

の話で。

プリンシパル・プログラミングにも書いてあったが、改めて意識したい点として「コードは書く時間より読む時間(人、回数)の方が多い」であり。
読み手にフレンドリーである事がとても良い。どうやるか。考える(べき)ことを減らす。
その一環として「表明」。「ここは、こうである」と。「AかBがCかそれ以外」を考慮するよりも「AかBか、それだけ。他はあり得ない」としてくれると楽だ。件のスライドを読み返したら書いてある、「想定しな蹴らばならない状況が減った」は正にこれだな望ましいな・・・

この「あり得ない」をコード上でサクッと「表明」してしまえ、というassertである。こいつと仲良くしたいな、という話。

自分としては、割とシンプルな条件の時に限って assert()を使うかもな、みたいな好みがあって複雑なときにはそりゃもうLogicExceptionなどを投げるんだけど。
ただ、使い分けが曖昧〜・・・・

  • 「複雑な」というのは、例えばif-elseif-elseで最終のelseに入るような呼び出し方は見直したほうがいいぜ?というときは、exceptionのthrow
  • 「複雑じゃない」というのは、例えば「RDBトランザクションが発生している状況でしか呼ぶなよ?」というメソッドにおいて、 $driver->inTransaction() みたいなくらいならassertで済ませるかも

メリットとしては「本番で無視されるからコストないぜ!!!!」っていうところか、ただしこの資料にあるように、「環境の差異減らしたいぜ〜」というサイドのみかたもあるかも。とはいえerror_reportingとかは分けるだろうから、自分としては「便利さに溺れていこうぜ!!」ってことでアサートは有効にするかな


って思って書きながら調べてたら、この記事とかは基準になるかもなー。

www.infiniteloop.co.jp

さすがのインフィニットループ様やでぇ。。。


  • 悩みとしては、「実例が少ない」     * 実際にどう使うか観点で、「めっちゃ判然とした!!」ていうレベルのプラクティスに出会えてないんだよなー
  • 気持ちとしては「どんどん推進・活用していきたい」

という温度感。
「本番に入る前に確実に防止できる(発覚する)、という自信ないし保証がある」ってところか。
あーさっきの記事の例も踏まえて考えると、「publicなAPI(web api、ではなく)」での利用は慎重になるべきかもしれない。逆に言うとprivateメソッドだと「目が届く」ので「呼び出し方・使い方を間違えてしまう」というのを、防ぎやすいというか。

いずれにせよ、テストカバレッジを一定以上に保っておかないと「見落とし」確率が高まって危険かもな。。


「コードは、何をするかは示しやすい、どうやるかも示しやすい、ただし何故やるのかを示しにくい」というので。この「なぜ」の部分、背景やらコンテキストやらを埋める手段として = 筆者の気持ちを考えなさい問題を回答する際のヒントとして、assert()いいよね〜の話
LogicExceptionとの住み分け、使い方、基準を自分の中で洗練させていかないと・・・

CakePHPのpatchEntity()とisDirty()

小ネタ。ちょっとハマったので。

「patchEntityをして、差分があったときだけsave()に入る」みたいな処理を書きたかった。cake3始めたばかりの頃。

$post = $this->PostsTable->get(1);
$post = $this->PostsTable->patchEntity($post, $this->request->getData();
if ($post->isDirty()) {
    $this->PostsTable->saveOrFail($post);
}

のような。 問題は、 isDirty()の挙動というか。

dirty となるのは 正しく、更新されたフィールドがあるとき`である。
何を意味するか。
すなわち、
更新しようと思ったフィールドが、全て「適切でなかったとき」、ditryとはならない** 。

たとえば、「ブログ(post)のタイトルを更新しようとした「posts.titleには「最大30文字」のバリデーションがかかっている」「40字のタイトルを付けて更新ボタンをクリック!」というケース。 これは、 marshal() が完了する前に拒絶され、「patchEntity()の結果得られる$post->title」は 以前のままである。その点において、isDirty()はfalseのまま。 (むしろ汚れてるけどねー)

Table::save() の中を追うと、 「isNew()である」もしくは「isDirty()である」のチェックが行われている。なので、「更新すべきフィールドがあったら〜」なんて処理、思い切ってsave()にたくしてしまって良い。

$post = $this->PostsTable->get(1);
$post = $this->PostsTable->patchEntity($post, $this->request->getData();
try {
    $this->PostsTable->saveOrFail($post);
} catch (\Cake\ORM\Exception\PersistenceFailedException $e) {
    $entity = $e->getEntity();
    $errors = $entity->getErrors();
    // $errorsをさばく
}

くらいなもんである。

ローカルに雑にhttpsな環境を作る時にhttps-poralがクソ便利だ

ngrockとかlocal tunnelでもいいですが!外部からアクセスさせるようなもんでもないな〜という時ありますもんね。

  • slackやlineといったbotのwebhook先はlocal tunnel
  • oauthのredirect urlや、ただ単にsecureにしたいだけな時はhttps-portal

みらいな使い分けを個人的には。

あたり。 こんなdocker-compose.ymlを用意した。

version: ‘3’
services
  https-portal:
    image: steveltn/https-portal:1
    ports:
      - '80:80'
      - '443:443'
    restart: always
    environment:
      STAGE: local
      DOMAINS: ‘browswer-kara-tataku-url.localhost -> http://jissaino-app'
  jissaino-app
    image: 'golang:latest’
# 以下省略

これで /etc/hosts127.0.0.1 browswer-kara-tataku-url.localhost としておけば、 htt://browswer-kara-tataku-url.localhost が利用可能になるっていう算段

「雑にCakePHP3プロジェクトを始めたいな」の時のDockerfileを書いてた

最近は業務で、これまでのPJ外のレポジトリに入り浸っている。
書いているのがCakePHP3用のプラグインで、普段は「Webアプリケーション」を書くことが多いのだけど、そこら辺から全く独立したプログラムだ。 ただしテストを書くために実行環境は必要で、「サクッと動けばいいな」という欲求

なので、今までの流れを無視して「とりあえず動けばいいでしょ雑にシンプルに用意して」、をした。

https://gist.github.com/o0h/69b79dea16a3c37b180082ac6dac89a4

  1. phpが動く
    • なるべく新しいやつ!
  2. CakePHP3が動く
    • そのためにintlとかの導入もクリアされている
  3. OSはなんでもいいや〜
  4. xdebugがほしい、それでIDEと繋がるところまではやっておきたい

既存の社内PJで「ちゃんと丁寧に書かれた内容」があったのでそこをかいつまみつつ、xdebug周りだったりdocker力の低さを補うために。このあたりを大変参考にさせていただきました。

ただ、PHPStormからだとxdebug.remote_connect_back で動作させられたな・・?バージョン上がったからとかなのかしら。

ひとまず、これで「なんかやろ〜」って思ったときに気軽に始められるので嬉し

Airbrake Blogの「PHPの例外ってそうだったんだ」シリーズが凄いタメになる

ブログもっと雑に書いてこ〜みたいな気持ちがしていた次第。メモとか放り込む

で、タイトルのとおりだけどAirbrakeが「組み込まれている例外、どういうときに使うもの?」というシリーズがありまして。 これが雑学的な読み物としても面白いな〜と思っていつも読んでいる。

今回は PHP Exception Handling – UnexpectedValueException 。 あんま自分は馴染みないかも・・・・と思ったけど。

https://airbrake.io/blog/php-exception-handling/unexpectedvalueexception-2

Not to be confused with the InvalidArgumentException

ほう

For example, if a function is returning a date value, but the runtime execution of this function produces a malformed date, you may opt to throw an UnexpectedValueException

と。前者はわかるぞ(いつもお世話になっております)
しかして、後者だ。すごく名前が似ている感じがする。どう違うの?と思ってみたら、サンプルコードがとても簡潔で良かった

    public function setPublisher(Publisher $publisher) {
        // Confirm that publisher is correct type.
        if (gettype($publisher) == 'object') {
            $class = get_class($publisher);
            if ($class != 'Publisher') {
                // Not a Publisher, so throw a new InvalidArgumentException.
                throw new InvalidArgumentException("Publisher cannot be set to type ({$class}), must be a Publisher object.");
            }
        } else {
            $type = gettype($publisher);
            // Not an object, so cannot be Publisher.
            throw new InvalidArgumentException("Publisher cannot be set to type ({$type}), must be a Publisher object.");
        }
        $this->publisher = $publisher;
    }

InvalidArgument〜は「待って!なにこれ!話が違うだろ!!」って言って投げるもので、UnexpectedValue〜は「あ、やばい!ちょっとうまく約束守れないかも!!」って使う感じかなー

あけましておめでとうございますブログ

2016年は良く痩せたなぁ〜という1年になった。それについては年の瀬にどっかで触れようーーと思ってたら年超えてた次第。
数字だけでいえば、1番大きな幅をとると5月下旬→11月中旬で体重が24kg/体脂肪率が19%ちょい落ちた。(元が酷い。)

運動するようになったね

GWに会社の合宿があり、最終日だけフリーだったのだけど「なにもしないで終わるなぁ」とモヤモヤしていたら、たまたまFacebookでシェアされてきた赤の他人の日記的な記事でfeelcycleの存在を知り。
うわ良さそう・・・!と思い立ち当日のうちにトライアルに参加し。都合の合ったのが横須賀中央のみだったので、わざわざ何時間か掛けて往復したw

大学で受けた健康診断=19歳の時点で「血圧が〜」みたいな注意を受けていて、そこからブクブク太り、ここ1,2年は服を着る度にパンパン具合に絶望して鏡で自分の姿が目に入る度に背けたくなり・・・という状況だったのだけど。運動とかしないとな・・と思いつつ、一時期はランニングなどしたりジムも入会したけど習慣にならず。
マジで「ジーンズのボタンが締まらなくなる」を通り越して「シャツのボタンが飛ぶ」ってあるもんなんですね。 ソコに対して、件の記事、「こんなの部活以来だ、ってくらい激しい運動」らしく「大音量で音楽を聴ける」という2点がとても魅力的に感じられ。
運動しなくなっちゃった、というだけで「昔みたいに本気で身体を動かす感じ!」には憧れていたし、爆音で音楽を聴くのも大好きなので、こりゃ良いぞ・・・・と。

実際にトライアル受けてみて、最初は目がチカチカするくらい搾り取られたのだけど、その場で入会。期待通りのキツさと躍動感で。
朝7時に最初の枠がある&会社の近くに2店舗あったのは凄く嬉しかった。平日の朝に行けるなら習慣的に通いやすいなーと。

それに加えて、「こんなに激しく汗掻くんならカロリーも相当消費するよね!」と思ってFitbitを買い、「体重減も期待できるんじゃない!?」と思いタニタの体組成計を買い。
きっかけが減量やダイエットではなかったけれど、実際に1回やってみて欲が出てきた感じかなぁ・・気付いたらこんなに贅肉まみれになていた自分が、抗えるものだと一切思ってもみなかったので。

そうやって勢いを得て、今年は自転車100km乗ってみたりとか実家までチャリ帰省したり。6月末までは、毎週何かしら運動の負荷を上げていく感じで楽しかったなー
100km走った時

ついでに食事も気をつけたり

基本的に「痩せるために始めた」という入り口でないので、あまり節制しよう!という風にはしなかったのだけど。誘われれば飲み行ったりするし相変わらず日本酒は好きに飲んでたし。
とはいえ「体重落ちるんじゃね!?」と舞い上がっている面もあったので、体組成計の出す基礎代謝量とかFitbitで見る消費カロリーとかを気にしつつ、1日の総カロリーを意識して・毎食絶対にサラダを最初に食べる・砂糖の多い飲み物は飲まない・スナック菓子や甘いものは食べない、という過ごし方。
仕事中にずっとキャラメル食べてたり毎日リプトン飲んだり日付変わってから寝る直前にラーメン食ったりしてたのに比べると随分とマトモ。(というか、体重落ちた要因は下手したら運動量よりもコッチが要因なのでは・・って気もする。

数字に現れる

6月くらいから体重如実に落ち始めて、4ヵ月連続で5kg前後落ちてた。何となく「25kg減量しました!って言ったら面白いんじゃねww」と思い始めて-25kgを目標にしていたのだけど、20kg落ちた辺りからペースが鈍化し。
そっから最終的には4kgちょっと落とせたけど、それまでに1ヵ月半くらいかかって、かつ低下が止まったので、多分この先は真面目に我慢とか管理とかしないとダメな領域なのかなーと感じた記憶。
そうこうして、BMIが30.5→21.5まで落ちたのでした。BMI30って何なんだ・・・
如実に減る様

もろもろよかったな~って感じ

体力は明らかについたなーと思うし、色々とポジティブな効果が出たな、という手応えはあり。がーーーっと自分を追い込む、みたいな体験は本当にストレス解消になるし、その「ストレス解消の手段を持っている」という感覚を自分が持てているのが非常に大きい。(7ヵ月前までは発散方法って暴飲暴食くらいだったからな。。。悪循環。
あと、その「自分が本気出している瞬間」を体得できているのは、マインドフルネスを実現する・・・とはちょっと違うかもしれないけれど、同じような効果を出せていると思う。明らかに仕事中とかの集中力が上がった。というか、集中しよ!って思った時に切り替えができるというか。

あと日中に襲われる睡魔が弱まったように思うので、コレは恐らく体力強化と食事改善だろうなぁ。血糖値の上昇抑えられれば眠くなりにくい、と聞くし。

今年はもうちょい踏み込む!

自分的には「5ヵ月連続-5kg!」が達成できなかったどころか年内の-25kgも果たせなかったのが癪なので、今年は25kg減と体脂肪率11%くらいを維持〜っていうのをやりたいなーという感じ。
とはいえ食事を高度に管理するのはストレスになりそうだし難しそうなので、引き続き、基本的に運動量を増やす・強度を上げるを頑張ってどうにかしたい感じ。
唯一あるとすれば、COMPにいよいよ手を出したので、毎日の朝食と過食後のフォローとか食事面倒くさい時に頼っていこうかなーと。栄養バランスと血糖値(満腹感、って言ったほうが近いのかな)への作用を期待しつつ。*1

というのと、あとは(有酸素運動だけでなく)筋肉つけたりして体脂肪抑えにいく、はそろそろやろうかなーという。anytime月に2,3回しか行かなかったので活用するw & ランニングとか、他の種類の有酸素運動もやる習慣つけたいなー。

ひとまず、2017年の私的な目標はこんな感じで! 仕事とかプログラミングな話も別途メモる・・

*1:元々、COMP購入に踏み切った理由は「コンビニで、毎朝あまり美味しくもないサラダを選んで買っていくのストレス」というのがあったからで。食体験として楽しくもない「食事」を続けていくくらいだったら、「ただ栄養だけとれればいい」な・・・という思いが強くなり。 実際には朝食をこっちに切り替えると摂取カロリー自体は増えると思うけれど、まぁトータルで見て魅力のほうが大きいのかなーって判断。