周回遅れのPiece Network 1レポート

今更ですがPiece Network 1のレポートというか、発表しての感想をば。資料は来週末ぐらいを目標に、紹介しきれなかったSPLクラスの分も加筆して公開します。

SPL入門

「SPL入門」というタイトルで話させていただきました。
SPLは「これまでできなかったことができるようになる」タイプの拡張モジュールではなくて、「これまでと同じことをPHP5のオブジェクト指向的な書き方で実現する」ものなので、SPLを使うことによるメリットを伝えるのは難しかったです。唯一の分かりやすい例としてRecursiveIteratorIteratorを紹介できたのは良かったのではないかと思っています。
また、おそらくこれまでの一生で言った回数よりも多く「Iterator」と言いました。「RecursiveIteratorIterator」の発音しづらさはガチ。


RecursiveDirectoryIterator + RecursiveIteratorIterator使用例:

<?php
// RecursiveIteratorIteratorを使うとRecursiveIteratorの
// getChildren()を自動で呼んでくれるので再帰を意識せずに書ける
// ただし、 hasChildren()がtrueを返した要素は無視されるので
// 用途によっては使えない場合もある
$dir = new RecursiveDirectoryIterator('/usr/local/share/pear/piece');
$iter = new RecursiveIteratorIterator($dir);

// $entryに代入されるのはRecursiveDirectoryIterator::current()が返した値
foreach ($iter as $entry) {
    if ($entry->isFile() && $entry->getBasename() == 'Config.php') {
        echo $entry->getRealPath(), "\n";
    }
}

反省

土壇場で資料を作る悪い癖のため、発表時間の見積もりを完全に誤っており、なんと持ち時間を半分以上のこしてスライドが終わってしまいました。これはいかんです。

即興

そこで余った時間を急きょ例の無名関数パッチの紹介に振り替えさせていただきました。当然資料など何もないので、完全にアドリブで。かなり受けが良くてほっとしました。
年内にはこれをPHP 5.3向けに作り直し、テストケースも作成したものを本家php.internalsに投げる計画です。5.3の仕様が固まっていない今がチャンス!*1

phsh最高

で、そのプレゼンではphshを使わせていただきました。
PHPカンファレンスのLT以来ずっと気になっていたphshですが、実際に使ってみたのは発表の2日前でした。もう感動ですよ。インタラクティブシェルがあるとちょっとしたコードのテストがすごく楽になるし、今回のような即興のプレゼンでは絶大な威力を発揮してくれました。


プレゼンで使ったphshの複数行ステートメント対応パッチ (やっつけ):

--- phsh.orig
+++ phsh
@@ -88,14 +88,27 @@
         }
 
         readline_read_history($this->options['history_file']);
-        $__phsh = array();
+        $__phsh = array('line' => '', 'continue' => false);
         @ob_flush();
 
         while (true) {
-            $__phsh['line'] = $this->modifyCommandLine($this->addHistory(
-                readline('<?php ')));
+            if ($__phsh['continue']) {
+                $__phsh['line'] .= $this->modifyCommandLine($this->addHistory(
+                    readline('..... ')));
+            } else {
+                $__phsh['line'] = $this->modifyCommandLine($this->addHistory(
+                    readline('<?php ')));
+            }
             if ($__phsh['line']) {
-                $this->printResult(eval($__phsh['line']));
+                if (strpos('{([', substr($__phsh['line'], -1)) !== false) {
+                    $__phsh['continue'] = true;
+                } else if (substr($__phsh['line'], -1) == '\\') {
+                    $__phsh['line'] = substr($__phsh['line'], 0, -1);
+                    $__phsh['continue'] = true;
+                } else {
+                    $this->printResult(eval($__phsh['line']));
+                    $__phsh['continue'] = false;
+                }
             }
             @ob_flush();
         }
@@ -113,6 +126,12 @@
             $new_line = '';
         } else if (substr($new_line, -2) == '?>') {
             $new_line = 'exit;';
+        } else if (substr($new_line, -1) == '\\') {
+            // pass
+        } else if (strpos('{([', substr($new_line, -1)) !== false) {
+            // pass
+        } else if (strpos('])}', $new_line[0]) !== false) {
+            $new_line = "{$new_line}; return;";
         } else if ($this->isCallable($new_line)) {
             $new_line = "{$new_line}; return;";
         } else {

*1:PHPはRCが出てからどころかマイナーリリースでも仕様が変わるじゃん!というツッコミ禁止