Serializerを使ってPHPでのJSONと配列やオブジェクトの相互変換を楽にする

Serializerとは

PHPの配列やオブジェクトをXMLJSONシリアライズしたり、その逆にデシリアライズすることができるライブラリです。

PHP向けのre:dash APIクライアントを作っている時に見つけました。

github.com

SymfonyにもSerializerというコンポーネントがありますが、Githubのスター数が多いという理由で今回はschmittjoh/serializerを選択しました。

Githubのスター数こそ少ないですが、Symfony内部で使われていそうなので、実ユーザーはこちらのほうが多いかもしれません。

インストール

Composerでインストールできます。

$ composer require jms/serializer

使い方

簡単なサンプルコードで使い方を紹介します。

サンプルコード

シリアライズ

まずはPHPの配列をJSONシリアライズしてみます。

<?php

$loader = require_once './vendor/autoload.php';

$data = [
    ['name' => 'PHP', 'description' => 'PHP is a popular general-purpose scripting language that is especially suited to web development.'],
    ['name' => 'Ruby', 'description' => 'A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.'],
    ['name' => 'Go', 'description' => 'Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.'],
];

$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$jsonContent = $serializer->serialize($data, 'json');
echo $jsonContent;

これを実行するとこんな感じになります。

$ php example.php
[{"name":"PHP","description":"PHP is a popular general-purpose scripting language that is especially suited to web development."},{"name":"Ruby","description":"A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write."},{"name":"Go","description":"Go is an open source programming language that makes it easy to build simple, reliable, and efficient software."}]

JSONがPretty printされていないので読みにくいですが、配列がJSONに変換されていることがわかります。でも、これはjson_encode関数とあまり変わらないですね。

シリアライズ

シリアライズのサンプルコードを少し改変して、JSONからのデシリアライズも試してみます。

<?php

$loader = require_once './vendor/autoload.php';

use Doctrine\Common\Annotations\AnnotationRegistry;
use JMS\Serializer\Annotation\Type;

AnnotationRegistry::registerLoader('class_exists');

class Language
{
    /**
     * @Type("string")
     */
    public $name;

    /**
     * @Type("string")
     */
    public $description;
}

$data = [
    ['name' => 'PHP', 'description' => 'PHP is a popular general-purpose scripting language that is especially suited to web development.'],
    ['name' => 'Ruby', 'description' => 'A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.'],
    ['name' => 'Go', 'description' => 'Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.'],
];

$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$jsonContent = $serializer->serialize($data, 'json');
// echo $jsonContent;

$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$object = $serializer->deserialize($jsonContent, 'array<Language>', 'json');

var_dump($object);

JSONからオブジェクトにデシリアライズする場合は、使用するクラスのメンバー変数にアノテーションを付ける必要があります。

ここでは、Languageクラスを用意し、JSONLanguageオブジェクトの配列にデシリアライズしています。

実行してみると、以下のような感じです。

$ php example.php
array(3) {
  [0]=>
  object(Language)#23 (2) {
    ["name"]=>
    string(3) "PHP"
    ["description"]=>
    string(97) "PHP is a popular general-purpose scripting language that is especially suited to web development."
  }
  [1]=>
  object(Language)#6 (2) {
    ["name"]=>
    string(4) "Ruby"
    ["description"]=>
    string(156) "A dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write."
  }
  [2]=>
  object(Language)#27 (2) {
    ["name"]=>
    string(2) "Go"
    ["description"]=>
    string(111) "Go is an open source programming language that makes it easy to build simple, reliable, and efficient software."
  }
}

まとめ

REST APIを使う場面では、ほとんどの場合JSONを使うことになりますが、決まった形式のJSONであればSerializerを使うことでPHPでの扱いが楽になるかもしれません。

さくらインターネットのArukasでSlackのBotkitを動かしてみる

Arukasとは

arukas.io

さくらインターネットが提供しているDockerコンテナーホスティングサービスです。Container as a Serviceとでも言ったらいいのでしょうか。

2016年5月現在はベータ期間中なので無償で利用することができ、現時点での料金プランではEssentialプランで3コンテナーまで無料とのことなので、ベータ期間が終わってもちょっとだけ使ってみたいというのであれば、無料で使用できそうです。

今回は、このArukas上で発言に反応するようなBotが動作するDockerコンテナーを起動し、動作確認するところまでをやってみます。

SlackのBotユーザーを作成する

Botの作成にはBotkitを利用します。

github.com

Botkitを利用するには、SlackのBotユーザーが必要です。以下のリンクからBotユーザーの追加ができるので、適当に名前を決めて登録し、BotユーザーのAPIトークンを取得します。

既存のBotユーザーがある場合はそのユーザーのトークンを利用することもできます。

https://my.slack.com/services/new/bot

ここで取得したBotユーザーのトークンは、後ほどArukasの設定で使用します。

Arukasの設定

Arukasにログインし、新しいアプリケーションを追加します。

f:id:ariarijp:20160506225045p:plain

その際、主要な項目は以下のように設定してください。

  • Image: ariarijp/botkit
  • Instances: 1
  • Memory: 256MB
  • Endpoint: (空白)
  • Port: 8080 tcp
  • ENV: 指定する
    • SLACK_API_TOKEN: Botユーザーのトークン
    • PORT: 8080

ベータ版の時点ではDockerイメージはDocker Hubからのpullのみの対応となっており、プライベートリポジトリには対応していないようです。今回使用するイメージは、この記事にあわせて作成したものとなりますが、Botの挙動を変更したい場合は、元のリポジトリをForkするなどして、JavaScriptを書き換えることになります。

また、ArukasはWebアプリ向けに作られているのか、必ずひとつ以上のポートを公開する必要があります。

発言に反応するBotを動作させる場合はポートを公開する必要がないのですが、今回使用するコンテナでは、SlackのSlash Commandのエンドポイントも含めており。そのエンドポイントが使用するポートを番号を指定しています(Slash Commandの設定については割愛します

各項目を入力したら、設定を保存してアプリを起動します。

アプリの起動後、詳細画面で「アプリは起動状態です」と表示されていれば、正常に起動ができているということになります。

f:id:ariarijp:20160506230201p:plain

動作確認

最後にSlackで動作確認します。アプリが起動している状態でSlackを見ると、Botユーザーがログインしている状態になっています。

f:id:ariarijp:20160506230414p:plain

この状態で、テストで利用するチャンネルにBotユーザーを招待し、以下のようにメンションをつけてメッセージを投稿します。

@Botユーザー名 hello

メッセージを「hello」とBotユーザー宛に投稿すると「hello」とBotユーザーはメッセージを送信します。

f:id:ariarijp:20160506230714p:plain

まとめ

今回は単純なBotをArukasにデプロイしただけですが、Dockerコンテナーに依存関係を押し込んでしまうことで、デプロイ先の環境などを気にせずBotを開発できますね。

しかし、Arukasはまだコンテナー同士のリンクや永続的なストレージには現時点で対応していないため、データが揮発することを考えてアプリを実装する必要があることには注意が必要です。

参考

PHP-FPMのステータスをメトリクスとして収集するMackerelプラグインを作った

週末にまとまった時間ができたので何か書こうと思った結果としてできた。

(6/30更新:本家にマージしていただきました!)

github.com

使ってみるとこんな感じ。Queue関連のメトリクスを実際の値でテストしたかったけれど、Backlogとかその辺がいろいろわかってないせいかできなかったので以下の動作イメージでも0のまま。

f:id:ariarijp:20160424210341p:plain

インストールは適当にgo getして$GOPATH/binからコピーするのを想定。

ひさしぶりにGoを書いたのでMackerelのヘルプを写経してから書いた。

mackerel.io

ヘルプをよく読めば気づいたことではあるけど、メトリクスはuint64またはfloat64でないと送信できないことに気づくまで2時間近くハマってしまった。それがなかったら1時間ちょっとで大体の処理は書けていたと思う。

テストコードではHTTPリクエストをモックできるhttpmockを使ってみた。

github.com

大したものではないけど、久しぶりに没頭できたので良い気分転換になった。

PHPでSlackに例外を通知するときに便利なariarijp/exception-to-slack-attachmentsを作った

github.com

ほとんどREADMEの内容に書いてあることだけど、ひさしぶりにブログも書いてみることにしました。

何がしたかったのか

PHPで例外を捕捉してSlackに通知する時に、SlackのMessage Attachmentsを使って見やすく通知したかったので、

PHPでSlackを連携するのによく使われるであろうmaknz/slackで使えるAttachmentsの配列を例外オブジェクトから生成するようにしました。

使い方

composer.jsonを用意してcomposer installする。既存のcomposer.jsonに追記する場合はcomposer updateをするなどうまい具合にしてください。

"require": {
    "ariarijp/exception-to-slack-attachments": "dev-master"
}

try-catchやフレームワークの例外ハンドラー内で例外オブジェクトを受け取ってSlackに通知する。といった使い方を想定しています。

以下はtryの中で例外を発生させ、その例外情報をSlackに通知する例です。

<?php

require_once __DIR__.'/vendor/autoload.php';

use Maknz\Slack;
use ExceptionToSlackAttachments\ExceptionToSlackAttachments;

try {
    throw new \Exception('Something went wrong');    
} catch (\Exception $e) {
    $attachments = ExceptionToSlackAttachments::toAttachments($e);

    $client = new Slack\Client('http://your.slack.endpoint');
    $client->to('#general')
        ->attach($attachments)
        ->send();
}

例外は以下のような感じで通知されます。

f:id:ariarijp:20160415105652p:plain

Shibuya.go#1に参加して、あとで調べたくなったことメモ

昨日に引き続きGo関連のイベントに参加してきました。

shibuyago.connpass.com

Goを実践的に使っている話が多く、昨日のGoもくもく会とは違った形で刺激をうけました。

発表のなかでいくつか使ってみたいものがあったので、忘れないようにメモしておきます。

eapache/channels

Channelの扱いを楽にできそう。

github.com

Songmu/goshim

よりよい go run

github.com

karupanerura/gostress

HTTP(S)のストレステストツール。いろいろ参考にできそう。

github.com

walter-cd/walter

Serverspecでも有名なmizzyさんが参加されてるビルドツール。会場ではJenkinsつらい問題対策への期待感を感じた。

github.com

yusukebe/revealgo

かっこ良すぎるプレゼンツールreveal.jsを便利に使えるCLIツールperlで作ったプロダクトの移植とのこと。

github.com

gin-gonic/gin

Go界隈で今は人気がありそうなWAF。

github.com

Chronograf

TSDBのInfluxDB向け可視化ツール

influxdata.com

yakst.com

その他

ariarijp/horenso-reporter-slack

songmuさんのスライド中で自作のツールを紹介していただいた。

horensoのreporterとしてSlackに結果を通知するCLIアプリ。

嬉しかったけど驚いて変な汗が出た。

github.com

まとめ

次回も開催決定しているとのことで、抽選あたったら参加したい。

内容が濃い会だったので、もうちょっとGoを使っておきたいところ。

主催のVOYAGE GROUPさん。ありがとうございました!おしゃれなオフィスだったなー。

voyagegroup.com