[PHP]Laravel5をOS X(Mac)のローカルサーバーにインストールする

Laravel はオープンソースの PHP アプリケーションフレームワークの一つで、CakePHP や CodeIgniter、FuelPHP などと並び多くの注目を集めています。
この記事では、Mac に Laravel 5 をインストールする手順や発生した問題とその解決方法について書き留めておきます。

現在の環境とインストール予定のバージョンはこちらです。

OS X Yosemite 10.10
Laravel 5.0 または Laravel 5.1

詳細な説明に入る前にインストールの流れを見ておきます。

(1) Composer のインストール
(2) Composer を使って Laravel をインストール
(3) Composer を使って Laravel プロジェクトを作成

すべてが順調に行けば以上の3ステップで導入できますが、実際にはいくつかの問題が発生し、遠回りすることになりました。順を追って説明していきます。


Composer のインストール

Composer は PHP のパッケージ管理ツールです。これを使うことにより依存関係を解決してパッケージをインストールしたり、アップデートを行うことができます。Laravel 専用のツールというわけではなく、Cake PHP などのインストールにも使われています。

インストールするには次のコマンドをコンソールで実行します。

curl -sS https://getcomposer.org/installer | php

実行すると composer.phar ファイルがダウンロードされます。
そのままでは使いにくいのでパスの通っているディレクトリに移動させます。

sudo mv composer.phar /usr/local/bin/composer

これで composer と入力しただけで composer.phar が実行できるようになりました。
試しにバージョンを確認してみます。

composer --version
Composer version 1.0-dev (e64470c987fdd6bff03b85eed823eb4b865a4152) 2015-05-28 14:52:12

正しくインストールされていればバージョンが表示されます。


Laravel のインストール

Laravel インストールには Composer を使って次のようにします。
最新の情報は公式ドキュメント(5.0 / 5.1)を参照してください。

composer global require "laravel/installer=~1.1"

Laravel プロジェクトの作成

Laravel をインストールしたので Composer から Laravel プロジェクトが作れるようになります。
ただし、作成するにはサーバーが次の要件を満たしている必要があります。

【Laravel 5.0】

PHP >= 5.4
Mcrypt PHP Extension
OpenSSL PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension

【Laravel 5.1】

PHP >= 5.5.9
OpenSSL PHP Extension
Mbstring PHP Extension
Tokenizer PHP Extension

PHP のバージョンを確認するために「$ php -v」コマンドを入力すると、「PHP 5.5.20 」であることがわかりました。Yosemite に標準搭載されている PHP のバージョンには問題ないようです。「which php」コマンドで場所を確認すると「/usr/bin/php」にあることがわかります。
しかし、標準搭載の PHP には Laravel 5.0 に必要な Mcrypt というエクステンションがインストールされていないため、このまま Laravel プロジェクトの作成をしようとすると次のような警告が出ます。(Laravel 5.1 では必要ありません)

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for laravel/framework v5.0.16 -> satisfiable by laravel/framework[v5.0.16].
    - laravel/framework v5.0.16 requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.

そのため、先に「ext-mcrypt」を使えるようにしておく必要があります。

方法は2つあり、もし開発に MAMP を使っているのなら、そちらの PHP をコンソールから使えるように修正し、ext-mcrypt を有効にするという手があります。

【MAMP の PHP をコンソールから使う場合】

コンソールで「php」というコマンドを使った時、通常は「/usr/bin/php」が実行されます。そこで、.bash_profile ファイルにパスを通して、「/Applications/MAMP/bin/php/」の中にある PHP が実行されるように変更します。

$ vi ~/.bash_profile

vi で .bash_profile ファイルを開いたら、次の行を追加します。

export PATH=/Applications/MAMP/bin/php/php5.6.7/bin:$PATH

「php5.6.7」の部分はインストールされている MAMP によって異なります。環境に合わせて書き換えてください。
.bash_profile への変更はログインし直すか下記コマンドを実行しない限り即時には反映されません。

source ~/.bash_profile

MAMP に入っている PHP には ext-mcrypt が付属されています。有効になっていない場合は php.ini を書き換えて有効にします。php.ini は「/Applications/MAMP/bin/php/php5.6.7/conf/php.ini」にあります。
「;extension=mcrypt.so」となっている部分を探して「extension=mcrypt.so」のように先頭の「;」を外したら、MAMP の Apache を再起動させます。

【標準搭載されている PHP に ext_mcrypt をインストールする場合】

Mac に標準搭載されている PHP に ext_mcrypt をインストールする場合は .bash_profile などを変更する必要はありません。
インストールを簡単にするために Homebrew というパッケージマネージャーを利用します。
まずはその Homebrew をインストールします。

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

インストールできていれば「brew -v」コマンドでバージョンが確認できるはずです。
次に「brew search mcrypt」コマンドで mcrypt に関連するパッケージを検索します。
こちらの環境では次のパッケージが見つかりました。

$ brew search mcrypt
libtomcrypt  mcrypt
homebrew/php/php53-mcrypt    homebrew/php/php55-mcrypt
homebrew/php/php54-mcrypt    homebrew/php/php56-mcrypt

PHP のバージョンに合ったものをインストールします。「php -v」コマンドで調べると「PHP 5.5.20」であることがわかったので「homebrew/php/php55-mcrypt」を次のようにしてインストールします。

brew install homebrew/php/php55-mcrypt

こちらで試した時は必要ありませんでしたが、こちらの二行を先に実行しておく必要がある場合もあります。

brew tap homebrew/php
brew tap homebrew/dupes

インストールが完了したら php.ini にこのエクステンションを有効にするための記述を追加します。
php.ini は /etc/php.ini にあるものが読み込まれますが、php.ini.default というファイルしかない場合があります。その場合は php.ini.default をコピーして php.ini に名前を書き換えます。
内容を確認し「;extension=mcrypt.so」という行があれば先頭の「;」を外し、無ければ「extension=mcrypt.so」」という行を追加します。追加が終わったら保存して Apache を再起動させます。再起動のコマンドはこちらです。

sudo apachectl restart

さて、これで PHP と mcrypt の準備が整いました。いよいよ Laravel のプロジェクトを作成します。まずは cd コマンドでドキュメントルートに移動します。MAMP を使っている場合は「cd /Applications/MAMP/htdocs」ですが、Mac の Apache を使っている人は「cd /Library/WebServer/Documents」になるかと思います。次にプロジェクトを作成するためのコマンドを実行します。

◆最新バージョンのインストール

composer create-project laravel/laravel プロジェクト名 --prefer-dist

◆バージョンを指定したインストール(5.0 の場合)

composer create-project laravel/laravel プロジェクト名 5.0 --prefer-dist

プロジェクト名の部分は好きなように書き換えてください。その名前のフォルダが作られます。公開ディレクトリはその中にある「public」というフォルダなので「http://localhost/プロジェクト名/public」でブラウザから確認ができるはずです。

通常は Laravel のデモ画面が表示されますが、おそらく真っ白な画面しか表示されないと思います。というのもフォルダ storage 以下に対して Apache が書き込めるようにパーミッションを設定していないからです。
そこで storage に対して 777 の権限をもたせます。

sudo chmod -R 777 storage

設定が済んだら再度「http://localhost/プロジェクト名/public」にアクセスしてみてください。
うまくいっていればデフォルトのウェルカムメッセージが表示されるはずです。

laravel5

海外の技術系掲示板に英語で質問する際の文例・定型文

Stack Overflow に日本語版ができたとはいえ、やはり英語圏のフォーラムに助けを求めなければならないことは多いと思います。
義務教育で習った英語で内容を読み解くことはできても、英作文となるとなかなか思ったことを表現できず、質問をためらってしまうことがあります。
そこで、実際の海外の掲示板のやりとりの中で一般的なフレーズを集め、どのように書けば自然な英文で質問できるのか考えてみることにしました。

質問の流れは次のような構成を取ることが一般的です。

1. 何をしようとしているのか
2. 何が起こったのか
3. 何を試してみたのか
4. 何を知りたいのか
5. 結びの言葉(省略可)

つまり、「こういうプログラムを作っていて、次のようなコードを書きましたが、このようなエラーが起きます。こうしてみても同じでした。何が原因なのでしょうか?宜しくお願い致します。」という順番で文を組み立てていけば自然な流れになります。

以下は技術系の質問文でよく使われていたフレーズです。
中には使用頻度の高い言い回しであっても文法的には正しくないものが含まれています。修正せずにそのまま掲載しているので気をつけて下さい。


【何をしようとしているのか】

I have A that ~
(~という A があって)

I am trying to ~
(~しようとしていて)

I am using A to B
(B をするために A を使っていて)

I want to create A using B
(B を使った A を作りたくて)

I am creating A with B
(B を使った A を作っていて)

I am working on A
(A に取り組んでいて)

I’m currently developing A
(現在 A を開発していて)

I want to implement something like A,
(A に似たようなものを実装したくて、)

I’m using the following code to A:
(A をするために次のコードを使っています: 〜)

I need to create a function that 〜
(〜する関数を作る必要があります。)

I’m trying to write a PHP script that 〜
(〜するPHPスクリプトを書いています。)

My application has the following structure: 〜
(アプリケーションの構造は次のとおりです: 〜)


【何が起こったのか】

I get this error: A
(起こったエラー: A)

I get an error saying 〜
(〜というエラーが起きます。)

The problem I am having is ~ / The issue I am facing is ~
(起きている問題は~です。)

The problem is that ~
(問題は~です。)

I am facing some problems.
(いくつか問題が有ります。)

Specifically,
(具体的には、)

When I run this, it (returns/shows) A.
(実行した時 A が[返ります/表示されます])

I am getting following error when I start my application.
(作ったアプリケーションをスタートしたとき次のエラーが発生します。)

It shows error A while trying ~.
(~を試してみたところエラー A が表示されます。)

I can’t A when I try to B.
(B しようと試みたところ A できません)

It doesn’t show me any errors.
(何のエラーも表示されません。)

I sporadically get "A" error. / I get "A" error sporadically.
(不定期に「A」エラーが発生します。)

It works fine on localhost, but throws error on production server.
(localhost では正常に動きますが、本番サーバーではエラーが投げられます)

It seems to be working fine but ~
(問題なく動いているようにみえるのですが、)

A not working as desired.
(A が思ったとおりに動きません)

A doesn’t not working properly.
(A は正しく動作しません。)

B doesn’t work correctly as well.
(B も同様に正しく動作しません。)

A does not work at all.
(A は全く動きません。)

It fails with an error.
(エラーが起きて失敗します。)

A stops with no error message
(A はエラーメッセージを出さずに停止します。)

When I run: A, I get the following message: B
(実行したもの: A、得られたメッセージ: B)

I tried following, but it gives a empty result:
(下記を試したのですが空の結果が返ります。)

I get only a blank page.
(空白のページしか得られません。)

The parameter A has a weird value B.
(パラメーター A におかしな値 B が代入されます。)

There is something wrong with A.
(A に何かおかしなところがあります。)

I also tried A, but that didn’t work either.
(A も試してみたのですがどちらも動作しませんでした。)

It only happens occasionally and I can’t reproduce the problem.
(それはたまにしか発生せず、問題を再現できません。)

Every time I try to A, I get this error:
(A しようとするたびにこのエラーが起きます。)


【何を試したのか】

I have tried changing A but (nothing happens/still not working).
(A を変えてみても[何も起きません/動かないままです]。)

I have tried A with no success.
(A を試しましたが成功しませんでした。)

I have tried A multiple times
(何度か A を試してみました。)

I have tried it on several different machines now and all show the same behavior.
(他のマシン数台でも試してみましたが、同じ振る舞いをしました。)

I have tried it on a different computer as well and it gives the same results.
(別のコンピューターでも試しましたが結果は同じでした。)

I already searched the web and Stack Overflow but I couldn’t find any answer.
(すでにウェブとスタックオーバーフローで検索しましたがどんな答えも見つけられませんでした。)

I have googled but I can’t find any (answer/solution).
(ググったけど何の[解答/解決策]も見つからなかった。)

None of the things I have searched don’t make sense to me.
(検索で得たどの情報も私には理解できませんでした。)

I searched for A and nothing came up.
(A について検索しましたが、何も見つかりませんでした。)

There is a similar question to mine but I can’t get it working as answered.
(私の質問に似たものは有りましたが、回答通りに動きません。)

I searched on A, but could not find any good example for B.
(A で調べましたが、B に関する良い例は何も見つけられませんでした。)

The document says / According to this documentation / By looking into documentation,
(ドキュメントによると)

Because of my production server limitation,
(本番サーバーの制限により、)

Code:
Here is (my/the) code:
Below is my code:
The code is something like this:
I tried this:

(こちらがコードです: )

Here is the main file:
(こちらがメインファイルです: )

Here is a simplified code
(簡略化したコードがこちらです)


【何を知りたいのか】

What I want is ~.
(私が知りたいのは~です。)

I have no idea how to 〜 .
(どのように〜するのか思いつきません。)

Is it possible to ~ ?
(~することはできますか。)

Is there (a/any) way to ~ ?
(~する手段はありますか。)

Is there another way to ~ ?
(~するための別の方法はありますか。)

Is there any alternative solution to 〜 ?
(〜するための替わりの解決方法はありますか。)

How can I ~ ?
(どうすれば~できますか。)

How to make A B
(どうすれば A を B できますか。)

What would be the best way to do this?
(最適な方法は何ですか。)

What is the right way of doing this ?
(こうするための正しい方法はなんですか。)

What is missing in the implementation?
(この実装に何がかけていますか。)

Any suggestions on how to ~ ?
(どうすれば~できるか提案はありませんか。)

I don’t know what is wrong.
(何が悪いかわかりません。)

I am not sure what’s causing this problem.
(何が原因かはっきりしません。)

Can someone explain what is happening in this code?
(コードについて何が起きているか解説してくれませんか?)

What is wrong with A ?
(A のどこが悪いのでしょうか。)

What could be the cause of this (issue/problem)?
(何がこの問題の原因になりえますか。)

What am I doing wrong?
(何を間違えてしまったんでしょうか。)

What am I missing?
(何を見落としているんでしょうか。)

Does anyone know how to make this work?
(動作させる方法を知っている人はいませんか。)

Does anybody have a solution for this?
(だれか解決策を持っている人はいませんか。)

How should I approach A with B?
(B を使った A についてどのように進めていくべきでしょうか。)

Is this the right approach?
(このやり方で合っていますか。)

Is there a (better / more clever) way to do this?
(これをするためのもっと良い方法はありますか?)

How to fix error while ~ ?
(どうすれば~時のエラーを修正できますか。)

My guess is that because ~
(~が原因ではないかと推測しています。)

I know that A is wrong, I just don’t know how to make it right.
(A が間違っているのはわかりますが、どうしてもそれを正常にする方法が分かりません。)

Has anyone ever had this problem?
(同じ問題にぶつかった人はいませんか。)

Can anyone give me an example of A ?
(A についての例をくれませんか。)

What does this error code mean?
(このエラーコードはどういう意味ですか。)

Does this mean 〜 ?
(これは〜ということですか。)

I do not want to use A because it will 〜
(〜なので A を使いたくありません。)


【結びの言葉】

Thanks.
(よろしくね。)

Thanks in advance. / Thank you in advance.
(よろしくお願いします。)

Thanks for the help. / Appreciate your help.
(回答お願いします。)

Does anyone have an idea? / Any ideas?
(何か案はないですか。)

Can anyone help me?
(手助けしてくれませんか。)

Any help will be appreciated.
(どんな回答でも歓迎です。)


ほとんどの質問の書きだしは「I have ~」か「I’m trying to ~」でした。
「~を実行するためのクラス A があって」「~を格納した変数 A があって」「○○フレームワークを使って~しようとしていて」のような始め方が多かったです。
初心者であることを表すために「I’m new to ~」と始めたりもしますがあまりプラスには作用しない印象です。
むしろコードを例示することで悟ってもらうほうが良いかもしれません。

「whatever」を使って「array_whatever」「whatever.toString()」のようにすると「array_何とか」「何とか.toString()」のような曖昧さを表現できます。仮の変数名などとして foo や bar、baz、something などもよく見かけました。

結びの言葉として「Thanks in advance」はよく用いられますが、押し付けがましく感じる人もいるようで注意した方がいいかもしれません。ちなみにこの言葉を使った上で回答があった場合「Thanks again.(改めてお礼を言います。)」と返すとよりこなれた感じになります。

明確に使い分けされていないことも多いですが、単語「Problem」は「解決されなければ害をもたらす問題」、「Issue」は「意見を取り入れて改善しようとしている課題、議論の中心となっている議題、賛否両論ある問題」というニュアンスが含まれるようです。

「誰か」を指す言葉として「someone」と「anyone」があり、どちらも同じような使い方ができますが、「someone」はこの場にいる誰か、「anyone」はどこかにいるかも知れない誰かを指します。ただし厳密に区別されずに使われていることもあります。

以上が海外のフォーラムを見て回って得た傾向です。私自身英語は得意ではないですが、避けていては外国語もプログラミングも上達しないのでどんどん使ってみようと思います。

[PHP]クラスにメソッドを動的に追加する

インスタンス化したクラスに、クラスメソッド(メンバ関数)を追加できるようにするには、そのクラスにマジックメソッド __call() を用意します。
__call() はアクセスが制限されたメソッドや、存在しないメソッドを呼びだそうとした際に実行される関数で、関数名とその引数が渡されます。

PHP 5.3 から無名関数(Closure)が導入され、関数を変数に代入して扱うことができるようになりました。
また、PHP 5.4 では Closure のメソッドに bindTo() が追加され、クラスに関数を追加することが可能となっています。

例としてクラス Sample に hello() という関数を取り付けてみます。

<?php
class Sample
{
	private $functions = array();
	private $hello = 'Hello';
	
	function __call($name, $args){
		$callback = $this->functions[$name];
		return call_user_func_array($callback, $args);
	}
	
	public function bindCallback($name, $callback){
		$this->functions[$name] = $callback->bindTo($this, get_class($this));
	}
}

$sample = new Sample();

$callback = function($str){
	return $this->hello . ', ' . $str;
};

$sample->bindCallback('hello', $callback);

echo $sample->hello("World!");
結果: Hello, World!

$callback に関数 hello() の処理を代入し、bindCallback() で保管しておきます。
$sample->hello() でメソッドを呼ぶと、__call() が実行され、call_user_func_array() によって用意しておいた関数が実行されます。

この方法によって既存のメソッドをオーバーライド(上書き)することはできませんが、書き換えを許可するメソッドを bindCallback() で用意しておけば、プラグインのように後から機能を変更するといった使い方もできると思います。

参考:
http://php.net/manual/ja/closure.bindto.php