チラシのうら

つれづれなるままに

10リアクション

PHP 5.4.1の新機能: Scalaライクなミックスイン

2012年4月1日にリリースされたPHP 5.4.1では、マイナーバージョンアップにも関わらず言語仕様が拡張されるという、PHPクォリティ全開の変更があったので紹介しよう。


実体化時ミックスイン (Mix-in instantiation)

クラスをインスタンス化する際にuse文でトレイトを追加できるようになった。トレイトは実行時に解決されるので、クラス宣言より後にトレイトを宣言することも可能。

例1

<?php
class JoJo {}

trait HermitPurple {
    public function sayStand() {
        echo '隠者の紫';
    }
}

trait StarPlatinum {
    public function sayStand() {
        echo '星の白金';
    }
}

$joseph = new JoJo use HermitPurple;
$jotaro = new JoJo use StarPlatinum;

$joseph->sayStand();
echo '/';
$jotaro->sayStand();

出力1

隠者の紫/星の白金

当然オートボクシングもできる。

例2

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello';
    }
}

(new stdClass use Hello)->sayHello();

出力2

Hello

衝突の解決

new-use構文によるミックスインでもinsteadof演算子やas演算子によって衝突の解決や別名の定義が可能。

例3

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

$talker = new stdClass use A, B {
    B::smallTalk insteadof A;
    A::bigTalk insteadof B;
    B::bigTalk as talk;
};
$talker->smallTalk();
echo ',';
$talker->bigTalk();
echo ',';
$talker->talk();

出力3

b,A,B

無名トレイト (Anonymous Traits)

実体化時ミックスインでは、use文のブレース中にメソッドおよびプロパティを記述できる。厳密にはトレイトでないのだが、便宜上この機能を無名トレイト (Anonymous Traits)と呼ぶ。

例4

<?php
(new stdClass use {
    public function sayHello() {
        echo 'Hello';
    }
})->sayHello();

出力4

Hello

名前付きトレイトとの併用

無名トレイトは通常の名前付きトレイトと併用することもできる。

例5

<?php
class JoJo {}

trait GoldExperience {
    public function sayStand() {
        echo 'ゴールド・エクスペリエンス';
    }
}

trait Requiem {
    public function sayStand() {
        echo 'レクイエム';
    }
}

$giorno = new JoJo use GoldExperience, Requiem {
    GoldExperience::sayStand as sayStand1;
    Requiem::sayStand as sayStand2;

    public function sayStand() {
        $this->sayStand1();
        echo '・';
        $this->sayStand2();
    }
};

$giorno->sayStand();

出力5

ゴールド・エクスペリエンス・レクイエム

implements演算子による機能チェック

PHPのトレイトは型システムとしての機能を備えていないので、instanceof演算子でトレイトが追加されているか調べることはできない。しかしミックスインによってインスタンス毎にトレイトを追加できるので、instanceof演算子だけではインスタンスが持つ機能を判定できなくなった。そこで、implements演算子を用いてトレイトの機能をチェックする。

例6

<?php
class Dio {}

trait TheWorld {
    public function sayHello() {
        echo 'WRYYY!';
    }
}

$dio = new Dio use TheWorld;
var_dump($dio implements TheWorld);
$dio->sayHello();

出力6

bool(true)
WRYYY!

注意事項

implements演算子による機能チェックは Class implements Interface によるクラス宣言時と同等のシグネチャ検証をする。そのため、右辺のトレイトが提供する機能を備えていれば、そのトレイトが追加されていなくても真となる。

例7

<?php
class Dio {}

trait TheWorld {
    public function sayHello() {
        echo 'WRYYY!';
    }
}

trait ScaryMonsters {
    public function sayWorld() {
        echo 'WRYYYYYY!';
    }
}

$dio = new Dio use TheWorld { TheWorld::sayHello as sayWorld };
var_dump($dio implements TheWorld);
var_dump($dio implements ScaryMonsters);
$dio->sayWorld();

出力7

bool(false)
bool(true)
WRYYY!

登録カテゴリ: PHP ネタ

リアクション(0)

php-mecab 0.5.0

拙作php-mecabがMeCab 0.99でビルドできなかったり、PHP 5.4でビルドできなかったのを修正した。

MeCab 0.99に対応するため、構造体の変更によって互換性が失われた関数を無効にしている。今後の開発はPHP 5.3.0以降とMeCab 0.99以降のみサポートし、MeCabの新たな機能を網羅したい。

GitHub/rsky/php-mecab

ダウンロード

他のプロジェクトたちも、とりあえずセーフモードチェックを切る対応をしないと・・・


追記

OpenDogs PHP extension channelも更新した。

インストール:

pear channel-discover pecl.opendogs.org
pear install opendogs/mecab

アップグレード:

pear upgrade opendogs/mecab

登録カテゴリ: php pecl

リアクション(0)

MacでAndroid端末のUSBデバッグをする方法

SDKのインストールとか端末側でUSBデバッグを有効にする方法は割愛。

システムプロファイラでデバッグしたい端末の製造元IDを調べて、~/.android/adb_usb.ini に追加する。以上。

ソニー製端末の製造元IDは 0x054c だが、0x54c とxに続く0は削ってもOK。ただしCを大文字にするとアウト。マスト小文字。なんでやねん。

0x054cadb installしたとき

1315 KB/s (3183951 bytes in 2.363s)
        pkg: /data/local/tmp/Hoge-debug.apk
Success

0x054Cadb installしたとき

error: device not found

15リアクション

PHP 5.4におけるZend APIの変更点

16日目@yohgakiさんに続いて、2回目のPHP5.4 Advent Calendar 2011 エントリです。

今回はヘッダファイルの差分を見てPHP 5.3からPHP 5.4のZend APIにどのような変更があったのかを見てみましょう。バイトコードに対する処理が書かれているzend_vm_def.hとzend_vm_execute.hを除いた全差分はGistに貼り付けました

全体的には char * / void * と定義されていた引数が const char * / const void * になっている箇所が多く見られます。この変更はPHP 5.2から5.3にもありましたが、中身を書き換えないポインタはconst修飾するというセオリーがより徹底されており、地味ながら良い変更ですね。


トレイト関連のAPI追加 (zend.h, zend_API.h)

トレイトが導入されたことにより、トレイト関連のAPIが追加されているほか、zend_class構造体もトレイトをサポートするために大きな変更があります。 (詳細はあとで書く)


zvalを操作するマクロの追加 (zend.h)

マクロ ZVAL_COPY_VALUE(zval *z, zval *v)INIT_PZVAL_COPY(zval *z, zval *v) が追加されています。

前者はzvalの「値」を同じにするために、後者はzvalの参照カウントを1にし、他のzvalへの参照であるというフラグを0にします。

このような処理はPHP 5.3までは個別に書かれていたのですが、定型処理をマクロ化したことでZend Engine/PHP本体だけでなく変数を操作する拡張モジュールが書きやすくなるかもしれません。少なくとも「定型処理に名前を付ける」ことで意図が明確になり、読みやすさは格段に向上します。


カレンダーの締め切りの時間が迫ってきたので、いったんここまでで投稿します。朝までに追記しますので請うご期待。

明日はついにここいち兄さん登場です!

登録カテゴリ: PHP

5リアクション

PHP 5.4 の配列Tips

PHP5.4 Advent Calendar 2011 4日目です。3日目@ooharabucyouさんでした。

2日目@yohgakiさんの記事で紹介されたように、PHP 5.4から [] で配列を定義できるようになります。大変めでたいですね。

この記事ではその他の配列まわりの変更を紹介したいと思います。


Array Dereferencingの採用

RFC: Function Array Dereferencing が取り込まれました。

これまでは配列を返す関数の返り値の一部だけが欲しいときでも、その値を一度変数に格納してから $foo[0] や $bar['baz'] としてアクセスする必要がありました。

Array Dereferencingによって、関数呼び出しの後ろに [] 演算子で配列の要素に直接アクセスできるようになります。

サンプル1

function foo($value)
{
    return [0 => 'bar', 'baz' => $value];
}

$obj = new stdClass;
$obj->qux = 'quux';
var_dump(foo($obj)[0]);
var_dump(foo($obj)['baz']->qux);
var_dump(explode(' ', 'The quick brown fox jumps over the lazy dog')[3]);

出力

string(3) "bar"
string(4) "quux"
string(3) "fox"

array_combine()が空の配列を受け付けるようになった

Changed array_combine() to return empty array instead of FALSE when both parameter arrays are empty. FR #34857

リンク先にあるコメントのように、何らかの解析結果から連想配列を作成したいといったケースで、リストが空かどうかのチェックをする必要がなくなります。


(クラス,メソッド)または(オブジェクト,メソッド)のペアからなる配列変数の後ろに()を付けて呼び出せるようになった

Added indirect method call through array. FR #47160

is_callable()に与えてtrueを返す変数は全て後ろに()を付けて呼び出せるようになったとも言えます。

これによって、コールバック関数を受ける関数をスマートに書けたりします。

サンプル2 冗長な記述

function hoge($callback, $arg1, $arg2)
{
    if (is_array($callback)) {
        list($object_or_classname, $method) = $callback;
        if (is_object($object_or_classname)) {
            return $object_or_classname->$method($arg1, $arg2);
        } else {
            return $object_or_classname::$method($arg1, $arg2);
        }
    }
    return $callback($arg1, $arg2);
}

サンプル3 call_user_func()

function hoge($callback, $arg1, $arg2)
{
    return call_user_func($callback, $arg1, $arg2);
}

サンプル4 コードが明瞭に

function hoge($callback, $arg1, $arg2)
{
    return $callback($arg1, $arg2);
}

配列をソートする関数のオプションに SORT_NATURAL と SORT_FLAG_CASE が加わった

Added support for SORT_NATURAL and SORT_FLAG_CASE in array sort functions (sort, rsort, ksort, krsort, asort, arsort and array_multisort). FR#55158

array_multisort()でもnatsort()natcasesort()相当の比較をしたいということで実装されました。

まずは特にフラグをつけずにarray_multisortにかけてみましょう。

サンプル5

$jojo = ['Jonathan', 'Joseph', 'Jotaro', 'Josuke', 'Jorno', 'Jolyne', 'Joshu'];
$php = ['PHP 5.3.7', 'PHP 5.2.7', 'PHP 5.2.17', 'PHP 5.3.9alpha1', 'PHP 5.4.0RC2', 'PHP 5.3.9RC2', 'PHP 5.4.0beta1'];

array_multisort($php, $jojo);
print_r(array_combine($jojo, $php));

出力

Array
(
    [Jotaro] => PHP 5.2.17
    [Joseph] => PHP 5.2.7
    [Jonathan] => PHP 5.3.7
    [Jolyne] => PHP 5.3.9RC2
    [Josuke] => PHP 5.3.9alpha1
    [Jorno] => PHP 5.4.0RC2
    [Joshu] => PHP 5.4.0beta1
)

普通に$phpを文字列として比較した結果が返ってきていますね。

次にSORT_NATURALをセットしてみましょう。

サンプル6

array_multisort($php, SORT_NATURAL, $jojo);
print_r(array_combine($jojo, $php));

出力

Array
(
    [Joseph] => PHP 5.2.7
    [Jotaro] => PHP 5.2.17
    [Jonathan] => PHP 5.3.7
    [Jolyne] => PHP 5.3.9RC2
    [Josuke] => PHP 5.3.9alpha1
    [Jorno] => PHP 5.4.0RC2
    [Joshu] => PHP 5.4.0beta1
)

数字が人にとって自然な順にソートされました。

さらにSORT_FLAG_CASEも加えてみましょう。

サンプル7

array_multisort($php, SORT_NATURAL | SORT_FLAG_CASE, $jojo);
print_r(array_combine($jojo, $php));

出力

Array
(
    [Joseph] => PHP 5.2.7
    [Jotaro] => PHP 5.2.17
    [Jonathan] => PHP 5.3.7
    [Josuke] => PHP 5.3.9alpha1
    [Jolyne] => PHP 5.3.9RC2
    [Joshu] => PHP 5.4.0beta1
    [Jorno] => PHP 5.4.0RC2
)

大文字/小文字を無視してソートされていますね。 この例だとuasort($ary, 'version_compare')でもいいじゃないかというツッコミは却下します。


まとめ

ここで紹介した新機能はPHPプログラムをシンプルに記述する上でちょっと役に立つと思います。

必ずしも短く書けるといいということではありませんが、プログラムの意図をより明確にできるのは良いことですね。

明日は@chobi_eさんです。

まだ枠はありますので、参加者も絶賛募集中です!

登録カテゴリ: PHP

1リアクション

Lion / CS4 問題私的まとめ

自分に関係ありそうな箇所をAdobe公式の Mac OS X 10.7 Lion で確認されている問題 より一部引用。

B-6. Fireworks

Fireworks CS4 : カンバスで選択したカラーが、カラーピッカーに反映されません。

FireworksだけはCS5をピンでライセンス持ってるのでOK。

B-11. Illustrator

Illustrator CS3, CS4 : 印刷すると強制終了する場合があります。過去にそのシステムにはAcrobat 8.xがインストールされていました。

TechNoteの Mac OS X 10.7 Lionで印刷すると強制終了する にあるとおりに /Library/Printers/PPDs/contents/Resources/*.lproj を始末すればよい。

というかAcrobat 8.xをインストールしたことがないので問題なし。

B-14. Photoshop

Photoshop CS4 では、レイヤーパネル内でレイヤーをドラッグすると強制終了します。

Photoshop CS4 のレイヤーパネルでレイヤーをドラッグして移動すると強制終了する に解決方法が書かれている。

MacBook ProでGPUの自動切り替えを有効にしているとアウトらしい。Mac miniやMacBook Airでは問題ないのだろうか?

結論

自分が使う範囲ではなんとかなりそうなので、Photoshop / Illustrator CS4だけインストールしてみよう。

番外編

B-10. Flash Professional

Flash CS4 Professional は Mac OS X 10.7 で動作しません。Mac OS X 10.7 用 アップデーターの提供予定はありません。Mac OS X 10.7 環境では使用しないことを推奨します。

ノーコメント。

2リアクション

KQ on PHP

祭りレポートを書く前に@nvsoftsさんプログラミング言語KQのPHP版を作ったので紹介してみようと思う。(→GitHub

KQ自体がBrainf*ckの方言なので、オリジナルの移植ではなくて以前に作ったBF処理系の焼き直し。ただしトークンをすげ替えただけでなくて、中身もちょっと整理している。

<?php
namespace KQ;

class Driver
{
    const DOOR_WILL_CLOSE = 'ダァシエリイェス';
    //snip.

とか、

$kq = new KQ\Driver();
echo $kq->doorWillClose(/*snip.*/);

とか、しょうもないネタを仕込んではいるけど、中身は方言をオリジナルBrainf*ckに変換、さらに実行コードに変換、簡易VMで実行と、BF処理系としての完成度はそれなりに高いと自負している。

ひとつ反省点を挙げるとすれば、方言とBFの変換部とBFコアは別クラスにすべきだった。あとは気が向いたら連続する+-をまとめる最適化を施してみたいが、たぶんずっとしない。

登録カテゴリ: PHP

1リアクション

MTKit: TinyMT for Objectve-C

Tiny Mersenne Twister (TinyMT)のObjective-Cラッパーを作った。→GitHub

TinyMTのAPIはすごくシンプルで特にラップしなくても容易に使えるのだが、Mac OS X / iOS向けにC標準の型でなくNSUIntegerやCGFloatを返すように作った。

特にiOSではコンパクトで質の良い疑似乱数生成器として有用だと考えている。

TinyMT.hをインポートして下記のように使う。

NSUInteger seed = 4649;
TinyMT *random = [[TinyMT alloc] initWithSeed:seed]
NSUInteger u = [random generate]; // [0..NSUIntegerMax]
CGFloat f = [random generateFloat]; // [0.0...1.0)
[random release];

名前だけ見るとフレームワークとして使えそうなのだけど、僕がXcodeでのライブラリ作りを習得していないせいもあって、今のところTinyMT.h, TinyMT.m, tinymt32.h, tinymt32.c, tinymt64.h, tinymt64.c をプロジェクトにコピーして使ってほしい。(iOSで使う場合は tinymt64.* は不要)

注意してほしいことがひとつ。ILP32環境では32bit版TinyMTを、LP64環境では64bit版TinyMTを使っており、32bit/64bitで同じ値をseedにしても生成される結果が異なる。32bit/64bit双方で同じ乱数系列を使いたい場合はTinyMTのC APIを直接使うべし。

TinyMT本体のライセンスはNew BSD Lisenceで、MTKitはMIT License。

登録カテゴリ: Objective-C