PHPカンファレンス関西2016に行ってきた 前編: トーク感想

先週土曜日、PHPカンファレンス関西2016に行ってきた。PHPカンファレンスは初めて。と いうか、カンファレンスとか勉強会とかに行くこと自体初めて。

前々から興味はあったが、なかなか機会がなかった。今回もだいぶ前から行こうと決めて なかったら行けてなかったと思う。前日もだいぶ気分落ち込んでたし。

行ってみたらとても楽しかったので行ってよかった。まあこの辺の話は後編に譲り、今回 はトークの感想。

タイムテーブルはこちら。

タイムテーブル PHPカンファレンス関西2016

スライド一覧を作ってくれてる方がいる。これは便利。

PHPカンファレンス関西2016 スライドリンク集 #phpkansai - お?意外といけるやん!

10:30-11:15 Composerを速くするために必要だったもの

基調講演。Compoerの通信周りをハックして高速化した話。前からこのプラグインのこと は知っていたが、試そうと思って試せてなかった。今の仕事でComposer使えてないのも あって……。

Compoerの使い方とか、思想とか、そういう基本的なところもきっちり抑えた上、その辺 が最後の伏線になったりしていてトークとしてレベルが高過ぎた。笑いも入ってるし。

物理的距離と糞実装に起因するレイテンシをどうするか、みたいな技術的な話の部分もも ちろん面白かったが、やはり最終部が最高だった。「問題と向き合うこと」大事。

PerlユーザとしてはCPANとかcpanmのこととかいろいろ考えながら聞いていた。cpanmが重 いのは、テストがいちばんのネックな気がするのでそのまま適用はできないだろうけど、 こっちも速くなれば・できればいいなあ。最近Perlもあまり書いてないけど。

スライドにも出てくるPRはこれ。後で試すなりして、いいねつけたい。でも先にプラグイ ンからかな……。

https://github.com/composer/composer/pull/5293

11:30-12:00 PHP開発とクラウド

今回のトークでこれだけはちょっと残念だった。ブース併設の部屋だったので、ちょっと うるさく聞き取りづらかったのがまず。

内容的にもふわふわしていた。よく考えるとタイトルからしてちょっとふわふわ感あった か。

13:00-13:30 ORMユーザー対談 〜Laravel/Doctrine/CakePHP3〜

アスペクト指向によるアプリケーション拡張」と迷ったんだが、昼食後メインホールに さっさと座ってしまったせいでけっきょくそのまま見た。

話自体は十分に面白かったんだが、濃い内容・三人の話者を30分でまとめきれるはずも なく、駆け足になってしまっていたのが残念。

Eloquent (Laravel), Doctorine (Symfony), CakePHP ORMそれぞれの特徴・差異がわ かったのはよかった。特にEloquentは個人的な好みに合いそう。それぞれのコードも今度 ちょっと読んでみたい。

それにしてもやっぱりアスペクト指向~の方見たかった気持ちが残ってしまって。後でス ライドちょっと見ても、やっぱりかなり楽しそうな内容だったっぽいし。

懇親会に参加しなかったことに次いで今回2つ目の後悔。

13:45-14:15 ビューのソースコードコンフリクトから解放される、PHPerのための次世代Webアプリケーション開発への道。

立ち見ならぬ座り見が出るほどの人気。みんな興味ある分野なんだなあ、とか思った。

タイトルにある「コンフリクト」周りを期待していたがちょっと違って、事実上Web Componentsの話だった。面白かったからいいけど。

Web Componentsさっぱりだったが、割と具体的な説明があって、Web Componentsがなんな のか、の基本的なところは理解できた気がする。ちょっと眠くて途中ちゃんと聞けてない ところもあったんだけど……w

フロントエンドはさっぱりだしあまり興味もないけど、今後手を出す必要が出てくるのは 確実だと思うんで、そのときまでにWeb Componentsくらいはちゃんと勉強しておきたい。

14:30-15:00 Laravel と DIコンテナ、コンポーネントの設計

DIとDIコンテナとその他の話。DIとDIコンテナの違い、このトーク聞いて初めて理解し た。というか今までは2つの違いにそもそも特に気を留めていなかった。

なお依存性を外部から突っ込むことの便利さを知りたければ、他人の書いていまいちな コードをテストするのがいいと思う。自分はそれで依存性の扱いに気を使うように なった。

コンストラクタでの注入も、名前ベースで持って来るようなのも、引数でやるのも、プロ パティやグローバル変数(!)でやるようなのも、大体一通り経験あるけど、どれがよくて どれがあまりよくないか、についてはそこまで深く考えたことがなかったが、このトーク を聞いた感じコンストラクタで突っ込めればそれがいちばんかなとか、名前ベースで引く のは便利だけどいろいろデメリットもありそうとか、ちょっと考えた。

あと、Laravelほんとやりたい。仕事でな

趣味でちょっとくらい触っても、やっぱり理解できないと思うんだよね。それに単純にや る気も出ないし。

15:15-15:45 PHPerに知ってほしいDB設計の話

この時間帯は最初にタイムテーブル見たときは特に決めてなかったと思うが、カンファレ ンス直前くらいから酷いDB設計に酷い目に遭わされてたせいで当日は即決。

MySQLのインデックス一つしか使わないとか、EXPLAINとか、基本的な内容なのかと思った ら意外と突っ込んだ話に展開して楽しかった。MySQLの進化とか、PostgreSQLの強さと か、どうせすぐには無理だろうけどいつかは味わいたい。

ちょうどSQLアンチパターン読み始めたところで、その関係ネタもあってよかった。

RDBの知識は長持ちする、みたいなところも考えさせられた。それじゃなくても経験値足 りてないんで、なにか一つくらい得意分野持たないととずっと思っているので。得意分野 にするならセキュリティかなと思ってたけど、RDBも楽しいかも。

16:00-16:45 LT

ここは一部だけ。

PHP7で脱!モッキングフレームワーク

PHPのコア機能で手軽に? モックオブジェクトを作ろうみたいな話。PHP 5でもリフレク ションとかあるけど、PHP 7の匿名クラスとか使うともっと手軽っぽい。いいな。

しかしPHP 5.3から抜け出すのに何年かかるという状況なので、PHP 7なんていつになった ら使えるやら……。

SwiftMailer アップデート

本題とは関係ないけどMailCatcherの話が出てきて、お、っとなった。アレなんか好きな んだよ。

PHPで作成されているOSSのソフトウェアとライセンスについて

これまた本題とは関係ないけど、スライドの長さは考えないと駄目だなー、と。ネタ的な 意味では面白かったが、ちゃんと本題を聞きたかった。

github.ioでブログを公開しよう

PHPみたいな言語は学生さんとかには人気なさそうと思ってたけど、そうでもないんだな と。

いろいろ初めてなのに、なんかライブコーディングみたいなことまで始めちゃってほんと すごい。

でもいちばんすごいのはじっさいにいいコード書いてることだよね。GitHubでちょっと見 てみたけど、普通にかなり書けてる。

こういうの見る度に今いる自分みたいな半端プログラマや、そんな自分以下のプログラマ とか、もう5年もすれば絶滅するんじゃないかと思うけど、じっさいそうでもないんだろ うな。そこ永遠の謎。

ロングポーリング(Comet)の話

興味あるネタなのでもうちょっと詳しく聞きたかった。というか記憶が曖昧だしスライド もないみたいなんであれなんだけど、これも最後までしゃべりきれなかったんだっけ?

Cometとか自分が職業プログラマになる前の話だし、ほんと懐しさ。

まとめ?

全体的に想像以上だった。また行きたい。

どうでもいいけどブログが軽く半年振りだ……。

Composer の autoloader のハッシュ値はなに?

vendor/autoload.php にある、 ComposerAutoloaderInitXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX の XXX... のことね。

手抜きでサーバ側に Composer 入れず autoloader だけ入れたいなと思ったんだけど、なにか環境ベースの値だったらいやなので調べた。

<?php
...
$suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true));

composer/AutoloadGenerator.php at master · composer/composer · GitHub

らしい。

uniqid の第2引数指定してるのが気になるけど、まあ多分安全じゃないかな。

しかしほんとブログ長いこと書いていなかった。書きたいネタ自体はいろいろあったんだけど。少しリハビリしなきゃな……。

PHPではグローバル変数は閉じ込めることができる。そして、関連して引っかかったこと

前提として、PHPでは変数には2つのスコープしかない。グローバルと、各関数(メソッド)ごとのものだ。ブロックスコープがないのが不便とはいえ、グローバル変数を使わなければ割と平和だ。

しかしレガシーコードを扱う場合など、仕方なくグローバル変数を使わざるをえない場合はある。今回、あるファイルに並んだグローバル変数が設定として使われている例があった。

ぜんぶ書き換えられるなら書き換えたいところだったが、なかなかそうも行かない。仕方ないので、せめて新しいコードからはラッパクラス経由でアクセスすることにした。

以下のようにすればベストだったと思われる。

<?php
# legacy-config.php

$xxx = 'OK';
<?php
# lib/MyApp/Config.php

namespace MyApp;

class Config
{
    public function get_xxx() {
        require 'legacy-config.php';

        return $xxx;
    }
}

require は、実行されたコード上のその位置でそのまま実行されたようにふるまう(おそらく)。そのため、 $xxx は、 get_xxx() のスコープになる。

こうすればグローバル変数のはずのものを、関数のスコープに閉じ込めることができて安全である。が、そのことを知らずによくない実装をしてしまっていた。

<?php
# lib/MyApp/Config.php

namespace MyApp;

require 'legacy-config.php';

class Config
{
    public function get_xxx() {
        global $xxx;

        return $xxx;
    }
}

こちらの実装でも、グローバル変数が漏れてはいるものの、動作自体は変わらない。

そのためしばらくは問題なかったのだが、あるとき設定の取得ができなくなった。調べてみると、 get_xxx() がなにも返していない。

原因はオートローダを導入したことだった。オートローダを導入するとなぜグローバル変数が消えるのか。さらに調べて、最初の「グローバル変数を関数に閉じ込めることができる」仕様を知った。

PHPのオートローダの実装は、 spl_autoload_register() という組み込み関数によって実現される。

クラスが必要とされた際に、この spl_autoload_register() の第1引数に設定した関数がコールバックされて、そこで呼び出すという形だ。たとえば最小限(かつ適当)なオートローダの実装はこんな感じになる。

<?php

spl_autoload_register(function ($class) {
    require strtr($class, '\\', '/') . '.php';
});

new \NS\Cls(); # NS/Cls.php が自動的に require される

見ての通り、 require は関数内で行われている。そのため、

  • オートローダで読み込まれたコード内のあらゆるグローバル変数は関数スコープになる。
  • さらに、オートローダで読み込まれたコード内で読み込まれたコードも関数スコープになる。

対策としては、今回のような場合は最初のコードのように、そもそも関数(メソッド)内で require すればよい。

なお require_once にするとまた別の問題が起きるので注意。すでにほかで読み込まれているときにわかりづらく問題になる。

また、どうしてもグローバル変数グローバル変数そのままで必要な場合は、そこだけ手動で読み込めばいいだろう。

Microsoft アカウントの登録がいろいろ微妙

Visual Studioのライセンス認証のために必要となったので登録しようと思ったが、いろいろ微妙だった。

URLがlive.comのまま。

ホーム|Microsoft アカウント から登録しようとしたのだが、「旧 Windows Live ID」とかあるのにlive.comのままで、バグってるのかと思った。

登録時に既存のメールアドレスで登録するか、Hotmailの新規アカウントを作って登録するかの選択肢があるが、違いがわからない。

以下を参考にした感じ、後者だと電話番号がいるように見えたが、じっさいにそうなのかは不明。

なぜかというと、じっさいに既存のメールアドレスで登録しようとしてみても電話番号フォームがあり、しかし入力は不要だったからだ。

ほんと謎。意味不明。

パスワードが16文字まで。

それ自体がもう言うことなしだが、さらに、16文字以上突っ込んだときのエラーが「17字以上は駄目です」な感じで無駄にわかりづらいという。


まあ目的を達するのに問題があるってほどじゃなかったけど、これだけリソースのある会社がこの程度のことしかできてないの見ると、残念な気持ちになる。

Firebugなど各種開発ツールで、input:textのvalueの変化が取れない

<!DOCTYPE html>
<html>
  <head>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
    <script>
jQuery(function ($) {
    $('input:text').val('ok');
    $('input:hidden').val('ok');
});
    </script>
  </head>
  <body>
    <form>
      <input type="text" name="text" value="">
      <input type="hidden" name="hidden" value="">
      <input type="submit">
    </form>
  </body>
</html>

こんな感じでJavaScriptからvalueを設定したとき、input:hiddenの変化はFirebugの方から取得できるのだが、なぜかinput:textの方が駄目だった。

f:id:xxmagai:20150720140843p:plain

この状態でsubmitするとクエリはちゃんと、 text=ok&hidden=ok となる。Firebugの表示だけおかしいのだろう。

なお、Firebug以外でも、IE, Firefox, Chromeの各開発ツールでも同じようになった。HTMLの仕様によるものだろうか。

知らずに引っかからなくていいところで引っかかりそうになった。危ない。

Windowsフォームデザイナーでツールボックスからカスタムコントロールを追加する場合の注意点

Visual Studio Community 2013で、C#で、Windows Formsでアプリ書いているんだが、なかなかやっかいなはまり方することが多くて困る。

今日はListViewを、継承してカスタムしたクラスに置き換えようとしてはまった。

カスタムコントロールを作るまでは、MSDNに書いてある感じでまあ問題ない。

方法 : 既存の Windows フォーム コントロールから継承する

問題はこのカスタムコントロールを、フォームデザイナーを使って、ツールボックスから追加しようとした場合に起きる。

上記の手順で追加した場合、カスタムコントロールはWindowsフォーム本体と同じ名前空間に属する。それ自体は自然だし問題ない。

だがフォームデザイナーがどうも、コントロールとフォーム本体が同じ名前空間に属する場合を想定していないようで、おかしなコードを出力する。

namespace MyApp
{
    partial class MyApp
    {
        ...

        private void InitializeComponent()
        {
            this.listView1 = new MyApp.ListView();

            ...
        }

        ...
    }
}

このコードが生成される、 myapp.designer.cs ファイルの名前空間MyApp になっているので、コンパイラMyApp.MyApp.ListView を見ようとしてエラーになる。

型名 'ListView' は型 'MyApp.MyApp' に存在しません。

対策としては、手動で書き換えるしかなさそうだ……。

今は大丈夫だけど、これからコントロールが増えてきたらどうしよう。

  • フォームデザイナーなんて使わず、手動で書く。
  • WPFに移行する。

どっちがいいだろうかね。困った。

おまけ

カスタムコントロールの方のクラスはまあこんな感じになるわけだが、

namespace MyApp
{
    public partial class ListView : System.Windows.Forms.ListView
    {
        public ListView()
        {
            InitializeComponent();
        }
    }
}

間違ってこう書くと、名前が被ってエラーになる。

using System.Windows.Forms;

namespace MyApp
{
    public partial class ListView : ListView
    {
        public ListView()
        {
            InitializeComponent();
        }
    }
}
'MyApp.ListView' と 'MyApp.ListView' を含む、循環する基本クラスの依存関係です。

まあ、ちゃんと文法わかってればない間違えなんだけど。

追記。

どうも、フォームデザイナーで修正する度に書き換えられちゃう模様。本気でどうにかしないと……。

C#のcatchがちょっと面白い

最近C#をちょっと書いているのだが、まったく未知のところからやっているとつい変なコードを書いてしまう。

先日は、こんなコードを書いた。

using System; // for Exception

class Program
{
    private static void Main() {
        try {
            throw new Exception("error!");
        }
        catch (Exception) {
        }
    }
}

見ての通り、catch句に受け取る型名しか書いていない。なんでこんなことが起きるのかとTwitterでつぶやいたら、こんな感じで教えていただいた。

実用的には、あるクラスの例外だけ再スローして、ほかの例外は処理する、などに使えるのだろう。

using System;

class ExceptionA : Exception
{
    // 関係ないけどコンストラクタいちいち書かないといけないのなんとかならんの?
    public ExceptionA(string message) : base(message) {
    }
}

class Program
{
    private static void Main() {
        try {
            throw new ExceptionA("error!");
        }
        catch (ExceptionA) {
            // こうすると再スローできる
            throw;
        }
        catch (Exception e) {
            // ExceptionA以外のExceptionクラスの例外は、処理する
            Console.Write(e);
        }
        // こうすると残りぜんぶ取れる
        catch {
        }
    }
}

型のゆるい言語を使っていると、catchした後にクラスを見て処理とか考えてしまうが、型の厳しい言語ではこういうやり方があるのだろう。

型の厳しい言語はほとんど使ったことがないので勉強になる。

追記

タイトルをちょっと修正した。メソッドじゃないのにcatch()とかおかしかったので。

メソッドといえば、メソッドのパラメータにクラス・型だけ書くのはできないようだ。まあ、意味ないしね。

// コンパイルすると、
// ... error CS1001: ID がありません。
// となる。
using System;

class Program
{
    private static void Main() {
    }

    private void Method(Exception) {
    }
}