枠だけのUIButtonをハイライトで背景色を変えるための拡張
中身透明で枠だけのボタンを作って、ハイライト時に背景色をボーダー色と同じに変えるUIButton拡張クラス(iOS7のロック画面パスコード入力ページの数値ボタンのようなヤツね)の作り方をメモしておきます。
UIBorderOnlyButton.h
#import <UIKit/UIKit.h> @interface UIBorderOnlyButton : UIButton @property (strong, nonatomic, readonly) UIColor *originalBackgroundColor; @end
UIBorderOnlyButton.m
#import "UIBorderOnlyButton.h" @implementation UIBorderOnlyButton - (void)setHighlighted:(BOOL)highlighted { [super setHighlighted:highlighted]; if (highlighted) { super.backgroundColor = [UIColor colorWithCGColor:self.layer.borderColor]; } else { super.backgroundColor = self.originalBackgroundColor; } } - (void)setBackgroundColor:(UIColor *)backgroundColor { [super setBackgroundColor:backgroundColor]; _originalBackgroundColor = backgroundColor; } @end
setHighlighted
をオーバーライドして同時に背景色を変え、元々の背景色をoriginalBackgroundColor
プロパティに退避しておく
しくみになっている。
あとは、IBビルダーで配置したButtonのclassをUIBorderOnlyButton
に変えて、ViewControllerなどのコード上で以下のようにボーダーを設定してやればOKです。
self.hogeButton.layer.borderColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0].CGColor; self.hogeButton.layer.borderWidth = 1.0;
参考サイト:
第77回PHP勉強会でAltaxをとりあげていだだきました
4/28にEngineYardさんで行われた第77回PHP勉強会で、私がオープンソースで作っているAltaxというPHPデプロイツールをとりあげていただきました。とっても嬉しかったのでブログに書いちゃいます。PHP勉強会についての詳細はリンク先を参照ください。
セッションの内容が動画でアップされてあったので先日拝見させていただきました。 登壇者の木村さんには丁寧な資料を作っていただき、デモまでして頂いて感謝の限りです。
自分が作っているプログラムが衆人の前で実行される場面を見るというのは、なんだか緊張と気恥ずかしさみたいなものがあって、動画を再生しているPCの前でニヤニヤ、もじもじしてしまいました。俺きめぇ。
さて、セッション内であがっていた話題などについて、いくつか言及させていただきたいと思います。
利用実績について
Altaxの利用実績があるのかという質問に対して、登壇者の木村さんも「......う〜ん(笑」と苦笑いしておりましたが、私も聞いたことがありません(笑。ごめんなさい。 あ、でも「作者は使っているハズ」という件について、はYESと答えられます。 私自身は自分が仕事で開発、運用しているWebアプリケーションのデプロイに使っています。 使い方はデプロイ用の作業サーバがあってそこでAltaxを実行してます。処理としては
- ローカルにリポジトリからWebアプリのソース一式を取得
- composer installなどのWebアプリのビルド処理を実行
- アプリケーションサーバ群にWebアプリをrsyncして配布
- 再起動が必要なデーモンの再起動
という一連の作業を自動化しています。
Githubで公開しているライブラリについて
セッション中、私がGithubで公開している他のPHPライブラリについても取り上げていただきました。 いくつか概要と私個人の利用内容について記載します。
kohkimakimoto/BackgroundProcess
これはPHPのWebアプリから非同期にコマンドを実行させるためのライブラリで、ここ にも書いたように、CSVファイルなどから一括で大量データをDBに投入するコマンドとWebインターフェースの連携に実際に使っています。 実はエラー処理まわりが不十分でその辺を修正してアップデートさせたいと思っているのですが、手がまわっていません。
MySQL用のDBマイグレーションツールです。PHPファイル一つで動くシンプルなツールで、後継のライブラリにkohkimakimoto/lib-migrationがあります。こちらはcomposerからのインストールに対応しています。 両方ともPHPクラス内に記述した素のSQLでスキーマ変更を行います。 これらのツールはこれまで素のSQLファイルと手作業でDB変更を行ってきていた古い既存システムがあって、そこにDBマイグレーションを導入する際に作ったという経緯があります。そのため今までのSQLをそのまま使いたかったのと、スキーマ定義をあまり抽象化した記述で行いたくなかったので、こういう設計のツールになりました。詳しくはここに書いてあります。
システムメンテの改善と小さなツール
Altaxもそうなのですが、これらのツールは私が実際に仕事で関わっている「3、4年まえからメンテし続けているちょっと古いシステム」の運用を改善するために作ったものです。このようなシステムは「まるっとすべてのリプレースを要するほど非効率な状態にあるわけでもないが、モダンなフレームワークなどにはある便利機能がなくて不満」という状況にあります。そこを少しずつ埋めるために開発しました。
おわりに
Altaxにはなぜか海外の開発者が多くGithubのスターをつけてくれていて、たまーにプルリクエストをくれるのも海外の方が多いです。うまく書けている自信は全然ないのですが英語でドキュメントを書いていたのがよかったのかもしれない、と個人的には思っています。 Altaxの初期バージョンはOSのSSHコマンドをPHPプログラムから実行するただのラッパーでした。改めてこれまでの開発を見直すと、なかなか成長したなあと思え、ちょっと感慨深いです。
今回、PHP勉強会で取り上げられたことはまったく予期していなかったので本当に驚いて、そしてこのように自分の作っているソフトウェアに好意的な反応をいただけるのはとても嬉しいことだな、と思いました。
コード上の利便性からオブジェクト指向を考える
今回はオブジェクト指向について書きたいと思います。 私がオブジェクト指向を初めて学んだのは8年くらい前で、そのときはJavaでコードを書いていました。 クラス、オブジェクト、継承、ポリモーフィズムなどは 「個々の犬オブジェクト(ポチ、シロとか)があって、それは犬クラスから生成されて、犬クラスと猫クラスは、 ほ乳類クラスを継承していて両方とも鳴くメソッドを持っていて、犬はワンとなくけど、猫はニャンとなく」とか本で説明されていたのを読んで 「これがオブジェクト指向か! なるほど(キリッ」 とか理解した気になって、おかしなコード書いて 「あれ? やっぱオレよくわかってなくね?」 とか思ったものです。
そして間違ったコードをその後も幾度となく書いて何度も書き直して試行錯誤して、 改めて本を読み直したりして、今現在なんとかわかった気になっています。 よいコードと悪いコードをいっぱい書いてきて頭の中で知識が整理されてからだと、 前述のような犬の比喩や抽象的な説明もわかるようになります。 整理された知識が理論で支えられているような、理解に安心感が得られます。
比喩や抽象的な説明はしない
この記事は以下の方針で書かれています。
- なるべく「抽象的」「比喩的」な説明はしない。
- コード上の「利便性」に注目する。
これはオブジェクト指向における、比喩や抽象的な話を否定するものではありません。 でもそれだけだと、理解するのがやっぱり難しいのではないかと思っています。 そこで別の視点、もっとコードよりで結局オブジェクト指向って何が便利なの?という視点から 解説してみてはどうかなと思って書いてみました。 何はともあれ、オブジェクト指向がプログラミングで使われているのは、それが便利なのだからです。
なお、説明のためのサンプルコードはPHPを使うものとします。では始めましょう。
クラス - 関数をまとめる
クラスはオブジェクトを生成するひな形、インスタンスの設計図などと説明されることが多いですが、 ここではそのような側面は取り上げません。まず理解すべきことは以下の性質です。
クラスは関連する処理(関数)をまとめる
たとえば文字列に関する関数を以下のようにまとめておくことができます。
// 文字列関連の関数をまとめたクラス class StringUtils { // 空白文字を削除する public function removeBlank($str) { return str_replace(array(" ", "\t", "\n", "\r"), $str); } // 先頭n文字を切り出す public function head($str) { return substr($str, 0, $n); } } // 以下のように使う $strutils = new StringUtils(); $str1 = $strutils->removeBlank("あ い うえお"); $str2 = $strutils->head("あいうえお", 2);
関連する処理、種類が同じ処理はまとまって記述してあった方が、コードが理解しやすいですよね。 これがクラスの「利便性」です。クラス内に定義した関数をメソッドと呼びます。これは名前が変わっただけです。 ただのクラス内でまとめられた関数でしかありません。
これをオブジェクト指向を使わないで書くと以下のようになります。
// string_utils.php // 空白文字を削除する function removeBlank($str) { return str_replace(array(" ", "\t", "\n", "\r"), $str); } // 先頭n文字を切り出す function head($str, $n) { return substr($str, 0, $n); } $str1 = removeBlank("あ い うえお"); $str2 = head("あいうえお", 2);
ただ関数を一つのファイルに並べただけです。クラスにまとめたときとあまり変わらないですか?
むしろオブジェクト指向なコードはnew StringUtils()
とかやっていて手間が増えていて解りづらいような。。。
そもそもnew
って何をやってるんですかね。すぐにわかります。でも、今は先に進みましょう。
クラス - 変数をまとめる
クラスは関数をまとめておけると述べました。同様に関連する変数(データ)もまとめられます。
// 「人」クラス class Person { public $name; public $height; public $weight; }
これは人を表すクラスですが、名前($name
)、身長($height
)、体重($weight
)と人に関する変数をまとめています。
ちなみにクラスにまとめられた変数をプロパティといいますが、これも名前が変わっただけです。
変数をまとめると何が便利なんでしょうか?
関数をまとめた時と同様にコードが理解しやすくなります。
まず$name
変数が格納しているデータが人の名前であること(何かほかの動物の名前などではなく)がコード上でもはっきりわかります。
また、このプログラムが扱う「人」のデータの内容がクラス内にリストアップされていて、わかりやすいです。
それに、データを一つにまとめることで関数の引数にデータを渡すときも一回ですみます。
// クラスでまとめられた変数に値を代入 $v = new Person(); $v->name = "鈴木"; // name変数に代入 $v->height = 173; // height変数に代入 $v->weight = 60; // weight変数に代入 // ユーザのデータを(DBなどに)保存する処理。 // いちいち名前と身長、体重を別々に渡す必要がないので見やすい! save_person($v);
変数$v
はvalueの略でこの場合意味はありません。->
はクラスでまとめた変数、関数にアクセスするための記号です。
ところで、また出てきたこのnew
は何でしょう?
インスタンス - データ構造にあわせた入れ物を作る
PHPのドキュメントには以下のように書かれています。
あるクラスのインスタンスを生成するには、new キーワードを使わなければなりません。
new
はクラスのインスタンスを生成しているらしいです。
クラスのインスタンス(以下単にインスタンス)とはなんでしょうか?
先ほどクラスは「変数をまとめる」と書きました。これをもうちょっと掘り下げて言い換えましょう。 クラスは変数をまとめて新しいデータ構造を作ります。 データ構造はデータ型ともよばれます。 ここでのポイントはクラスはデータそのものではなく、データの構造を作っているという点です。 例示しましょう。データ構造の例としては配列がいいです。 以下はPHPが最初から用意している配列型データ構造とそれにデータを代入している例です。
// 配列型データ構造 $v = array(); $v[0] = "aaa"; $v[1] = "bbb"; $v[2] = "ccc";
配列は複数のデータを順番にならべて格納できるデータ構造ですね。
上記のコードでは$v = array();
で空の配列で変数を作っています。その後実際のデータaaa
,bbb
,ccc
をその構造にそって代入しています。
さて、前述のPerson
クラスのコードを再掲してみましょう。ちょっと配列と操作が似てませんか?
// クラスのインスタンス化 $v = new Person(); $v->name = "鈴木"; $v->height = 173; $V->weight = 60;
配列の場合もクラスの場合も、やっていることは
- 指定したデータ構造の変数をつくる。
- 変数の構造にあわせてデータを入れる。
ということをやっています。前述したデータに関する言葉をそれぞれのコードに当てはめてみましょう。
データ構造
:データそのもの
:- 配列の例:
$v
に代入されているaaa
,bbb
,ccc
- クラスの例:
$v
に代入されている鈴木
,173
,60
- 配列の例:
インスタンスとはクラスという新しいデータ構造から作られたデータの入れ物なのです。
オブジェクト
「オブジェクト指向」の「オブジェクト」について語るときがきました。
まず、言葉としてオブジェクトとインスタンスは基本的に同議です。おなじものなのです。
文脈によってインスタンスといわれることが多かったり、オブジェクトといわれることが多かったりしますが、
ほとんどの場合どっちを使ってもいいです。
例えば前述のnew
キーワードの説明の
あるクラスのインスタンスを生成するには、new キーワードを使わなければなりません。
は
あるクラスのオブジェクトを生成するには、new キーワードを使わなければなりません。
でも全く問題なく、意味が通じます。それでは先に進みましょう。
オブジェクト - データと関数をまとめる
ここまでクラスの利便性を二つ述べました。
- 関数をまとめられる
- 変数をまとめて新しいデータ構造を作れる
実はこの二つの利便性は組み合わせることで真価を発揮します。以下にコードを例示します。
// 「人」クラス class Person { public $name; public $height; public $weight; // 身長、体重からBMIを計算する処理 public function calcurateBmi() { return ($this->weight / ($this->height / 100 * $this->height / 100)); } } // 以下のように使う $v = new Person(); $v->name = "鈴木"; $v->height = 173; $V->weight = 60; // BMIを計算して表示する echo $v->calcurateBmi();
これは身長$height
と体重$weight
変数からBMIを計算しています。
これの利便性はやっぱりまとまっていると理解しやすいということです。
またcalcurateBmi
メソッドが必要とするデータ(身長と体重)は同じクラス内にまとめられてあるので、
処理を呼び出す際データを間違えることがありません。
比較のために同じことをオブジェクト指向を使わずに書いてみましょう。
// 身長、体重からBMIを計算する処理 function calcuratePersonBmi($weight, $height) { return ($weight / ($height / 100 * $height / 100)); } $personName = "鈴木"; $personHeight = 173; $personWeight = 60; // BMIを計算して表示する echo calcuratePersonBmi($personWeight, $personHeight);
calcuratePersonBmi
関数に注目しましょう。
オブジェクト指向で書いたときは、オブジェクトが内部に保持しているデータを使って計算処理をしています。
一方オブジェクト指向でない(手続き型といいます)ときは、データは引数で関数の外側から渡されています。
たいした違いではありませんか?
しかしcalcuratePersonBmi
の実行するとき、プログラマが引数の正しい順番(体重、身長の順)を意識して関数を呼び出さなければなりません。
それよりもあらかじめ、体重、身長をまとめたデータ構造のオブジェクトを作っておいて、あとは単純に
calcurateBmi
メソッドを引数なしで呼び出した方がちょっぴりシンプルで、間違えにくいと思いませんか?
これは非常に単純な例で、些細な比較ですが、オブジェクト指向プログラミングの重要な性質が現れています。つまり
データと処理をまとめることで、処理の呼び出し部分をちょっとシンプルにできる
ということです。この「呼び出し部分」はAPIなどとも言われます。 APIがシンプルであれば処理の内容が理解がしやすく、ほかのプログラムからもこれが使いやすくなります。
カプセル化
オブジェクト指向の利便性をもっと高めるため「制約」の話をしましょう。 「制約」は何かを制限するという意味の言葉なので「利便性」とは逆の概念に思えますが、プログラミングの世界では「制約」はよい影響をもたらすためによく使われます。
「人」クラスで例示してみましょう。
// 「人」クラス class Person { protected $name; protected $height; protected $weight; public function __construct($name, $height, $weight) { $this->name = $name; $this->height = $height; $this->weight = $weight; } // 身長、体重からBMIを計算する処理 public function calcurateBmi() { return ($this->weight / ($this->height / 100 * $this->height / 100)); } } // 以下のように使う $v = new Person("鈴木", 173, 60); // BMIを計算して表示する echo $v->calcurateBmi();
前回までと変わったところは、プロパティの属性がpublic
からprotected
に変更され、__construct
メソッドが追加された点です。
protected
から説明しましょう。これはオブジェクトのプロパティへのアクセスを外部から禁止します。
つまり以下のようなコードが書けなくなります。
$v = new Person(); $v->name = "鈴木"; // これはエラーになる。->でプロパティにアクセスできなくなる。
__construct
はコンストラクタとよばれるメソッドで、new
によるオブジェクト生成時に呼び出され
オブジェクトの初期処理を行います。上記の例では引数で渡した$name
,$height
,$weight
でプロパティに初期値を設定しています。
あわせるとこのクラス(正確にはそこから生成されたオブジェクト)には
プロパティの内容はオブジェクト生成時に設定され、以後変えることができない
という制約がつけられます。このような制約をカプセル化と呼びます。これの何が便利なのでしょうか?
間違いを予防できるというのが答えです。間違ってデータを変更、削除してしまうのをさけられます。 最初に設定したら変えることができないのだから当然ですね。
Person
クラスの例でいうとcalcurateBmi
メソッドが正常に動作するにはプロパティの身長$height
、体重$weight
が設定されている必要があります。
自由にプロパティの変更ができてしまうと、これらのプロパティに値が入ってないという状況が発生してしまうかもしれません。
しかしprotected
属性でアクセスを制限しているので、コンストラクタで初期値を確実に入れさえすればその後、変更、削除されることはなくcalcurateBmi
は間違いなく動くということが保証されます。
プログラミングにおいて間違いをおこさせない仕組みで作るというのは設計上の基本戦略です。
ついでにもうちょっと、Person
クラスを拡張してみましょう。
// 「人」クラス class Person { protected $name; protected $height; protected $weight; public function __construct($name, $height, $weight) { $this->name = $name; $this->height = $height; $this->weight = $weight; } // 身長、体重からBMIを計算する処理 public function calcurateBmi() { return ($this->weight / ($this->height / 100 * $this->height / 100)); } // 名前を取得 public function getName() { return $this->name; } // 身長を取得 public function getHeight() { return $this->height; } // 体重を取得 public function getWeight() { return $this->weight; } } // 以下のように使う $v = new Person("鈴木", 173, 60); // 名前を表示する echo $v->getName();
メソッドを三つ追加しました。getName
、getHeight
、getWeight
です。
このメソッドによって人オブジェクトからそれぞれ名前、身長、体重のデータを外部から取得できるようになりました。
でも、依然データの更新、削除はprotected
によって禁止されています。
言い方をかえると変数と関数の組み合わせによって制約の一部を緩めることができるということです。
オブジェクトにどのような制約をつけるかは、あなたが実際に作るシステムの要件によります。 たとえば、人の名前を画面に表示する必要がある場合は、人オブジェクトから名前データをとってこなくてはならないので、 今回のように取得できるように制約を緩めます。
適切な設計へのポイント
オブジェクト指向の利便性を述べてきましたが、この利便性は適切に設計しなければその恩恵を受けられません。 オブジェクト指向でプログラミングする場合、従来の手続き型プログラミングの構造化に意識が行き過ぎていると設計に失敗します。 手続き型プログラミングだと処理を適切な粒度に切り出し関数として実装し、その関数に必要なデータを引数で渡す、というようにデータを処理というフィルターにかけるような意識で設計します。一方オブジェクト指向の場合データを適切な粒度にまとめて、そのデータを必要とする処理をくっつけるという意識で設計します。
クラスに変数と関数をまとめるとき「本当にこの場所(=クラス)に実装するのが適切か」と考える必要があります。 あわせて制約も注意深く考えましょう。特にオブジェクト内のデータを後から書き換えられるように制約を緩めるときは注意です。 不適切な変数や関数がクラス内にまとめられているかもしれません。
今回説明していないこと
クラスメソッドやクラス変数、継承やポリモーフィズムについてはまた後日。。。書くかも。
Composerがパッケージのstabilityを解決するしくみ
PHPとComposerで先日composer/composer
のdev-master
に依存したプログラムを作っていたら、composer install
のときに以下のようなエラーがでてインストールできない問題にぶちあたりました。
Your requirements could not be resolved to an installable set of packages. Problem 1 - kohkimakimoto/altax v3.0.6 requires composer/composer dev-master -> no matching package found. ...
解決方法はcomposer.json
に"minimum-stability": "dev"
と"prefer-stable": true
を指定するか、対象のパッケージに"composer/composer": "@dev"
のようなstabilityフラグをつければOKでした。
さて、この件に関連する日本語情報があまりなかったのですが、 根本の仕組み(Composerがパッケージのstabilityを判断してダウンロードする仕組み)を丁寧に書いたブログをみつけたので、以下和訳してみました。
Composerのスタビリティフラグ
原題:Composer Stability Flags
https://igor.io/2013/02/07/composer-stability-flags.html
今のところcomposerのサポートにやってくる最もよくある問い合わせは、スタビリティ(パッケージの安定性、stability)がどう解決されるのかよくわからないというものだ。 よくこのケースは以下のような問い合わせになる。
パッケージB:dev-masterに依存するパッケージA:dev-masterを要求(require)したら、composerがパッケージBが見つからないというんだ。
ルートパッケージ
ルートパッケージはメインのcomposer.json
ファイルのことだ。これはcomposer install
を実行するときにいるディレクトリと同じディレクトリ内にある。
多くのcomposer.json
のフィールドはルートオンリーで、これはルートパッケージ内で指定されたときだけ影響をもつということだ。
ルートパッケージはコンテキストだ。
あなたが自分のパッケージのディレクトリ内でパッケージAに依存しているといった場合、あなたのパッケージがルートパッケージとなる。
パッケージAのディレクトリにcd
したらAがルートパッケージだ。
スタビリティはルートパッケージで決定される。そしてルートパッケージのみで決定される。 これを忘れないようにして、ちょっと考えてみよう。
Composerはユーザの手にわたる依存物がどのようなスタビリティか判断をする。 ユーザとしてあなたは開発版、ベータ、または安定版のリリースを使いたいか決める。
最低限のスタビリティ(minimum-stability)
このスタビリティの判断はルートパッケージのminimum-stabilityフィールドに基づいて行われる。これはルートオンリーだ。スタビリティフラグのデフォルト値を定義し、下限として振る舞う。
これは引き下げることのできるルーラーで、デフォルトは"stable"をさしている。 しかし引き下げると、より低いスタビリティフラグを示すことができる。
minimum-stabilityはすべての制約のためのデフォルトの安定性を定義する。
スタビリティの解決
それでは、つぎのようなシナリオを考えてみよう。ルートパッケージがA:dev- masterを要求していて、 それがさらにB:dev-masterを要求している場合だ。
ルートパッケージは以下のようになる
{ "require": { "A": "dev-master" } }
Composerは以下のステップを踏む:
minimum-stability
を決定:このケースではフィールドが定義されていないのでデフォルト値が設定される。これは"stable"だ。- Aは
dev-master
というバージョン制約をもっている。dev-
プリフィクスがついているので、これはdevバージョンであることがわかる。そしてdevバージョンは"dev"スタビリティをもっている。ルートパッケージで定義されたこのdevバージョン制約のため、暗黙的に@dev
スタビリティフラグを得る。 Aは制約
A:dev-master@dev
をもっているので、このバージョンはマッチしてcomposerはリンクする。AはBにdev-master
という制約つきで依存している。これはdev-
プリフィクスを持っている、よって"dev"スタビリティをもっている。ところが、この制約はパッケージAの中で定義されていて、かつルートパッケージではないので、暗黙的に
@dev
スタビリティフラグを得ることはできない。その代わりにminimum-stability
を継承する。これは"stable"だ。よって、解決される制約はB:dev-master@stable
となる。
ここが障害のポイントだ。なぜならB:dev-master@stable
はどうやっても解決できないからだ。composerは与えられたスタビリティの範囲でパッケージBが見つからないとこたえるのだ。
この問題に対処する方法の一つはminimum-stability
を"dev"に下げることだ。
しかしこれは通常とてもよくないアイデアだ。これはすべての制約に適用されてしまい、
その結果、すべてのパッケージを不安定なバージョンで取得してしまう。
だからお願いだ。それをしないでくれ。
スタビリティフラグ
代わりにスタビリティフラグを使おう。
フラグはバージョン制約の一部として定義される。スタビリティはルートパッケージでのみで決定されるので、フラグもまたルートオンリーだ。 依存パッケージ内で定義されたフラグは単純に無視される。
フラグは不安定版パッケージを指定するホワイトリストとして使うことができる。このケースにおいて、私はBをホワイトリストに追加したい。このようにする:
{ "require": { "A": "dev-master", "B": "@dev" } }
注目すべきなのは、実際のバージョンをルートパッケージ内で定義していない点だ。 これはルートパッケージはインストールされるBのバージョンを扱わないということを意味する。 バージョンの決定は指定する制約をもっているAに委譲している。
これによって、もしAがBへの依存をdev-master
から~1.0
またはそれ以外に変更したとしても、ルートパッケージはなにも変更する必要がなくなる。
Silexの例
この動作が実際にどのようなものか、よりアイデアを得るために、silexを例に見てみよう。
これを書いている現時点で、silexは安定バージョンがない(訳者注:今は1.2の安定バージョンがありますね)。インストールするために@dev
フラグを追加する必要がある:
{ "require": { "silex/silex": "1.0.*@dev" } }
Silexは1.0
の開発バージョンである1.0.x-dev
バージョンのみがある。
Silexのすべての依存物は安定バージョンがある。これはデフォルトでv2.1.7
の多数のsymfonyコンポーネントとv1.0.1
のpimpleを得るということだ。
もし数日前にリリースされたsymfonyコンポーネントのv2.2.0-RC1
バージョンを試したくなった場合、
それを以下のようにホワイトリストにすることができる:
{ "require": { "silex/silex": "1.0.*@dev", "symfony/event-dispatcher": "@RC", "symfony/http-foundation": "@RC", "symfony/http-kernel": "@RC", "symfony/routing": "@RC" } }
バージョンをすべて指定するのは面倒なので、minimum-stability
を下げることもできる。
この場合それはOKだ。あなたが望まない不安定バージョンがインストールされることがないからだ。
{ "minimum-stability": "RC", "require": { "silex/silex": "1.0.*@dev" } }
prefer-stable
このポストを書いてしばらくした後、composerはprefer-stable
という機能をリリースした。
もし、依存物のスタビリティを把握したくない場合、単にprefer-stable
フィールドをルートパッケージで使うことができる。
Composerは可能なもので最も安定した依存物を導きだす。
これはとても便利でほとんどの場合それで十分だ。しかし、私はあなたが本当に必要としているスタビリティを考えることをお勧めする。明示的にそれを定義することもね。あなたは便利さと制御をトレードしてるかもしれない。
結論
composerがどのようにスタビリティを解決しているか。不安定バージョンを取得するためにスタビリティフラグどのように使うことができるか。この記事があなたのよりよい理解に役立てば、幸いだ。
でも覚えておいてくれ:スタビリティフラグを必要とするもっともよくある理由は、あなたの依存物のメンテナが安定板をタグ付けしない理由によるものだ。彼らにブランチエイリアスの追加とタグリリースをさせるため、いってやってくれ。彼らがそれを行ったらすぐに、スタビリティフラグを捨てて、またハッピーになれるよ。
Xcode5でxib(Storyboardを使わない)プロジェクトの作り方
ちょっと前に出版されたiOSアプリ入門書とか読んでるんですけど、最初のほうのサンプルアプリの作成手順で説明されているのがstoryboardを使わないでxibを使う構成だったりしてこまってました。 プロジェクトの作成画面で[Single View Application]を選択して[Use Storyboards]のチェックを外しましょう、って手順が書いてあって、[Use Storyboards]のチェックボックスねーよ! Xcode5からなくなってるよ! デフォルトで有効で外せねーってことかよ! うきー!
Storyboardを使うのが主流なんですか? でも今はまだiOSアプリ初心者だから、とにかく動くものをつくって、手順を繰り返して、コードを写経して、ツールの使い方とかObjective-Cのコードの感じとかAPIとかをちょっとずつ頭に入れたいんですよ。でもいきなりつまずいたーああああーーー。のおおおーーー!
さて、いろいろググって探した末、以下の手順でxibのプロジェクトを始めるのが良さげだったのでメモしておきます。参考のサイトはこちら、詳細は元の記事を見てください。
http://www.appcoda.com/hello-world-app-using-xcode-5-xib/
手順
- Xcodeを起動
- [Create a new Xcode project]を選択
- [iOS]の[Application]を選択[Empty Application]を選択
- 適当に[ProjectName]とかを埋めて、[Next]をクリックしてプロジェクトを作成
- Xcode上でAppDeletege.hとかのソースファイルが入っているフォルダを右クリックしてメニューから[New File...]を選択
- [iOS]の[Cocoa Touch]の[Objective-C class]を選択、[Next]をクリック
- [Class]に
**ViewController
のような名前のクラス名を入力、[Subclass of]にUIViewController
を指定。[With XIB for user interface]にチェック。[Next]をクリック
これで. xibと対応するViewControllerが作成される。最後にこのViewControllerを読み込むようにするためにAppDeletege.m
にコードをちょっと追加する。#import
とdidFinishLaunchingWithOptions
メソッドを以下のようにする。
#import "AppDelegate.h" // ここを追加 #import "ViewController.h" // ここを追加 @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; // ここを追加 ViewController *viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; self.window.rootViewController = viewController; // ここを追加 return YES; }
ViewController
のところは上記の手順7で実際に作成したViewControllerのクラス名に読み替えてください。
以上っす。
PHPデプロイツールのAltaxのバージョン3をリリースしました。
去年10月位にバージョン2に書き直して、今回さらにまるっと書き直しました。 タスクの記述方法などもごっそり変えてしまったので、すでに使っている人は今までの設定ファイルは使えないので注意してください。
https://github.com/kohkimakimoto/altax
ドキュメントはこちら
http://kohkimakimoto.github.io/altax/ja/
一応英語圏のひとにも使ってもらえるようにドキュメントは英語でも書いています。正直、英語苦手なので変な英語だったら誰かツッコミいれてください。
概要
PHPでタスクが記述できるCapistranoみたいなものです。
SSHでリモートサーバに対してコマンドを並列実行します。
またpharでソースを全部まとめて配布しているので、動作に必要なのはPHPとaltax.phar
だけなので手軽につかってもらえると思います。
使い方
チュートリアルを書きました。
http://kohkimakimoto.github.io/altax/ja/tutorial/
タスク定義の例をあげると、Gitからデプロイする簡単なタスクは以下のように定義します。
Server::node("web1.example.com", "web"); Server::node("web2.example.com", "web"); Task::register("deploy", function($task){ $appDir = "/path/to/app"; // Execute parallel processes for each nodes. $task->exec(function($process) use ($appDir){ // Run a command remotely and get a return code. if ($process->run("test -d $appDir")->isFailed()) { $process->run("git clone git@github.com:path/to/app.git $appDir"); } else { $process->run(array( "cd $appDir", "git pull", )); } }, array("web")); });
バージョンアップにあたって
タスクをLaravelのRouting定義ぽい記述方法にかえました。
実行コマンドのリターンコードや、出力内容を取得できるようにしました。
リモートホストに対してのファイルダウンロードやアップロードに対応しました。
プラグインでタスクを拡張できるようになりました。
プラグイン
プラグインで機能拡張をできるようにしました。 サンプルにAdminerというMySQL管理ツールをさくっと使えるようになるプラグインも同時に作って公開したので、 ご興味のあるかたはどうぞ。
http://kohkimakimoto.github.io/altax/ja/docs/plugins-introduction.html
このプラグインのしくみなんですが、元ネタというか影響をうけたのがGruntのプラグインの仕組みだったりします。 Gruntはプラグインのインストールをnpmをつかってやって、Gruntfile.jsに設定を書くという構成ですが、 AltaxはPHPのツールなのでComposerでプラグインをインストール、PHPの設定ファイルに設定を書く、という構成にしています。
個人的に今はリモートサーバにたいしてchefリポジトリをgitからcloneしてchef-soloをするという、 自動化タスクをプラグインで書いてみたりしています。
https://github.com/kohkimakimoto/altax-chef
開発とかテストの環境
最近メインPCをWindowsからMacにかえました。 だだし開発自体はVirtualBoxで構成したCentOS6上でやってます。そういうわけで、 プログラム動作は主にOSXとCentOSで検証しています。あとCIにTravisを使っています。
なおMacに入っているデフォルトのPHPだとpcntlモジュールが入っていないので、 並列処理の際にプロセスをforkする処理が動かないので、この場合は並列動作させずに、 順次実行するようになっています。
SymfonyとLaravelを比べてみての考察
SymfonyとLaravelはPHPのWebアプリケーションフレームワークで 2014年現在、モダンなPHPフレームワークとして人気があるようです。 両方ともComposerによるパッケージ管理、MVCアーキテクチャ、 開発時のPHP組み込みサーバのサポート、 バンドル(Laravelではパッケージ)などでの機能拡張性を持っています。
ここ最近、個人的な興味でこのふたつのフレームワークを触ってみていたので、 感想と比較を述べてみます。
なお、実際に触ったバージョンはSymfony2.4とLaravel4.1です。 また実際のプロダクトの開発に使用したわけではないのと、 パフォーマンス比較などは行っていないことを断っておきます。
ざっくりとした比較イメージ
細かい感想と比較を書く前に、ざっくりとイメージを述べておきます。
- Symfonyは構造がしっかりしていて重厚
- Laravelは構造がフラットで軽量
ここでの重厚とか軽量とかは、プログラミングをしているときの感触であって、 アプリケーションの動作のことではありません。 また、開発するアプリケーションの規模にそれを合わせて、 サービスが小規模だからSymfonyは適していないとか、 大規模だからLaravelはよくないという話でもありません。
基本的にアプリケーションの規模が小規模でも大規模でもどっちのフレームワークを使ってもよいと思いました。
アプリケーションの規模にフレームワークの向き不向きが全くないとは思いませんが、 それよりも開発するプログラマのやり方、好みにマッチしているかどうか が一番のポイントなんじゃないかと思っています。以下、個別にピックアップします。
ネームスペース
PHPでは5.3からネームスペースによるコードの構造化がサポートされました。
Symfonyで開発するコードはこのネームスペースで厳格に構造化する必要があります。
たとえば、Pakagistのトップページ
のコントローラはPackagist\WebBundle\Controller\WebController
というネームスペースに置かれています。
Laravelではコントローラをはじめ多くのクラスがグローバルなネームスペースを使用します。Laravelの典型的なコントローラは以下のようにnamespaceなしで定義されます。
<?php
class HomeController extends BaseController {
public function index()
{
return View::make('home.index');
}
}
ネームスペースによる構造化はクラス名の衝突を避けられ、構造の見通しをよくします。 一方でそれに合わせてディレクトリ構造が深く複雑になりがちです。
Symfonyは構造が健全であることに重きをおいて設計され、Laravelは記述のシンプルさに重きをおいて設計されている感じです。
デフォルトのテンプレートエンジン
SymfonyはTwig、LaravelはBladeというテンプレートエンジンを標準で使います。
ところで、一世代まえのPHPフレームワーク(CakePHP,Symfony1,ZF1)だと、素のPHPをテンプレートエンジンに使用するのがスタンダードでした。 でも最近はそうでもなく、Symfonyの開発者であるFabien Potencierの ブログなどで言及 されているように、素のPHPでは「最適」なテンプレートの記述が行えないということから、 専用のテンプレートエンジンを利用するようになってきています。
素のPHPがスマートに対応できない領域は、テンプレート継承や、エスケープ処理、イテレータ処理などです。 もちろん、全くできないわけではないが、インラインのphpタグでテンプレートがごちゃごちゃしてしまうのが避けられない。 このへんの問題は、前述のFabienさんのブログでも参照してください。
で、SymfonyとLaravelのテンプレートエンジンのはなし。
SymfonyのTiwgは前述のPHPテンプレートのダメな部分を完全に取り除いて 理想的なテンプレートエンジンを目指して設計されている感じです。 テンプレート継承もできるし、エスケープも自動。またfor文は以下のように書ける
{% for user in users %}
* {{ user.name }}
{% else %}
No users have been found.
{% endfor %}
このテンプレートはPHPとは基本的に別ものであり、テンプレートにPHPを書くことはできません。
LaravelのBladeも同様にテンプレート継承やエスケープ機能を提供してくれますが、 設計としてPHPと別ものではなく素のPHPテンプレートに正規表現による薄い変換処理をかぶせて、ちょっと文法を拡張した感じのものです。 なので、bladeのテンプレートにはPHPのコードも書けるのですが、Twigのfor文みたいなPHPの書式から大きく異るような機能は用意されていません。
テンプレートに素のPHPを記述できることを、害悪ととるか柔軟性ととるかは、プログラマの好みによる話だと思います。 私はPHPを記述できたほうがいいと感じるタイプです。
Symfonyはその領域において最適なコンポーネントを提供するのに対して、 Laravelは最適ではないが、PHPプログラマが慣れ親しみやすいコンポーネントを提供する。 そういう設計になっています。
設定ファイル
設定ファイルの記述に関しても設計思想の違いが感じられます。 たとえば、URLとアクションをひもづけるルーティングの定義をSymfonyはyamlかアノテーションを使います。 (PHPでも記述できるが、かなり冗長なのでこれを使うひとは多分いない)
一方、Laravelは素のPHPを使います。ただしSymfonyのPHP設定ファイルのような冗長さはなく、 グローバルネームスペースとスタティッククラスでRubyのDSLっぽい簡潔な記述を提供します。
テンプレートエンジンの話と同様なのですが、 Symfonyは設定ファイルの記述においても最適な方法(PHPは最適ではないのでyamlなどの別の手段)を提供するのに対して、 LaravelはあくまでPHPを使い(PHPプログラマのためのフレームワークだからか)、その上で記述しやすい施策をとっている印象です。
まとめ
最後に抽象的にまとめると
といったところでしょうか。