PHP5.4 の新機能を試すために インストールしてみます。
ソースのダウンロード。
$ wget http://jp.php.net/get/php-5.4.0.tar.gz/from/this/mirror \
-O php-5.4.0.tar.gz
解凍。
$ tar xzvf php-5.4.0.tar.gz $ cd php-5.4.0/
configure
今回は /usr/local/php540 に入れます。
$ ./configure --prefix=/usr/local/php540
次のようなエラーが出たので libxml2 を入れました。
configure: error: xml2-config not found. Please check your libxml2 installation.
$ sudo apt-get install libxml2 libxml2-dev
再度 configure 。
$ ./configure --prefix=/usr/local/php540
make & make install 。
$ make $ make test $ sudo make install
make test でエラーが出たんですが 今回は新機能のお試しが目的なので とりあえずインストール終了。
node.js には express という Web フレームワークがあり これを使うと簡単に Web システムの雛形が作れるそうなので 試してみます。
次のサイトを参考に進めました。
[参考]
Node.js(Express)アプリの雛形を自動生成する - アインシュタインの電話番号
express をグローバルインストール。
これで express コマンドが使えるようになります。
$ sudo npm install -g express $ express -v 2.5.8
"-g" オプションでグローバルインストールです。
上記のサイトでやってるように hoge というアプリを作成します。
$ express hoge $ cd hoge $ sudo npm link express $ npm install jade
express と jade も入れています。
express は、グローバルインストールしてあるのでリンクで入れます。
こうするとシンボリックリンクが作成されます。
これでもう雛形ができました。
さっそく動かしてみます。
$ node app.js
Express server listening on port 3000 in development mode
ポート 3000 で Web サービスが起動します。
http://127.0.0.1:3000/
次のような画面が表示されます。
ソースを修正して表示を "Welcome to Hoge" にします。
ソースを修正するたびに 毎回 Web サービスを起動するのは面倒なので 自動的にリロードしてくれるコマンドを入れます。 これも上記の参考サイトの通りです。
node-dev をグローバルインストールします。
$ sudo npm install -g node-dev
node コマンドの代わりに node-dev コマンドで起動します。
$ node-dev app.js
Express server listening on port 3000 in development mode
Web サービスが起動した状態で ソースを修正します。
バージョンが代わっているせいか 上記の参考サイトとは違うファイルでした。
$ vi routes/index.js
/* * GET home page. */ exports.index = function(req, res){ res.render('index', { title: 'Express' }) // "Hoge" に変更 };
Web サービスを起動したコマンドの方を見ると ソースを変更したことによって リスタートしているようでした。
$ node-dev app.js Express server listening on port 3000 in development mode [INFO] Restarting Express server listening on port 3000 in development mode
アクセスしてみます。
http://127.0.0.1:3000/
表示内容が変わりました。
とりあえずここまで。確かに簡単ですね。
node.js と mongoose をインストールしたので node.js から MongoDB の値を取得してみます。
次のサイトを参考に進めました。
[参考]
mongooseを使ってmongodbにアクセスしてみる - A Peak Never Ending !
まず MongoDB にデータを登録します。
$ mongo MongoDB shell version: 1.2.2 url: test connecting to: test type "exit" to exit type "help" for help > use memo switched to db memo > db.memos.save({title:'test title1', body:'test body1'}) > db.memos.save({title:'test title2', body:'test body2'}) > exit
データベースは memo、コレクションは memos にします。
node.js のスクリプト memo.js を作ります。
上記の参考サイトのスクリプトをそのまま貼り付けます。
$ vi memo.js
/* * Mongooseでデータを取り出して表示するテスト */ var mongoose = require('mongoose'); // スキーマ定義 var MemoSchema = new mongoose.Schema({ title: String, body: String }); // モデルとして登録 var Memo = mongoose.model('Memo', MemoSchema); // mongodbに接続 mongoose.connect('mongodb://localhost:27017/memo', // memoの部分はデータベース名 // コールバックでエラー時の処理が書けるみたい。 function(err) { if (err) { console.log(err); } else { console.log('connection success!'); } } ); // findしてコンソールに出力 Memo.find({}, function(err, docs) { if(!err) { console.log("num of item => " + docs.length) for (var i = 0; i < docs.length; i++ ) { console.log(docs[i]); } mongoose.disconnect() // mongodbへの接続を切断 process.exit() // node.js終了 } else { console.log("find error") } });
実行してみます。
$ node memo.js
connection success!
num of item => 2
{ _id: 4f73edfbb7c76c517dc7eb16,
title: 'test title1',
body: 'test body1' }
{ _id: 4f73edffb7c76c517dc7eb17,
title: 'test title2',
body: 'test body2' }
node.js から MongoDB の値が取得できました。
これで、できることの幅が広がりました。
作業メモです。
前回の node.js の続きです。
今回は mongoose を入れます。
mongoose は node.js から mongodb を ORM っぽくアクセスするためのライブラリです。
mongoose のインストールには npm を使います。 npm は、前回の node.js のインストールで入っています。
$ which npm
/usr/local/bin/npm
プロキシ認証が必要な環境だとちょっと大変です。
まず npm にプロキシの設定をします。
$ npm config set proxy http://USER:PASSWORD@SERVER:PORT
プロキシを使う環境だと DNS が引けなくても大丈夫だったりしますが npm では下のサイトに書いてあるように名前の解決ができくてエラーになってしまいました。
[参考]
Proxy環境下でnpmインストール :ダメ人間オンライン
DNS を設定するか /etc/hosts に接続先の registry.npmjs.org を追加したりして対応します。
mongoose のインストール。
$ npm install mongoose
・・・と思いきや、またもやエラーが出ます。
npm http GET https://registry.npmjs.org/mongoose npm ERR! Error: connect ECONNREFUSED npm ERR! at errnoException (net.js:670:11) npm ERR! at Object.afterConnect [as oncomplete] (net.js:661:19)
次のサイトに書いてあるように https だとうまくいきません。
[参考]
WindowsXP + プロキシ環境でnpmを使う - 四角革命前夜
ホームディレクトリに .npmrc ができているので編集します。
$ vi ~/.npmrc
プロキシの設定が書いてあるので 次の行を追加します。
registry = http://registry.npmjs.org/
もう 1 度インストール。
$ npm install mongoose
今度は成功しました。
作業メモです。
まず、ソースをダウンロード。
$ wget http://nodejs.org/dist/v0.6.14/node-v0.6.14.tar.gz
解凍。
$ tar xzvf node-v0.6.14.tar.gz $ cd node-v0.6.14
configure 。
$ ./configure
Checking for program g++ or c++ : /usr/bin/g++
Checking for program cpp : /usr/bin/cpp
Checking for program ar : /usr/bin/ar
Checking for program ranlib : /usr/bin/ranlib
Checking for g++ : ok
Checking for program gcc or cc : /usr/bin/gcc
Checking for gcc : ok
Checking for library dl : yes
Checking for openssl : yes
Checking for library util : yes
Checking for library rt : yes
Checking for fdatasync(2) with c++ : yes
私の環境では 最初 次のようにエラーが出たので libssl-dev をインストールしました。
Checking for openssl : not found Checking for function SSL_library_init : not found Checking for header openssl/crypto.h : not found /home/odin/node-v0.6.14/wscript:374: error: Could not autodetect OpenSSL support. Make sure OpenSSL development packages are ...
$ apt-get install libssl-dev
make と make install 。
$ make $ sudo make install
node コマンドを実行してみます。
$ node > 3 + 5 8 > var a = 3; undefined > console.log(a); 3 undefined
これで終わりです。
今回は、実際にデータを登録して見ます。 MongoDB は、 事前にテーブルなどを作成しません。 (スキーマレスと呼ぶそうです)
データベースと言えば SQL なので 次のサイトが わかりやすくて参考になりました。
[参考]
SQL脳に優しいMongoDBクエリー入門 - あるプログラマーの後悔日誌
MongoDB の操作は JavaScript な感じです。
> db.books.insert({ name : "a" });
スキーマレスなので、 何の定義もなく いきなりこんな記述で、データを登録できてしまいます。
books の部分が『コレクション』で RDBMS だとテーブルのようなものだと思います。
そこに JSON 形式のデータを INSERT しました。
{ name : "a" }
"show collections" で コレクションの一覧を参照できます。
> show collections
books
system.indexes
さっき登録した books があります。
もう 1 件登録してみます。
> db.books.insert({ name : "b" });
コレクションの中身を見るには次のように コレクションに対して find() メソッドを使用します。
> db.books.find();
{ "_id" : ObjectId("4f5ff9e69d12fb10f7c2955f"), "name" : "a" }
{ "_id" : ObjectId("4f647e7b9d12fb10f7c29560"), "name" : "b" }
上のように暗黙的に "_id" が作成されて データが管理されます。
もう少し複雑なデータを登録してみます。
> db.books.insert({ name : "c", detail : { size : "b5", page : 120 }});
> db.books.find();
{ "_id" : ObjectId("4f5ff9e69d12fb10f7c2955f"), "name" : "a" }
{ "_id" : ObjectId("4f647e7b9d12fb10f7c29560"), "name" : "b" }
{ "_id" : ObjectId("4f6480479d12fb10f7c29561"), "name" : "c", "detail" : { "size" : "b5", "page" : 120 } }
このように MongoDB は 1 つの "_id" に対して 1 つの JSON 形式のデータ(ドキュメント)を格納する形式のようです。
Web のインターフェースを使って見てみます。
http://127.0.0.1:28017/test/books/
test の部分がデータベース名、bookes がコレクション名です。
{ "offset" : 0, "rows": [ { "_id" : { "$oid" : "4f5ff9e69d12fb10f7c2955f" }, "name" : "a" } , { "_id" : { "$oid" : "4f647e7b9d12fb10f7c29560" }, "name" : "b" } , { "_id" : { "$oid" : "4f6480479d12fb10f7c29561" }, "name" : "c", "detail" : { "size" : "b5", "page" : 120 } } ], "total_rows" : 3 , "query" : {} , "millis" : 0 }
こんなデータが返ってきました。
これなら Ajax や node.js などからも
簡単に連携できそうです。
今回も mongo クライアントの話です。
mongo クライアントを起動すると デフォルトでは、次のように test というデータベースに接続されます。
$ mongo MongoDB shell version: 1.2.2 url: test connecting to: test type "exit" to exit type "help" for help >
"show dbs" で データベースの一覧を表示します。
> show dbs
admin
local
test
"use [データベース名]" で データベースを変更します。
> use local
switched to db local
DB に接続するというよりは カレントの DB を変更する、という感じですね。
Firefox11 の 3D は 「何かできそう」な気がする機能なので 思いつくままに遊んでみたいと思います。
3D ならでは、ですね。
超手抜きでピラミッド・・・。
頑張れば塔やビルとか作れそうです。
3D ビューにしないとわからないメッセージを埋め込んでみます。
何もない HTML ですが・・・
3D ビューにすると文字が浮かんできます。
[サンプル]
3D ビューに文字を埋め込んでみる
他にも色々できそうな気がします。
こういう「何かできそう」という機能は楽しいですね。
Firefox の 11 では ページインスペクタに「3D ビュー」という コンテンツの階層を 3D で表示できる機能が追加されました。
[参考]
Firefox 11.0 リリースノート
[Ctrl]+[Shift]+[I] で表示する ページインスペクタ(メニューから表示する場合は「ツール」→「Web 開発」→「調査」です)の 右下に「3D」ボタンが出るはずなのですが、 自分が使ってる環境(複数)では表示されませんでした。
表示する方法を教えてもらったのでメモとして上げておきます。
まず about:config で設定画面を表示します。
Firefox にも表示されますが設定の変更は危険ですので
理解したうえで自己責任で試してください。
検索で「webgl」を探します。
出てきた中の「webgl.force-enabled」を true に変更します。
webgl.force-enabled
次に「tilt」を検索して
出てきた中の
「devtools.tilt.force-enabled」を true に変更します。
Firefox を 再起動します。
ページインスペクタを表示すると「3D」ボタンが追加されます。
押すと 3D ビューが開始します。
マウスのホイールやドラッグ、キーボードのカーソルキーなどで
動かすことができます。
同時に HTML ソースや スタイルも見れるので 3D にすれば、深いところにある定義も指定しやすくなります。
今回は mongo クライアントを使ってみます。
Ubuntu10.04 の場合、mongodb パッケージをインストールすると mongo クライアントも入ります。
起動します。
$ mongo MongoDB shell version: 1.2.2 url: test connecting to: test type "exit" to exit type "help" for help >
出力されている通り help 表示してみます。
> help
HELP
show dbs show database names
show collections show collections in current database
show users show users in current database
show profile show most recent system.profile entries with time >= 1ms
use <db name> set curent database to <db name>
db.help() help on DB methods
db.foo.help() help on collection methods
db.foo.find() list objects in collection foo
db.foo.find( { a : 1 } ) list objects in foo where a == 1
it result of the last line evaluated; use to further iterate
なんか色々と出ました。
exit で終了します。
> exit bye $
たぶん続きます。
入ってる Linux のディストリビューションがわからない場合 Ubuntu だと次のように /etc/lsb-release を見ればわかるんですが CentOS は?と聞かれたのでメモ。
$ cat /etc/lsb-release
[参考]
インストールした Linux ディストリビューション名とバージョンを確認するには - PRiMENON:DiARY
上の参考サイトによると とりあえず /etc/issue 、 あとは /etc の下に xxxx-release みたいなファイルがあるようです。
なので次のようにしておけばよいかと。
$ cat /etc/issue /etc/*-release
ドキュメント指向とやらの MongoDB を使ってみます。
まずはインストール。
環境はいつもの Ubuntu10.04 です。
$ sudo apt-get install mongodb
パッケージがあるので apt-get します。
ただ、↓のような感じで結構色々必要なようでした。
4 upgraded, 140 newly installed, 0 to remove and 121 not upgraded. Need to get 66.1MB of archives. After this operation, 258MB of additional disk space will be used.
インストールが完了すると、すでに起動しています。
$ ps ax | grep mongo
28350 ? Ssl 0:00 /usr/lib/mongodb/mongod --config /etc/mongodb.conf
起動の引数になっていた設定ファイルは以下のようでした。
$ cat cat /etc/mongodb.conf
# This is an config file for MongoDB master daemon mongod # it is passed to mongod as --config parameter logpath = /var/log/mongodb/mongod.log dbpath = /var/lib/mongodb/ # use 'true' for options that don't take an argument logappend = true bind_ip = 127.0.0.1 #noauth = true
LISTEN ポートは 27017 と 28017 が追加されてました。
$ netstat -ant
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:28017 0.0.0.0:* LISTEN -
27017 が DB 接続用のポート(デフォルト)で、 それに +1000 した 28017 は管理用の Web ページのようです。
http://127.0.0.1:28017/
これにアクセスすると下の参考サイトような感じで 色々とデータベースの情報が見れるようです。
[参考]
HTTPインターフェース - Docs-Japanese - 10gen Confluence
また、データベースやクエリーを URL に設定してアクセスすると データを text/plain の JSON 形式で出力してくれるので Web サービスとしても簡単に利用できそうな気がします。
今回は配列カーソルの話です。
PHP の配列には、『現在配列のここを見てますよ』というのを覚えておくカーソルというものがあります。
例えば次のような配列があるとします。
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry');
each 関数は 配列のキーと値のペアを返しますが 使用するたびに次の要素に移動します。
$a = each($fruit); // 'a', 'apple' が代入される $b = each($fruit); // 'b', 'banana' が代入される $c = each($fruit); // 'c', 'cranberry' が代入される $d = each($fruit); // FALSE が代入される
こんなことができるのは 配列が内部的に現在の位置を覚えているためです。
次の while ができるのも同じ理由です。
while (list($key, $val) = each($fruit)) { echo "$key => $val\n"; }
カーソルを初期化するための reset という関数があります。
reset($fruit); while (list($key, $val) = each($fruit)) { echo "$key => $val\n"; }
他で参照されている可能性がある場合 上のようにループ処理の前では カーソルを初期化します。
気をつけなくてはならないのは、 カーソルは「配列を別の変数に代入すると初期化される」という仕様です。 「配列に変数を」ではなく「変数に配列を」なのがわかりにくいところです。
次のコードは無限ループになってしまいます。
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry'); while (list($key, $val) = each($fruit)) { echo "$key => $val\n"; $food = $fruit; // この処理でカーソルが初期化される }
上の処理は次の処理と同じです。
$fruit = array('a' => 'apple', 'b' => 'banana', 'c' => 'cranberry'); $food = $fruit; while (list($key, $val) = each($fruit)) { echo "$key => $val\n"; reset($fruit); // この処理でカーソルが初期化される }
今回は list の話です。
次のように、配列の形で値を返す関数があるとします。
function test() {
return array(1, 2, 3);
}
この関数から返る値を 配列を使わずに受ける場合 list という PHP の言語要素を使用します。
list($a, $b, $c) = test();
変数 $a,$b,$c に それぞれ 1,2,3 が格納されます。
list は関数ではなく言語の構造なので 変わった記述ができます。 例えば次のように 受け側の数が少なくても OK です。
list($a, $b) = array(1, 2, 3, 4); var_dump($a, $b);
int(1) int(2)
受け側の変数が 2 つなので 配列も 2 つ目までが格納されます。
次のように変数を省略することもできます。
list(, $a, , $b) = array(1, 2, 3, 4); var_dump($a, $b);
int(2) int(4)
この場合、変数を省略した 1 つ目、3 つ目は飛ばされて 2 つ目と 4 つ目の値が格納されました。
あと、list は数字がキーの要素のみ扱うので 文字列がキーの配列は無視されてしまいます。
例えば次の例では、2 つ目と 3 つ目の文字列がキーの 要素は無視されるので $a,$b には 0,1 が入ります。
list($a, $b) = array(0 => 0, 'a' => 1, 'b' => 2, 1 => 3);
次の例の場合、キーが 1 の要素が存在しないため NOTICE が発生して $b には NULL が入ります。
list($a, $b) = array(0 => 0, 2 => 2);
要するに list は次のような処理になるわけです。
list($a, $b, $c) = $array; // ↑ // この 2 つは同じ処理 // ↓ $a = $array[0]; $b = $array[1]; $c = $array[2];
そのため、キーが負の数字の場合も無視されます。
list($a, $b) = array(1 => 1, -5 => -5, 0 => 0);
この場合、$a,$b には 0,1 が入ります。
なかなか便利な list ですが、 受け側も配列の場合、気をつけなくてはならないことがあります。
list は 右側から順に値を格納していきます。
つまり次のような場合、キーの値と定義順が逆になります。
list($a[0], $a[1]) = array(1, 2, 3, 4); print_r($a);
Array ( [1] => 2 [0] => 1 )
格納される値は変わりませんが キーが 1,0 の順で定義されています。 そのため、for と foreach で結果が変わってしまうようなことになります。
for ($i = 0, $c = count($a); $i < $c; $i++) echo $a[$i];
int(1) int(2)
foreach ($a as $v) echo $v;
int(2) int(1)
さらにキーを省略した場合は もっと大変なことになります。
list($a[], $a[], $a[]) = array(1, 2, 3, 4); print_r($a);
Array ( [0] => 3 [1] => 2 [2] => 1 )
右側から順に格納されるため キーまで逆に付いてしまいます。
オマケですが、次のように list をネストさせることもできます。
list($a, list($b, $c)) = array(1, array(2, 3));
前回から間が空いてしまいましたが PHP の配列に関する話を またやっていこうと思います。
PHP の配列は キーを省略して定義することができます。
$a[] = "a"; $a[] = "b"; $a[] = "c"; print_r($a);
キーを省略した場合は その配列の最大のキーの値に 1 を足した値がキーになります。 (配列が空の場合は 0 になります)
Array ( [0] => a [1] => b [2] => c )
ただし、ここで最大値を求めるキーは 数値のキーのみになります。 文字列のキーが存在してもそれは無視されます。
$a["test1"] = "a"; $a["test2"] = "b"; $a[] = "c"; $a[] = "d"; print_r($a);
Array ( [test1] => a [test2] => b [0] => c [1] => d )
このように文字列のキーは無視して 数値のキーが設定されます。
次のようなこともできます。
$a["test1"] = "a"; $a[] = "b"; $a["test2"] = "c"; $a[] = "d"; print_r($a);
Array ( [test1] => a [0] => b [test2] => c [1] => d )
この仕様を利用して 配列のキーを 1 から始めることもできます。
$a[1] = "a"; $a[] = "b"; $a[] = "c"; print_r($a);
Array ( [1] => a [2] => b [3] => c )
次のようにキーの値の間が空いていても詰められません。
$a[10] = "a"; $a[] = "b"; $a[20] = "c"; $a[] = "d"; $a[5] = "e"; $a[] = "f"; print_r($a);
Array ( [10] => a [11] => b [20] => c [21] => d [5] => e [22] => f )
PHP 4.3 からキーの最大値が、
負の数値の場合
キーは最大値 +1 ではなく
0 になります。
$a[-5] = "a"; $a[] = "b";
Array
(
[-5] => a
[0] => b
)
lua は変数に型を定義しませんが 型は存在します。 他の型のない言語と同じように 変数に色々な型を入れることができます。
適当に試してみます。
$ lua >
対話モードに入りました。
> = type(a)
nil
type は引数の型を返す関数です。
変数 a が定義されていない状態では nil を返します。
> a = "test" > = type(a) return > a = 2.2 > = type(a) number > a = true > = type(a) boolean > a = {1,2,3} > = type(a) table
変数には関数も入れることができます。
> a = type > = type(a) function
当然、次のようなこともできます。
> a = type > = a(a) function
lua は変数に型がない言語としては かなり速いそうです。
適当に試してみます。
$ time lua -e 'for i=1,1000000 do j=i end' real 0m0.029s user 0m0.030s sys 0m0.000s
$ time perl -e 'for($i=0;$i<1000000;$i++){$j=$i;}' real 0m0.143s user 0m0.150s sys 0m0.000s
$ time php -r 'for($i=0;$i<1000000;$i++)$j=$i;' real 0m0.160s user 0m0.140s sys 0m0.020s
$ time bash -c 'for ((i=0;i<1000000;i++)) do j=i; done' real 0m6.276s user 0m5.910s sys 0m0.180s
厳密な比較ではないですが なんとなく速そうですね。