October 28, 2008

PHP の foreach のポインタにまつわる変な挙動

PHP の foreach でポインタにまつわる変な挙動に遭遇しました。
PHP のバージョンは 5.2.4 です。

foreach で配列のポインタを使う

例えば以下のようなコード。

<?php
$array = array("a", "b", "c");

foreach ($array as $index => $item) {
    if ($index == 2) {
        // 3番目の要素だけ「X」に変える
        $item = 'X';
    }
}

var_dump($array);
?>

これの出力は以下のようになります。

array(3) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
}

3番目の要素の値が「X」になってませんね。
これはコードを以下のように書き換えることで期待通りに動作させることができます。

<?php
$array = array("a", "b", "c");

foreach ($array as $index => &$item) {
    if ($index == 2) {
        // 3番目の要素だけ「X」に変える
        $item = ‘X’;
    }
}

var_dump($array);
?>

foreach の中で使用する変数である「$item」の頭に「&」を付けています。
こうすることで、変数「$item」が配列の各要素へのポインタになります。
これを実行すると以下のように出力されました。

array(3) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "X"
}

期待通りですね。
よかったよかった。

って、これで終わりじゃないんです。

配列の挙動が。。。

次に、以下のようなプログラムを実行してみます。

<?php
$array = array("a", "b", "c");

foreach ($array as $index => &$item) {
    if ($index == 2) {
        // 3番目の要素だけ「X」に変える
        $item = ‘X’;
    }
}

//var_dump($array);

foreach ($array as $index => $item) {
    echo $item . “\n”;
}
?>

さっきのプログラムの後ろに foeach で配列の要素を順番に出力する処理を付け足しているだけです。
これを実行すると以下が出力されました。

a
b
b

ん?、最後の要素は「X」のはずなのに「b」と出力されています。
どういうことでしょう?

いろいろ実験した結果、以下のコードでこのおかしな現象を再現できることがわかりました。

$lt;?php
$array = array("a", "b", "c");

foreach ($array as $index =$gt; &$item) {
}
var_dump($array);

foreach ($array as $index =$gt; $item) {
}
var_dump($array);
?$gt;

二つの foreach ループを回しているだけです。
一回目の foreach ではループ変数に要素へのポインタを指定しています。
これを実行すると以下のように出力されます。

array(3) {
  [0]=$gt;
  string(1) "a"
  [1]=$gt;
  string(1) "b"
  [2]=$gt;
  &string(1) "c"
}
array(3) {
  [0]=$gt;
  string(1) "a"
  [1]=$gt;
  string(1) "b"
  [2]=$gt;
  &string(1) "b"
}

二回目の foeach の後に配列の中身がおかしなことになってますね。
配列の最後の要素が「c」ではなく「b」になってます。
なんでこんなことになるんでしょうか?

ていうか、何もしない foreach 文を二つ書くだけで配列の挙動がおかしくなってしまうなんて素敵な言語ですね!

調べた

ちょっと調べてみたんですが、

PHP 5 以降、$value の前に & を付けることで、 容易に配列の要素の値を変更できるようになっています。 これにより、値をコピーするのではなく、 リファレンス が代入されます。
[略]
警告
foreach ループを終えた後でも、 $value は配列の最後の要素を参照したままとなります。 unset() でその参照を解除しておくようにしましょう。

PHP: foreach - Manual

ということらしいです。

foreach でループ変数にポインタを使った場合、foreach を抜けた後に unset() を呼ぶ必要があるんですねぇ。
(foreach 側で自動でやっておいてくれたらいいのに。。)
というわけで、さっきのコードを以下のように変えてみました。

$lt;?php
$array = array("a", "b", "c");

foreach ($array as $index =$gt; &$item) {
}
var_dump($array);

// ポインタをリセット
unset($item);

foreach ($array as $index =$gt; $item) {
}
var_dump($array);
?$gt;

一回目の foreach の後に「unset($item);」を追加しています。
出力は以下のようになりました。

array(3) {
  [0]=$gt;
  string(1) "a"
  [1]=$gt;
  string(1) "b"
  [2]=$gt;
  &string(1) "c"
}
array(3) {
  [0]=$gt;
  string(1) "a"
  [1]=$gt;
  string(1) "b"
  [2]=$gt;
  &string(1) "c"
}

おお、ちゃんと期待通りの値が出力されました!

でもまだ納得いかないんですよねぇ。
ポインタをリセットしないと二回目の foreach で配列がおかしくなるっていうのが解せないです。
なんでだろ。

PHP ってほんと難しい言語ですね。
こういうところが PHP の魅力なのかもしれませんね(違っ)。

追記
こちらの解説が詳しいです。
foreachの$valueを参照で受けると思わぬバグを引き起こす - ぱせらんメモ
そういうことだったんですね。

October 27, 2008

Rails勉強会@東京第34回に参加してきました

後で書く。

追記

Rails勉強会@東京第34回に参加してきました。

勉強会と呼ばれるようなものに参加するのはこれが初めてです。
いやー、行ってよかったです。

勉強会の前半は Yuumi3 さんの「Scaffoldの半歩先へ」という Rails 初心者向けのセッションに参加しました。
Yuumi3 さんは Ruby on Rails のセミナーやってたり、Gauche on Rails なんかも作っていたりするすごい人です。
そんな人に教えてもらえる勉強会っていいですよね。
教えてもらってばっかりじゃだめだと思うんですが、まだまだ僕は初心者です。

やっぱり Ruby とか Rails にもっとコミット(ソースをコミットするとかじゃなくて)していかないとだめだなぁ、と思いました。
だって、知れば知るほどおもしろいですからね、Ruby も Rails も。
(ちなみに、PHP は知れば知るほど嫌いになる言語な気が最近すごくしてます)

Rails や Ruby は、ただ使い方を覚えるだけじゃなくて、その思想を理解する必要があると思うんですよねぇ。
Ruby や Rails の目指していることろって、如何にスマートに問題を解決するか、ってところだと思うんですよ。
実際に Rails でバリバリ開発している人の話を聞いてると、そういった思想とか考え方みたいなものがすごく伝わってくる気がするんですよね。
こういうのが勉強会のいいところなんだなぁと思いました。

勉強会の後半は Yugui さんによる「Railsのリファレンスを全部読む」というセッションでした。
話のスピードにちょっとついていけないところもあったんですけど、Yugui さんの独り言みたいな喋りともろはしさんの親切な解説がなかなか良かったです。
「リファレンスを全部読む」っていうのは重要だなと思いました。
全部暗記しなくとも、確かこういうのがあったなくらい思い出せるだけで全然違ってくると思います。

初めての参加でかつ知ってる人もいないのでドキドキしましたが、まあ、そんな緊張する必要もなかったな、と思いました。
勉強会行きたいけどなんかドキドキするなぁなんて思って躊躇している人がいたら僕に連絡してください。
一緒に行きましょう。

追記

懇親会にも参加しました。
8人くらい来てました。
Mac と iPhone の話題で結構盛り上がってました。
MacBook と iPhone 欲しくなりました。
やっぱり新しい MacBook かっこいいですねー。
あと、id:willnet さんと話ができてよかった。

October 21, 2008

JJUG Cross Community Conference 2008 Fall レポート2

これの続き。

DOMパフォーマンスチューニング入門

講師: amachang

JavaScript は遅い遅いといわれているけど
ベンチマーク取ってみると Rerl とか Ruby 並みの速度
遅いのは DOM に 関する処理

DOM 関連の処理を分解してみると、

  1. コンポーネントとの通信
  2. DOMノードの追加
  3. スタイルの再計算
  4. レイアウトの再計算

となる。

1 コンポーネントとの通信
XPConnect や COM との通信
IE が特に遅い
無駄なプロパティアクセスを減らすと良い
→ 変数に入れるなどして

2 DOMノードの追加
ノードに「変更されたフラグ」が立つ
「parent.appendChild(child)」とすると parent と child にフラグが立つ
(DOM に対する処理をすぐに実行するのではなくて後でまとめてやるためにマークを付けとく、みたいな感じですかね。)

3 スタイルの再計算
スタイルの再計算が行われるタイミングを把握しておく必要がある
スタイルの再計算はどんな時に行われるか

  1. 変更フラグが立っているノードがあるまま JavaScript が終了した時
  2. 変更フラグが立っている状態でスタイルの再計算が必要な処理を行った時
    offsetWidth プロパティの値を取得したり

処理の順番を意識する必要がある
スタイルの再計算が行われるエレメントを意識する必要がある
子ノードとか下にあるエレメントとかもスタイルの再計算が行われる

4 レイアウトの再計算
要素の幅、高さ、位置の計算がここで行われる
激しく重い
→ 親ノードにも影響を及ぼすことがあるので
基本、スタイルの再計算に気をつけていればいい

プロファイラのデモ
各メソッドの実行時間とか、呼び出し回数なんかが簡単に調べられる
(safari 4 にはプロファイラが搭載されるらしい)

質問タイム
Q: 再計算のタイミングを知るには
A: Webkit をデバッガで起動。ログを仕込んだりして調べる。

Q: Webkit のソース解読 Tips
A: Webkit の IDL ファイルを見ると良い

ギークなお姉さんができるまで

講師: べにぢょ (アルカーナ株式会社), purprin (エスカフラーチェLLC)

個人的にはあまり興味がわかない内容でした。
おもしろかったけど。
(というか、人の話を聞くのって基本おもしろい。退屈な話しかしない人もいるけど、自分が何を考えているのかということをちゃんと話そうとして話している人の話はだいたい面白い。)
purprin さんの話がもうちょっと聞けたらよかったかも。
Web デザインの話とか。

『JavaからRubyへ』・アンド・ナウ

講師: 角谷 信太郎 (株式会社永和システムマネジメント), 高井 直人, 和田 卓人

Java から Ruby、EJB から Rails という流れの裏にどのような歴史があるのか、というようなお話
以下はスピーカーの方達のブログ記事。

YET ANOTHER GREEN IT

講師: 和田 卓人, 角谷 信太郎 (株式会社永和システムマネジメント)

息が合えばペアプログラミングってすごく楽しそうだなぁと見てて思った。
こういうセッションも楽しいですね。
他人が開発してるところとか普段そんなに注意深く見てないし。

Agileは現場に適用できるのか? ~オンナだらけのパネル・ディスカッション~

講師: 片山 智咲子 (Java Edge), きたむら (日本XPユーザグループ), 柳本芙友子 (要求開発アライアンス)

なにかこう、釈然としないディスカッションでした。
アジャイルという言葉の意味が人によってまちまちだなぁ、とすごく思いました。

java-jaプレゼンツ・第十一回 第2回チキチキ JJUG だよ全員集合 ライトニングトーク大会

おもしろかったです。
え?、西尾さんビーズの話して終わり?みたいな。

読書: ソフトウェア開発者採用ガイド

ソフトウェア開発者採用ガイド ソフトウェア開発者採用ガイド
青木 靖

翔泳社 2008-03-20
売り上げランキング : 12836

Amazonで詳しく見る by G-Tools

これ読んだ。
いやー、Joel の文章はどれもいい。
書いてある内容もそうだけど、とにかく文章がいい。
例えるなら、めちゃくちゃいい絵を描く漫画家みたいな感じ。
こんなふうに書けたら(描けたら)いいなぁと思わせる。

印象に残ったところをいくつか引用。

この6年の間、友人のマイケルと私でソフトウェア会社を率いてきた。私たちは最初の最初から第一に優先することは優れた人を採用することだと考えていた。どんなソフトウェアを作るか考える前からだ。そうしてその年月の間、優れた人たちが私たちのところで働きたいと思うようにすることに注力し続けた −− まだ誰かを雇えるようになる前からだ。私たちはいくつか間違いをし、そこから多くを学んだ。今では優れた人を得るというのは Fog Creek にとって唯一問題を感じないことと思えるほどになった。

逆にいうと、すごいアイデアがあったとしても優秀な人間がいないと実現に至らないんだよなぁ。
金で技術は買えるかもしれないけど、見極める力がなくて間違った技術を買っちゃったらどうするの?、とかも思う。
A ランクの人は自分よりも能力のある人を雇い、B ランクの人は自分よりも能力が劣る人を雇う、みたいな話があったな。

ソフトウェア会社を作るのは、それまで解けなかった何かの問題を解決する巧妙なアイデアを見つけて実現し、それによって富を得るのが目的なのだ、と一般には信じられている。これを「より良いねずみ取り作りの信条」と呼ぶことにしよう。しかしソフトウェア会社の本当の目的は、資本を役立つソフトウェアへと変えることであるべきなのだ。

Joel が言いたかったことからは若干ずれるかもしれないけど、最近僕はこんなふうに考えてる。
「誰でもすごいアイデアを思いつけるわけじゃない」
というか、人間の発想なんてたかが知れてる。
すごいアイデアで何かを成し遂げたい!って思うのは、そうすることがすごく魅力的に見えるからだと思う。
なぜそれが魅力的に見えるかというと、すごいアイデアで何かを成し遂げるということができていない今の自分が全然魅力的に見えないからなんだよね。
状況を変える何かが欲しいんだよね。
とにかく努力あるのみ。
中途半端な努力で思いつくようなアイデアなんて誰もが思いつくようなものばかりだと思う。

開発者が現在の作業のために最適でないプログラミング言語を、それがボスの好みだからという理由で使うように言われることほど、彼らを憤慨させることはない。人々が厳格に能力によって昇進するのではなく、コネによって昇進することほど、彼らを怒らせることはない。組織で自分より上にいるか、より強いコネをもった人間が要求しているために、技術的に劣った方法でやらなければならないということほど、彼らをムカつかせることはない。

まあ、これはその通りですね。
プログラマじゃなくてもこういう事態になったら普通怒ると思うけど。
ただ、ちゃんとした根拠もなく最新の技術を使いたいとかお気に入りのフレームワークを使いたいとか言うのはちょっと違う。
あくまでその状況において最適な技術・ツールは何か、ということをちゃんと考える必要がある。

私たちの信条は長期的視点で採用するということだ。現在たまたま知っているどんな技術も、来年には古くなっている可能性がある。しかもそれらの技術の中にはいとも簡単に学べるものもある。 [略] 基本的に優れたソフトウェア開発者には、別なプログラミング言語を学ぶというのはまったくたいしたことではないのだ。彼らは2週間で非常に生産的になっていることだろう。2年後には、まだ発明されていないプログラミング言語でまったく違ったことをやってもらっているかもしれない。

これもその通り。
Joel の話からはちょっとそれるけど、僕が前から思っているのは「PHP しか知らない人は PHP すらも知らない」ということ。
他の言語を理解するということは、その言語の理解も深めることにもなる。
そもそもプログラミングを学ぶというのはそういうことだと思うんだけどなぁ。
あ、Lisp 勉強しないと。

問題のある開発者の多くは、単純に優れた開発者になるための素養を欠いているものだ。頭は良いがポインタや再帰を決して理解できない人がいるというのは私が強く思っていることだ。

そうかもしれない。

October 18, 2008

JJUG Cross Community Conference 2008 Fall レポート1

レポートっていうほどのアレでもないけど。

JJUG Cross Community Conference 2008 Fall というイベントに参加してきた。

その感想など。

CloudとAndroid 丸山 不二夫 (早稲田大学)

話題が多方面にわたって、ついていくのがやっと。
結局のところ、何がいいたいのかよくわからなかった。
んー、まあ、クラウドですよクラウド(よくわかってない)。
で、インフラが重要であると。
Google はクラウドを実現するためのインフラを作り上げた。
ネットワークが高速化するとコンピュータのあり方が変わってくる。
分散。
プログラムの組み方も変わってくる。
リレーショナルデータベースは時代遅れに。キー・バリュー型へ。

Android
携帯のオープン化の動きは非常に重要
携帯市場は巨大
デジタルデバイドの終焉
新しい市場の可能性

Hudsonによる継続的インテグレーション - 川口 耕介 (Sun Microsystems, Inc. senior staff engineer)

個人的にはこれが一番ささった。

マシンをフル活用せよ!
人件費に比べたらマシンのコストなんて安い。
自動化!

Hudson
Java 製の CI サーバー
ビルドやテスト等のタスクを自動化

このツールはすごーく便利そう。
UI もよさげだし。
もうちょっととっつきやすい名前だったらいいのになぁ。
あと CI(継続的インテグレーション)という言葉も堅苦しい感じがする。

続きはまた後で。

追記:
書いた

October 15, 2008

FriendFeed のウィジェットがいい

FriendFeed のウィジェットがいい。

↓こんな感じのをブログのサイドバーに貼り付けてる。
friendfeed.png

Web 上でのパブリックな僕の行動のほとんどが FriendFeed に集約されてる。
だからどうしたというわけでもないけど。

ウィジェットの作成は以下から。
FriendFeed - Embed

google_en2ja.user.js - Google で翻訳してくれる Greasemonkey スクリプト

Google で翻訳してくれる Greasemonkey スクリプトを作りました。
Web ページ上の英文を日本語に翻訳することができます。

更新履歴

2.0 - 任意のテキストを入力しての翻訳もできるようにしました。詳しくは以下。
System.Exit - google_en2ja.user.js をもうちょっと便利にしました

スクリプト

google_en2ja.user.js

使い方

翻訳したい英文を選択し、左上の四角やつにカーソルを合わせてください。

en2ja_2.png

すると、翻訳された文章が出てきます。

en2ja.png

感想

他に似たようなツールがある気はするんですけど、探すよりは作った方が早い気がしたので作りました。
でも Google の翻訳精度ってなんか微妙なんですよねぇ。