2012-03-08

"Pyrus 動かない" - その 3つの現象と対応

PEARパッケージを入れる場合に遭遇するかもしれない3つの現象について現在の回避作を個人的に記します。
ちなみに、pyrusのBTSはgithubですのでそちらもご確認ください。
https://github.com/pyrus/Pyrus

なお、動作がおかしいと思ったら、
はじめに、

$ pyrus ./vendor install pear/FSM

を試してみてください。
すくなくともphpソースだけのpear/FSMではインストール時にトラブルにならないと思います。
また、pyrusの設定の確認コマンドはalpha4からgetの引数なしに統一されました。

$ pyrus get

vendorフォルダ指定時は

$ pyrus ./vendor get

です。

なお、以下の各説明コマンドは便宜的にvendorフォルダ指定なしでの記載です。

1. bin_dir が再指定されていない。

scriptsファイル(binファイル)を含むパッケージをインストールする場合に遭遇します。
PHPUnitなどの場合に該当します。先日もかいたとおり

php $PYRUS ./vendor set bin_dir /home/yourname/tmp/vendor/bin

と set bin_dirしておきます。

2. package.xml (PEAR1) がおかしい

今まで(旧来)のPEARパッケージをインストール際に遭遇します。
順を追って確認します。今回はopenpear.org/Wozozo_Unkoを例に取ります。

  • パッケージファイルがダウンロードできるか
$ pyrus download openpear.org/Wozozo_Unko

ダウンロードできたら、そのtgzファイル指定でインストールできるか確認します。

$ pyrus download openpear.org/Wozozo_Unko-3.0.0.tgz 

以下のようなエラーが出た場合はインストールしようとするpackage.xmlでのパスがおかしいです。

Unable to make directory Wozozo_Unko/./src/bin/ in /home/sasezaki/tmp/pyrus/vendor/.journal-data

展開してpackage.xml中身を確認します

$ tar xzvf Wozozo_Unko-3.0.0.tgz 

とくにcontentsノードのファイルを確認します。
今回の場合、

 <contents>
  <dir baseinstalldir="." name="/">
   <file baseinstalldir="." md5sum="0794a66ee8488556584c0ef290252df0" name="src/bin/wozozo" role="data" />
   <file baseinstalldir="." md5sum="845385b585b74eb13e7cbc9028e99077" name="src/Wozozo.php" role="php" />
  </dir>
 </contents>

となっているのでむちゃんこ怪しいです。(とくにbaseinstalldir=.)

再度パッケージできるか確認します。

パッケージをtarコマンド展開したあとは、ディレクトリ直下は

  • package.xml
  • Wozozo_Unko-3.0.0

となっているはずなので、

$ mv package.xml Wozozo_Unko-3.0.0

とpackage.xmlを移動し、

$ pear package

でパッケージングし、
ただしくパッケージングできるか確認します。(今回の場合)

Analyzing src/Wozozo.php
Warning: in Wozozo.php: class "Wozozo" not prefixed with package name "Wozozo_Unko"
Warning: Channel validator warning: field "date" - Release Date "2011-02-21" is not today
Warning: Channel validator warning: field "version" - major version x in x.y.z may not be greater than 1 for any package that does not have an <extends> tag

といったエラーです。

pyrusでpackage.xmlをmakeしなおしてみます。

$ pyrus make 

package.xml とpackage_compatible.xmlが生成されると思います。これでまた pyrus packageとしてもエラー(おそらくダウンロードしたpyrus.phar alpha4だとCannot locate PEAR2/Exception.php)となると思います。
pyrusにてmakeしても

 <contents>
  <dir name="/">
   <dir name="src" baseinstalldir="/">
    <dir name="bin">
     <file role="php" name="wozozo"/>
    </dir>
    <file role="php" name="Wozozo.php"/>
   </dir>
  </dir>
 </contents>

となっており、phpファイルではないscriptsファイルが混ざっているのが原因です。 (file roleが php やdataではなく scriptが正しい)

$ mkdir scripts
$ mv src/bin/wozozo scripts/wozozo 
$ rm -rf src/bin

としてscriptsフォルダへ移動し、makeしなおすと、

 <contents>
  <dir name="/">
   <dir name="scripts" baseinstalldir="/">
    <file role="script" name="wozozo"/>
   </dir>
   <dir name="src" baseinstalldir="/">
    <file role="php" name="Wozozo.php"/>
   </dir>
  </dir>
 </contents>

と生成され、package & install にてインストールされるはずです。

【※依存するパッケージが怪しい場合】

ノードにいくつかパッケージを含む場合は、それらをコメントアウトして依存パッケージなしで入るか確認します。

パッケージをtarコマンド展開したあとは、ディレクトリ直下は

  • package.xml
  • Wozozo_Unko-3.0.0

となり

$ mv package.xml Wozozo_Unko-3.0.0

とpackage.xmlを移動し、依存パッケージをコメントアウトしたあと

$ pyrus package

でパッケージングし、

$ pyrus install Wozozo_Unko-3.0.0.tgz

で再度インストールしてみてください。


また、上記とはべつにpearinstallerのバージョン指定が古いだけの場合
がありますが、そちらはバージョンを書き直したりしただけでインストールできる場合もあります。

3. 設定ファイルを壊した

pyrusのコンフィグでの各パス値に相対パスなどにしたほか、不明な値にしたときに遭遇します。
ちなみに、pyrus起動時にパス設定するよう求められますが、ここもフルパス指定じゃないとダメげです。
unix系の場合は、$HOME/.pear windows7などの場合はドットなしの $HOME\pear (c:\Users\yourname\pear など)
がpyrusの設定フォルダですのでそちらを一時的にどかすかなどで初期化して確認を行います。


なお、本格的にpyrusをデバッグしたいかたは、開発用セットアップについて以下のページに記載があるので確認ください
https://github.com/pyrus/Pyrus/wiki/Developing-for-Pyrus

2012-03-07

PHP 5.4.0 でArray to string conversionがarray_diffで発生してフルコンボだドン!

要約

array_diff、array_diff_assocで多次元配列のときにE_NOTICEが発生するってことだドン!

PHP 5.4.0で実行すると、

となるのだドン!



以下は遭遇した時のお話だドン!

さて、今日もcontributeという名の時間のコインを投入するのだドン!
ZF2は先日のリリースで PHP 5.4 Support とか大判振る舞いしちゃってるので再確認するのだドン!

テストを動かしてみるドン!


エラーが出たドン!ソースを確認してみるのだドン!

対象行の変数をvar_exportして再現させてみるドン!

$ ~/php/php-5.4.0/sapi/cli/php 6_MvcTest_2.php
$

あれー?

あ、error_reportingを忘れていたドン!
先頭にerror_reporting(E_ALL);を追加して再実行だドン!

マニュアルをよく読めってことだったドン!

注意: この関数は、N 次元配列の一次元だけを調べます。もちろん、例えば array_diff_assoc($array1[0], $array2[0]); とすることにより、より深い次元でチェックを行うことも可能です。
http://jp2.php.net/array_diff_assoc

ちなみに、PHP5.3だとこのE_NOTICEはでないのだドン!

関連
array_diff()は文字列比較だから注意してね | Suinasia

2012-03-05

俺の彼女と幼なじみとPHPとAutoloadが修羅場すぎる(classmapのはなし)

PHPのことを一晩中考えてる皆さん!Autoload使ってますか!

- 「PHP5.3世代の最新フレームワーク使ってるから当然使ってるよ!」(キリッ!)
- 「is_aの挙動の変更はまさにPHPっぽいと断言できる!」(キリッ!)
- 「vendor/.composer/autoload.phpをリクワイアするのハもうオーベイではジョーシキデース!」(キリッ!)

なるほど!!


残念!そちらのPHPのオートローディング機能そのものではなく、
http://jp.php.net/autoload

theseer/Autoload のほうです。
https://github.com/theseer/Autoload

PHPカンファレンスのスライドにも載っけてます。
http://www.slideshare.net/sasezaki/php-9151036/51


PHPカンファレンスでも話した通り、psr-0に沿えば良いし、SplClassLoaderとか使って、spl_autoload_registerにクラスローダと名前空間を登録すれば良いと思います。最近のライブラリ使って開発してる限りでは。。で、上記スライドに挙げてる通りパフォーマンス上の問題もありますけれども、psr-0に沿わないクラスファイルローディングにも効力を発揮するのが、theseer/Autoloadです。

githubでの説明では"A lightweight php namespace aware autoload generator"となってますが、要するにclassmap generatorです。

classmap?

クラス名とファイル一覧のセットを指します。
http://www.slideshare.net/sasezaki/php-9151036/50

念のために言うと、autoloadが実行されたときにこのclassmapに基づきファイルがロード(遅延ロード)されるため、
すべてのファイルをindex.phpとかブートストラップなところでrequire_onceを全て書いてるのとかは意味が違います。

使い方

  • ヘルプ

$ phpab -h

でヘルプがでてきます。

(Miffieの例)

$ phpab -n -b src/Miffie -o src/Miffie/Autoload.php -i "src/Miffie*" src

pyrus genereate-pear2で作った雛形(ようするにsrcがコンポーネントdirの場合)だとこんな感じ、で下のようなものができます。

<?php
// @codingStandardsIgnoreFile
// @codeCoverageIgnoreStart
// this is an autogenerated file - do not edit
spl_autoload_register(
    function($class) {
        static $classes = null;
        if ($classes === null) {
            $classes = array(
                'Miffie\\CLIRunner' => '/CLIRunner.php',
                'Miffie\\GetoptExt' => '/GetoptExt.php',
                'Miffie\\Spider' => '/Spider.php'
            );
        }
        if (isset($classes[$class])) {
            require __DIR__ . $classes[$class];
        }
     }
);
// @codeCoverageIgnoreEnd
  • 配列の返却のみにしたい場合

-t(--template)の引数に作成したテンプレートを用意します。

↑のファイルを-tオプションの引数に指定すると、↓といったアウトプットになります

<?php
return array(
'Miffie\\CLIRunner' => '/CLIRunner.php',
                'Miffie\\GetoptExt' => '/GetoptExt.php',
                'Miffie\\Spider' => '/Spider.php'
);
  • アレなソースの判定にも使える

昔のソースだとif分岐でclass定義を2回書いてたりしますので、wordpressフォルダ配下で

$ phpab wp-includes

なーんてやると、

phpab 1.6.0 - Copyright (C) 2009 - 2011 by Arne Blankerts

Error while processing request:
 - Redeclaration of class 'services_json_error' detected
   Original:  wp-includes/class-json.php
   Secondary: wp-includes/class-json.php

エラーになるので、エラーとなったコードファイルの個別対応が必要になりますがtolerantオプションで無視するか--excludeオプションで、

$ phpab -n -e "*class-json.php" wp-includes

とやると一応class-json.phpを無視した形でのクラスマップは作成できます。

名称(phpab)について

さて、このAutoload(phpab)名前が紛らわしい。googleビリティへの配慮が欠けてる。と思われるかも知れませんが、thePHP.ccの面々は前々からこんな感じのプロダクト名ばっかりなので気にしたら負けです。ちなみにphpabはAutoloadなんとかの略ではなく、作者が Arne Blankerts のためその略だと思われます。んがんぐ。

あれZend Framework2にも似たものが?

はい、ありますね。。
http://framework.zend.com/wiki/display/ZFDEV2/Proposal+For+Autoloading+In+ZF2
微妙に違って、https://gist.github.com/1601031のように手を加えないとだめそうです。

2012-03-04

任意のPHPのバージョンと、任意のPHPUnitのバージョンを組み合わせて実行する。

3ヶ月前にgistに書いてtwitterでつぶやいたきりでしたが、こっちにも記載。
いくつか方法はありますが、たぶん最低限の方法で、
任意のPHPのバージョンと任意のPHPUnitのバージョンを動かす方法です。
Ubuntuの場合を中心に書きますが、Windowsとかでもフルパス指定でやれると思います。

  • 任意のPHPをmakeまでします。(方法割愛)
  • 任意のPHPUnitをpyrusで任意のフォルダにインストールします。

PHPUnit 3.5の場合

3.4と3.5だとezComponentへの依存がありましたが、3.6からはなくなってようです。

  • bin/phpunitのインクルードバスを設定しなおします。

PHPUnit 3.5の場合

set_include_path(dirname(__DIR__).'/php' . PATH_SEPARATOR . get_include_path());

require_once 'PHP/CodeCoverage/Filter.php';
PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'PHPUNIT');

/**
if (strpos('/usr/bin/php', '@php_bin') === 0) {
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
}*/

  • 実行します

trunkのPHPに、phpunit3.6で実行する場合

$ ~/php-src-trunk/sapi/cli/php ~/tmp/phpunit36/bin/phpunit -c tests/phpunit.xml tests/Zend/Acl

たぶん、phpunit3.7だとpharバージョンが提供されそうなので苦しまなくてもいいかも。

関連リンク

頻度が多い場合はちゃんとphp-buildとphpenv使ったほうがいいと思います。はい。

2012-03-03

最速PHPフレームワーク研究会 (pecl的な意味で)

Yaf

- http://www.php.net/manual/en/book.yaf.php
- Controller、View、Router、Configについての機能をそなえる
- http://blog.tojiru.net/article/231387723.html:title=http://blog.tojiru.net/article/231387723.html
- パフォーマンス記事 / http://www.laruence.com/2011/12/02/2333.html
- 作者は、最近PHPコアで活躍のLaruence氏

autocracy

- https://github.com/mike-php-net/autocracy
- pecl_http v2 に対するContoller部分はphpで実装が上記のもの
- http://mike-php-net.blogspot.com/2012/03/introducing-autocracy.html
- 作者はpecl_httpのmike
- PHP5.4以上が必要

phalcon

- http://phalconphp.com/
- Yaf同様Contoller、View、なども備えてるがORMを備えたのは世界初
- パフォーマンス記事 / http://phalconphp.com/documentation/benchmark
- peclには申請中

2012-03-03

PHP スライド・ベスト10

PHP界隈でまたイライラすることがあったが、ちょっと落ち着くために今まで個人的に見たスライドの中で勝手に決めたベスト10をここで紹介したいと思う。というのも、最近だとこれとか見るに「あれ、あんましスライドチェックって皆しないの。。」と思ったからで、改めて紹介していないと見過ごされてるかも、モッタイナイと感じたからだ。(そういえば自分の情報源について謎とか言われることがあるが、ここで紹介するのはjoind.in経由で知ったのが半分ほど。なのでPHP関連の情報に飢えてる人はjoind.in見たほうがいいかも知れないが、「またレビュー身内ぼめやんけ」とかジャンクなスライドとかに時間を浪費することになるのでネットウォッチ気質がない人には薦めない)

moriyoshiさんが2009年のPHPカンファレンスに行った発表のスライド。まじで自分がPHPについて無知だと思い知らされ、消沈して終わりだったが、何人かの日本人開発者のコアに対するやる気を鼓舞している。PHPコアに対する解説については情報が少ないとよく言われるが、phpcredits()に出てきたメンバー名をググればいくつかサイトにスライドが掲載されてるのが確認できる。だが、いままでコアに対する解説スライドで一番概要が分かるのがこれだと思う(何せ日本語ですしね!)



Objects for the Masses / Marcus Börger
20120303000030
昨年のPHP勉強会で自分が発表にも登場させたMarcus BörgerによるOOPの解説。よくあるOOP解説に見受けられる内容も多々あるが言語設計者の一人だけに抜かりない解説となっている。(Zend Engineの解説とかは少なめ)


出落ち。


と言ったら、それまでだが今まで知っている発表タイトルで一番印象に残っているのがこれ(掴み大事)。
もともとは、この発表時期の前後あたりでRasmusが、"Hello world"のベンチマークをして遅いよねというパフォーマンス第一に考えるRasmusの発表(talk.php.netにあると思う)が知れ渡っていた時期のもの。内容はフレームワーク潮流の内容なので今見てもおそらく新鮮味なし。


ZFリードのweierophinneyによるモデルについてのスライド。
と言っても一応ZFコードそのものは出てこず、サービスレイヤ・ORMでのプラクティスについて解説してある。
サービスレイヤについてはZFのクイックスタートのコードにはついて来ないことも、あって教科書的なサンプルコードをお探しかも知れない。ZFCR Teamの一員Akrabatのこのリポジトリがそれにあたるだろう。(Akrabatのこのスライドや、noopableさんのZF勉強会でのスライドは見逃せない)



コンポーネントライブラリ作成については現時点でもっとも突っ込んだ内容と言えるのが、イギリスのカンファレンスでは常連であるStuart Herbert。QAツールを含めライブラリ作成のphingタスクなどをがっしり詰め込んだphixを使えば、gitでのタグ付けなどを踏まえたpearパッケージ作成・サーバ作成・配布がたちどころに行えるが、ただちょっとphix自体に癖がある。。。



スライドの冒頭にもあるとおり、エラーや例外の話は退屈かも知れない。だが、個人的には仕事上運用面で(Javaだったけれど)の経験からもっともアプリケーション作成で重要だと思っている。例外についてはJavaのプラクティスのあれとかいろいろ確認して上手いこと言おうとして言えなかったのでこのスライドをぜひ参照していただきたい。


PHP Go VROOOM!-tek11
20120303000032
wordpressファンは見るのを控えたほうが良いかもしれない。なにせ"Switch to another system"という件があるから(ネタバレ)auroraeosroseというハンドルで知られる Elizabeth M Smithのスライド。この内容ではPHPにおけるパフォーマンス手法についてチップを得ることができる。PHP-Gtkなどにも携わる彼女だけに締めが"Write it in C"となっているのも納得?


セキュリティについてスライドと言えばPHPccの人のもあるんだけれど、スライドだけだとよくわからない。。各ポイントをおさえつつ、ちゃんと突っ込んだ内容になってる素晴らしい解説だと思う。(何せ日本語ですしね![2回目])。実はnazoさんとは同じ屋根の下で一夜を共にしたこともあるのだが、それでも守っていた私の心のセキュリティ、このスライドで奪われましたね。。



Jenkins浸透とともに日本でも利用者をわりと見かけるようになったビルドツールのPhing。もちろんリードのMichiel Rookの発表などもあるのだが、なんでもかんでもphingでやろうとするraphaelstoltのスライドは、phing利用に対するコツが載っているのでここではお薦めしたい。


http://www.stefan-marr.de/2010/12/php-next-traits-presentation-for-afup-in-paris/
PHPにtraitsをもたらしたStefan Marr氏自身によるTraitの解説。
。。というところで10個のスライドは以上。順番は適当です。



次点

The state of DI in PHP - phpbnl12
いやーPHPにDIの波来ちゃいましたねー(キリ)と言いつつ、いまいち掴みきれてない自分にとって実はZF2でのDI利用について、これが一番個人的には分かりやすいと思う。

2012-02-09

わぁいPhar、あかりPhar作るの大好き!

2012年はpharの年!嘘です!

みなさん、プログラムソースが1ファイルになってるの好きですか!

好きですよね!
http://www.google.co.jp/search?ie=UTF-8&q=phpspot+1%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB
ファイルの総行数が1万行超えても?

、、、ということで、PHPのためのアーカイブ形式pharについてです。
http://php.net/phar

ここ最近はpharとして提供されるものがいくつか出てきましたね!

  • pyrus.phar
  • imagine.phar
  • goutte.phar
  • guzzle.phar

また、Zend Framework 2 (http://packages.zendframework.com/) では

$pyrus download Zend_**

で、pharファイルとしてダウンロードできます。

PHP界隈での大きな流れとしてPHPUnitが3.6で下位互換性の問題が浮上したこともあり、
phpunit.phar作成についてSebastian Bergmanも前向きな姿勢がみえます。まさにpharのビッグウェーブ!といった所ですが、shimookaさんのphar紹介記事 意外と身近なphar - PHp ARchive から4年以上経ってます。そう、この記事は人類には早すぎたんだ!


基本的なpharアーカイブの作成方法はマニュアルにある通りです。・・・って書こうと思ってたらこうだよ!

そのうちにきちんと書きます。

http://www.php.net/manual/ja/phar.creating.intro.php

めちゃんこ端的なサンプルとしての作成コードは

<?php
$phar = new Phar('hello.phar', 0, 'hello.phar');
$phar->addFromString('hello.php', '<?php echo "hello";');
$phar->setStub("<?php Phar::mapPhar(); __HALT_COMPILER();");

( マニュアルの"buildFromIterator""TwigをPhar化"のbuildFromDirectoryの記事も参照してみてください)

とにかく

などをアーカイブ作成する際に考慮しておきたい基本事項です。

んで、2、3のファイルなら明示的に追加対象にすればいいのですが、

  • ディレクトリまるごとやる場合(".svn"などのignoreファイルの考慮、strip_whitspace)
  • 依存するライブラリがある場合

などちょっとややこしいですね!

GoutteやBehatは独自にCompilerクラスを作ってpharコンパイルを行っています。
そのソースを見たところだと定型処理としてツールができそうだし、ありそうですね!


pharアーカイブ作成・展開を対象としたツールはいくつかあります。

Imagineはphar-utilをguzzleはphingのタスクを使ってるようです。

このうちempireについてはPEARの開発者@hことHelgi Þormar ÞorbjörnssonのPHP Beneluxスライドで知りました。


pyrusでのpharの作成はこのような形で実現できます。

$pyrus generate-pear2 Foo __uri
$pyrus make
$pyrus package -p

上記のコマンドのうちpackage -p
はphar作成オプションでのパッケージングコマンドで、phpの設定でphar.readonly=0でなくてはだめなので、一般には

$php -d phar.readonly=0 pyrus package -p

です。
(補足として、phar作成の記事やライブラリのエラーメッセージでphp.ini変えろとか言ってきますが、上記のようにディレクティブ設定してればいいでないのん?)

あなたが単にPSR-0に沿ったライブラリ用ソースを持っていれば、上記generate-pear2で作ったひな形フォルダのsrcにファイルをぶち込めばphar作成可能です。

デフォルトのstubの方でspl_autoload_registerが作成されているので、作成されたphar形式のライブラリの使用は、

<?php require_once 'Foo-0.1.0.phar';

となります。

また、この pyrus package -p で作成したpharファイルは、PEARだと、*.tgzでおなじみだったPEARパッケージアーカイブ形式でもあるようで、

pyrus install Foo.phar

でそのままインストールも可能です。

作成するpharが依存するファイルやPEARパッケージの中身加えるにはどうすればいいの?

作成対象のpharが何かしらの依存ファイルがある場合、extrasetup.phpに個別のファイルやpearパッケージを指定することで、依存ファイルをひっくるめたpharパッケージを作成可能です。

<?php
// レジストリ内にあるパッケージを参照する場合
$config = \Pyrus\Config::singleton(__DIR__ . '/vendor');

$extrafiles = array(
    $config->registry->toPackage('PEAR2_HTTP_Request', 'pear2.php.net'),
);

// 直接チェックアウト先のpackage.xmlを参照する場合
$extrafiles = array(
  new \PEAR2\Pyrus\Package(__DIR__ . '/../../HTTP_Request/trunk/package.xml'),
);

// 個別に特定のファイルを指定する場合
$extrafiles = array(
    'php/PEAR2/HTTP/Request.php' => __DIR__ . '/Request.php',

http://pear.php.net/manual/ja/pyrus.commands.package.php

extrasetup.phpに記述した依存情報はpackage.xmlにはwriteされません。

ただし、今のところの不具合としてgenerate-pear2で対象としてるひな形でのフォルダ"scripts"、"tests"、"data"が存在した場合、makeで不整合のあるpackage.xmlが作成されるようで、インストールに失敗します。んがんぐ。
pyrus/Pyrus_Developer#14
pyrus/Pyrus#26