また PHP 5.3 のお話です。ReflectionFunction::getClosure() 及び ReflectionMethod::getClosure() が追加されてますね。なんだろうこれ?

<?php

$rf = new ReflectionFunction('time');
$time = $rf->getClosure();
$rm = new ReflectionMethod('ArrayObject', 'count');
$count = $rm->getClosure(new ArrayObject(array(1, 2, 3)));

echo 'time(): ', $time(), PHP_EOL;
echo 'ArrayObject::count(): ', $count(), PHP_EOL;
time(): 1219387333
ArrayObject::count(): 3
hikomedal.jpg

「ひこにゃんなんかどうでもいい。俺はしまさこにゃんが欲しいんだ!」。中国農業大学体育館で14日に決勝まで行われた北京五輪のレスリング男子グレコローマン84キロ級の表彰式で、3位に入ったアラ・アブラハミアン(スウェーデン)が三位入賞者に与えられるゆるキャラを不服として、首にかけられたひこにゃんをはずし、マットの上に投げ捨てて立ち去る一幕があった。

アブラハミアンは「かぶとを頂っけただけのニャンまげなんて誰が欲しがる。それにこいつには尻尾まであり、まったくでたらめだったからだ」と激高し、なだめる同僚らも振り切って表彰式で怒りを爆発させた。

ロイター通信によると、アブラハミアンは前回2004年のアテネ五輪で同じ種目でいしだみつにゃんを獲得しており、今回はしまさこにゃん獲得に大きな期待がかかっていた。

遅延静的束縛と関連のあるお話です。クラスメソッドを呼び出す際に parent, self, static キーワードを使わず、クラス名を指定してやると呼び出し元がそのクラスになります。

<?php

class A
{
    public static function method()
    {
        echo __METHOD__, ' called by ', get_called_class(), PHP_EOL;
    }
}

class B extends A
{
    public static function method()
    {
        echo __METHOD__, ' called by ', get_called_class(), PHP_EOL;
        return A::method(); // 遅延静的束縛のための情報は引き継がれない
    }
}

class C extends B
{
    public static function method()
    {
        echo __METHOD__, ' called by ', get_called_class(), PHP_EOL;
        return parent::method();
    }
}

C::method();
C::method called by C
B::method called by C
A::method called by A

forward_static_call() 及び forward_static_call_array() は遅延静的束縛の情報を残したままメソッドを呼び出すために(も?)用意されました。

<?php

class A
{
    public static function method()
    {
        echo __METHOD__, ' called by ', get_called_class(), PHP_EOL;
    }
}

class B extends A
{
    public static function method()
    {
        echo __METHOD__, ' called by ', get_called_class(), PHP_EOL;
        return  forward_static_call(array('A', 'method')); // 遅延静的束縛のための情報を引き継ぐ
    }
}

class C extends B
{
    public static function method()
    {
        echo __METHOD__, ' called by ', get_called_class(), PHP_EOL;
        return parent::method();
    }
}

C::method();
C::method called by C
B::method called by C
A::method called by C

継承関係にないクラスを指定しても引き継がれません。また親から子を指定しても引き継がれません。その他の制限として、クラススコープ以外で呼び出すと E_ERROR が発生します。後は call_user_func() 及び call_user_func_array() と使い方は同じのようです。

どんな場面で使うのかは、…どうなんだろう?

__CLASS__ 定数の遅延静的束縛版といったところでしょうか。

<?php

class A
{
    public static function whose()
    {
        return get_called_class();
    }
}

class B extends A
{
    public static function whose()
    {
        return parent::whose();
    }
}

class C extends A
{
    public static function whose()
    {
        return A::whose();
    }
}

echo 'A: ', A::whose(), PHP_EOL;
echo 'B: ', B::whose(), PHP_EOL;
echo 'C: ', C::whose(), PHP_EOL;
A: A
B: B
C: A

ActiveRecord のようにクラスメソッドがバカスカ生えるクラスに使えるかもですね。でもここでは継承される事を想定したシングルトンの例を上げます。そんなのありか!

<?php

class Hoge
{
    private static $instances = array();
    
    protected function __construct()
    {
        if (array_key_exists(get_called_class(), self::$instances))
        {
            throw new RuntimeException('もう作っちゃらめ!');
        }
    }
    
    final public static function getInstance()
    {
        $callee = get_called_class();
        if (!array_key_exists($callee, self::$instances))
        {
            self::$instances[$callee] = new static();
        }
        
        return self::$instances[$callee];
    }
    
    public function __clone()
    {
        throw new RuntimeException('クローン作っちゃらめ!');
    }
    
    public function __toString()
    {
        return get_class($this) . '(' . spl_object_hash($this) . ')';
    }
}

class Fuga extends Hoge
{
}

class Piyo extends Fuga
{
}

echo Hoge::getInstance(), PHP_EOL;
echo Fuga::getInstance(), PHP_EOL;
echo Piyo::getInstance(), PHP_EOL;
echo Hoge::getInstance(), PHP_EOL;
echo Fuga::getInstance(), PHP_EOL;
echo Piyo::getInstance(), PHP_EOL;
Hoge(ea3b5927dbfffe7c0456ff51c413a384)
Fuga(0e67c95a7d082c779dc82db7e8554d9c)
Piyo(3b3af9abb7c1ee816230684be1ec11dc)
Hoge(ea3b5927dbfffe7c0456ff51c413a384)
Fuga(0e67c95a7d082c779dc82db7e8554d9c)
Piyo(3b3af9abb7c1ee816230684be1ec11dc)

5.3 から HTTP ストリームのコンテキストに ignore_errors オプションが利用できるようになるそうです。

01 Aug 2008, PHP 5.3.0 Alpha 1
- Improved streams:
  . Added "ignore_errors" option to http fopen wrapper. (David Zulke, Sara)

今までは fopen() や file_get_contents() の URL に HTTP ストリームを指定した場合、HTTP レスポンスのステータスコードが(最終的に) 2xx でなければレスポンスボディを取得できませんでした。ところが HTTP の仕様としてレスポンスボディを設定できるステータスコードは 2xx だけではありません。PHP 5.3 からはコンテキストに ignore_errors = true を設定すると、エラーとなっていたステータスコードを無視するようになります。次のコードは HTTP サーバが 404 として用意しているレスポンスボディを取得します。

$context = stream_context_create(array('http' => array('ignore_errors' => true)));
echo file_get_contents('http://www.example.com/not-exists-url', false, $context);

また、REST スタイルな Web API にアクセスして取得に失敗した時に、それが認証が必要だったせいなのか、サービスが存在していなかったのか、リクエストの内容が間違っていたのか、さまざまな状態を判別するのに使えるステータスコードを拾えるようになります。

例として、ハイパーテキスト・コーヒーポット制御プロトコルを実装した HTCPCP サーバに HTTP ストリームを使ってアクセスするコードを上げます。

<php
// なにもしない、なにも足さない、HTCPCP サーバ

switch (strtoupper($_SERVER['REQUEST_METHOD']))
{
    case 'POST':
    case 'BREW':
    case 'WHEN':
        header('HTTP/1.1 418 I\'m a teapot', true, 418);
        header('Content-Type: text/plain', true);
        echo '私は急須だ。';
        break;
    
    default:
        header('HTTP/1.1 501 Not Implemented', true, 501);
        echo '要求されたメソッドは未実装です。';
        break;
}
<php
// HTCPCP サーバに対して BREW メソッドを発行するクライアントプログラム

$coffeepot = 'http://www.example.com/coffeepot.php';
$options = array(
    'http' => array(
        'method' => 'BREW',
        'header' => array('Content-Type: message/coffeepot'),
        'content' => 'start',
        'ignore_errors' => true,
    ),
);
$stream = @fopen($coffeepot, 'rb', false, stream_context_create($options));
$meta = stream_get_meta_data($stream);
preg_match('|\\AHTTP/\\d\\.\\d +(?<status_code>\\d{3}) +(?<reason_phrase>.*)\\E|', $meta['wrapper_data'][0], $captures);
echo $captures['status_code'], '/', $captures['reason_phrase'], PHP_EOL;
fpassthru($stream);
fclose($stream);

結果

418/I'm a teapot
私は急須だ。

怒られちゃいましたね。こんな具合に、Web API をちょっと叩いてみたい時に PEAR::HTTP_Client や Zend_Http_Client 等の外部ライブラリに頼らずともできるようになるのはありがたいです。

ゼニさん、見てたらよろしくー。

先生に言われたら断れませんね!

desktop.jpg

Q1.あなたのデスクトップを見られて、一言どうぞ。
へんなのが映っててもしー。お願いしますね

Q2.これはあなた個人のパソコン?
個人です。

Q3.この壁紙は何?どこで手に入れた?
かっこいい壁紙の紹介スレで。

Q4.壁紙は頻繁に変える?
他の壁紙にしてもまたこの壁紙に戻すを繰り返してます。

Q5.デスクトップのアイコンの数はいくつ?
ごみ箱の一つ。クイック起動にある20個は常用です。ファイルへは NCW でアクセスします。

Q6.ファイルやショートカットがゴチャゴチャしているデスクトップ、許せる?
筆箱の鉛筆を背の順に並べると早死にするという無茶苦茶な噂が流行したことがあります。関係ないですね。個性が出て面白いと思います。

dev.jpg

Q7.何かこだわりはある?
削除されて困るものは置かない。

Q8.今回、このバトンが回ってきてから、こっそりとデスクトップを整理した?

仕事一筋をアピールするためにクイックから HOI2 へのショトカを削除しました。夜が無くなるたぁこいつの事だ

Q9.最後に『この人のデスクトップを覗きたい』という5人へバトン!

気になる人ほど伝えられない><

usagi.jpg

丑の日に食べるものは『う』が付けばなんでもいいそうで、うまい棒でも宇宙食でもいいのだ。だが北の将軍様、お前は別だ!

closure の記事を書いた後に気付いたんですが、クラスに __invoke() メソッドが定義されてると関数のように呼び出せるんですね。こいつぁ使える!

<?php

class A
{
    public function __invoke()
    {
        echo 'ひえひえ細胞';
    }
}

$a = new A();
$a();

http://d.hatena.ne.jp/masugata/20080709#p1 いやっほおおお!日をまたいでいてすぐ眠りたいのですが、が… php-6.0-dev がベンチに座ってチャックを下ろす姿を見てホイホイ落としちゃったのだ。

<?php

$hikonyann = function ($multiplier)
{
    return str_repeat(’ひこにゃん’, $multiplier);
};

echo $hikonyann();
ひこにゃんひこにゃんひこにゃん

うんうんいいよー。レキシカル変数を参照するには?use () で宣言するのか。

$name = 'ひこにゃん';
$hikonyann = function ($multiplier) use ($name)
{
    return str_repeat($name, $multiplier);
};

echo $hikonyann(3) . PHP_EOL;
ひこにゃんひこにゃんひこにゃん

うんうんいいよー。このレキシカル変数は値渡し?参照渡し?

<?php

$name = 'ひこにゃん';
$hikonyann = function ($multiplier) use ($name)
{
    return str_repeat($name, $multiplier);
};

echo $hikonyann(3) . PHP_EOL;
$name = 'しまさこにゃん';
echo $hikonyann(3) . PHP_EOL;
ひこにゃんひこにゃんひこにゃん
ひこにゃんひこにゃんひこにゃん

値渡しですね。& で参照渡しになる、と。

$name = 'ひこにゃん';
$hikonyann = function ($multiplier) use (&$name)
{
    return str_repeat($name, $multiplier);
};

echo $hikonyann(3) . PHP_EOL;
$name = 'しまさこにゃん';
echo $hikonyann(3) . PHP_EOL;
ひこにゃんひこにゃんひこにゃん
しまさこにゃんしまさこにゃんしまさこにゃん

クラスと組み合わせると?

<?php

class Mascot
{
    private $name;
    
    public function __construct($name)
    {
        $this->name = $name;
    }
    
    public function generate()
    {
        return function ($multiplier)
        {
            return str_repeat($this->name, $multiplier);
        };
    }
}

$hikonyann = new Mascot('ひこにゃん');
$generator = $hikonyann->generate();
echo $generator(3) . PHP_EOL;
ひこにゃんひこにゃんひこにゃん

$this は明示的に指定しなくていいんだね。他は、どんな呼び出し方があるのかな?

<?php

$lamda = function () { debug_print_backtrace(); };

$lamda();
$lamda->__invoke();
call_user_func($lamda);
#0  lambda() called at [*:\********\closure.php:5]
#0  lambda()
#1  Closure->__invoke() called at [*:\********\closure.php:6]
#0  lambda()
#1  call_user_func(Closure Object ()) called at [*:\********\closure.php:7]

あら?オブジェクト?

<?php echo get_class(function () {});
Closure

まぁ、Closure クラスですって!ReflectionObject の出番よ。

<?php Reflection::export(new ReflectionObject(function () {}));
Object of class [ <internal> final class Closure ] {

  - Constants [0] {
  }

  - Static properties [0] {
  }

  - Static methods [0] {
  }

  - Properties [0] {
  }

  - Dynamic properties [0] {
  }

  - Methods [0] {
  }
}

まっさら。__invoke() はマジックメソッド扱いなのかしら?

時間が出来たら詳しく調べます…。

from-search-bar.png

ブラウザの検索バーから MoE Wiki 内を検索するためのファイルを用意しました。OpenSearch 対応のブラウザでご利用下さい。

お使いのブラウザによっては、BASIC 認証の確認ダイアログが出る可能性があります。BASIC 認証は MoE Wiki の仕様です。

set-keyword.png

Firefox 3 でご利用の場合は、検索エンジンのキーワード設定をお勧めします。これによりロケーションバーからダイレクトに検索できるようになります。

from-location-bar.png

最近の画像

  • hikomedal.jpg
  • dev.jpg
  • desktop.jpg
  • usagi.jpg
  • set-keyword.png
  • from-search-bar.png
  • from-location-bar.png
  • figure2.jpg
  • figure1-2.jpg
  • figure1-1.jpg