2020年のPHPエディタ

PHPを書くなら有料のPhpStormを使うのが一番良い気がしていて実際私も使っていますが、無料ならVSCode + PHP Intelephenseが良さげです。

PHP Intelephenseも一部機能は有料ですが、無料で大抵の機能が使えます

ということで環境構築方法を紹介します。

初期設定手順

1. PHP Intelephenseをインストールする

VSCodeのExtensionsタブでPHPと検索すると上の方にPHP Intelephenseが表示されるので、これをインストールします。

PHP IntelliSenseというExtensionが一番上に表示されますが、一つ下のPHP Intelephenseの方を入れます。

f:id:y_d:20200731223119p:plain

2. PHP Language Featuresを無効化する

Extensionsタブで@builtin phpと検索するとPHP Language Featuresが表示されるので、これを無効化します。

f:id:y_d:20200731223823p:plain

3. 設定画面でPHPのバージョンを指定する

VSCodeの設定画面で PHP Version と検索するとPHP IntelephenseのPHP Versionの設定が表示されるので、ここでPHPのバージョンを指定します。

PHP 7.4.0がデフォルトっぽいので、このままでよければ特に何もしなくて良いです。

PHPのバージョンが異なる複数のサービスを運用している場合は、Workspaceの設定にすると良さそう。

f:id:y_d:20200731224224p:plain

これで設定完了です。
※もしかしたら再起動必要かも。

使ってみる

インスタンスのメソッドが補完されるようになりました。

f:id:y_d:20200731231437p:plain

↓function内で $ と書き始めるとスコープ内に存在する変数のみが表示されるようになりました。

f:id:y_d:20200731224639p:plain

↓設定画面で PHP Version を5.3.0に設定した状態で、戻り値の型宣言を書いてみると、このようにエラー表示されるようになりました。

f:id:y_d:20200731224752p:plain

しばらく使ってみて、これである程度いけそうだったらPhpStormのサブスクリプションを解約しようかなと思っています。

air-shodo.comというサイトを作りました

air-shodo.comというサービスを正式リリースしました。

https://air-shodo.com

このサイトではPCやスマホで手軽に書道した気分を味わうことができます。今のところ機能はとてもシンプルで、大きくいって下記の3つです。

  • 書道する
  • 投稿する
  • 投稿を閲覧できる

特に3D touch対応のiPhoneiPad+Apple Pencilを使うと筆圧が反映され、より書道っぽい書き味になります。 今の時期だと、書初めなんかに使うとおもしろいと思います。

f:id:y_d:20181212072018g:plain
air-shodo.comで書いているところ

技術面

技術面では特に変わったことはしていないのですが、訳あって開発開始から2年半ブランクを空けて開発を再開したため、再開した時には開発環境のアップデートから始める事になりました。

  • Laravel5.0 --> 5.7(当時としても5.0は古かった)
  • gulp + Babel --> Laravel mix + TypeScript
  • Vagrant + Chef --> Docker Compose

主要なところだとこんな感じで、このあたりの更新に時間がかかりました。

やる気

実は2年半前(2016年5月頃)に書道できる機能だけのティザーサイト的な状態で公開していて、その後力尽きて放置していたのですが、今回投稿機能を追加した事で、当初やろうとしていたことがある程度実現でき、今回の更新を正式リリースとすることにしました。

生きていると色々あります。転職だったり、交通事故を起こしたり。未来は何があるかわからないので思いついた瞬間やる気がなくなる前にやりきってしまうことが大事だと開発を再開するとき改めて感じました。

という事で下記を意識して開発をしています。

  1. やる気が無くならないように楽しいところから作る
  2. やる気があるうちに、目に見える形になるまで作る
  3. やる気がない時は小さな機能改善や雑務でやる気が復活するのを待つ
  4. 時間を開けない(やる気がなくなってしまう)
  5. 万が一やる気が無くなっても、いつの日か再開できるようにドキュメント(できればShellScriptやMakefile)を残しておく

私はこれを 「やる気駆動開発(Yaruki-Driven Development; YDD)」 と呼んでいます(雑)。

MongoDBのcursor

f:id:y_d:20180605222656p:plain

下記の感じでなんとなくでMongoDBのcursorを使っているけど、今までちゃんと公式ドキュメントを読んだ事がなかったので改めてドキュメントを読んでみた。

var cursor = db.users.find();
while (myCursor.hasNext()) {
   printjson(cursor.next());
}

現行バージョン:
https://docs.mongodb.com/manual/tutorial/iterate-a-cursor/

過去バージョン:
https://docs.mongodb.com/v3.0/core/cursors/

仕様概要

軽く読んだ感じ次の仕様になっているらしい。

  1. cursor.next() を使ってループする実装にしていても、実は毎回MongoDBサーバーからデータを取得している訳ではない(ネットワーク負荷がボトルネックになってパフォーマンスが出ないので)。

  2. MongoDBドライバは実は裏でMongoDBサーバーから小分けにデータを受け取っていて、 cursor.next() はその小分けのデータから1ドキュメントずつ返しているだけ。小分けで受け取っていたデータがなくなったらMongoDBサーバーに問い合わせて小分けのデータを補充する。(裏でMongoDBドライバがMongoDB Wire Protocolを使ってデータ取得やらなんやらしているが、それをMongoDBドライバが隠匿している)

  3. MongoDBドライバがどれくらい小分けにして受け取るかというと、一番最初は101個のドキュメントをまとめて取得し、それ以降は16MBずつ取得する。この挙動は batchSize()limit() を使って制御する事が可能。
    ※3.4より前のバージョンだとちょっと挙動が違う

  4. MongoDBドライバは、MongoDBサーバーから小分けにデータを貰ってくるが、MongoDBサーバーはその瞬間の最新データを返す。したがってデータの更新が重なると1回のカーソルのループで、同じレコードが複数回返ってくる事がある。
    ※insert,updateでnatural orderが変わった時に複数回返ってくると思われる
    ※ただし前述の通り、結果が101ドキュメント以下なら複数回返ってくるのは起こり得ないはず

  5. 上記の、同じレコードが複数回返ってくる問題は cursor.snapshot() を使って回避する事ができる。

という事で、cursorを使っていても最新のデータが返ってくるケースがあるっぽい(もちろん古いデータが返ってくることもある)。

個人的に注意が必要だと思ったのは下記の点。

  • cursorから返ってくるドキュメントは、 find() した瞬間のドキュメントが返ってくることもあれば、そうでないこともある
  • cursorをループしていると、同じドキュメントが複数回返ってくることがある

概念図

文章だけだとわかりづらいので図にしてみる。

+---------+   +---------+   +--------+
| MongoDB |   | MongoDB |   | Client |
| Server  |   | Driver  |   |        |
+-+-------+   +----+----+   +------+-+
  |                |               |
  |                |     find()    |
  |    OP_QUERY    <---------------+
  <----------------+               |
  | 101 documents  |               |
  +---------------->     cursor    |
  |                +--------------->
  |                |               |
  |                | cursor.next() |
  |                <---------------+
  |                |   document    |
  |                +--------------->
  |                |               |
  |                | cursor.next() |
  |                <---------------+
  |                |   document    |
  |                +--------------->
  :                :               :
        101個documentを取得する
  :                :               :
  |                | cursor.next() |
  |   OP_GET_MORE  <---------------+
  <----------------+               |
  | some documents |               |
  +---------------->   document    |
  |                +--------------->
  |                |               |
  |                | cursor.next() |
  |                <---------------+
  |                |   document    |
  |                +--------------->
  |                |               |

補足

  • MongoDBサーバーとMongoDB Driverは MongoDB Wire Protocol を使ってやり取りを行う。
  • (言語は何でもいいけど)例えばPHPからMongoDBクラスを使ってMongoDBサーバーと通信を行うとき、裏では MongoDB Wire Protocol を使っている。
  • PHPからすると、MongoDBからcursorを取得して、cursorから 1 documentずつドキュメントを受け取るように実装したとしても、実はある程度の塊でMongoDBサーバーからMongoDB Driverが複数のドキュメントを受け取っていて、MongoDB Driverがそれを 1 documentずつ返している。

参考資料