PHP5.4でコンストラクタを呼ばずにインスタンスが作れる

こんにちは。PHP5.4 ADVENTカレンダー13日目PHP5.4の新機能の一つ: アップロード進捗の取得に続いて14日目の担当のPaulです。

PHPはReflectionを使うことにより、privateとかprotectedとかのルールを無視して色々出来ます。
下はReflectionを使ってprivateメソッドを呼び出す例です。

class LockedDoor
{
    private function open()
    {
        return 'privateだけどドア開いちゃったよ!!';
    }
}

$refClass = new ReflectionClass('LockedDoor');
$refMethod = $refClass->getMethod('open');
$refMethod->setAccessible(true); //無理やりprivate解除
 //privateだけどobjectの外から実行できる
echo $refMethod->invoke($refClass->newInstance());

PHP5.4(Beta1)でReflectionClassにnewInstanceWithoutConstructorというメソッドが加わりました。
そうです!名前通りコンストラクタ使わずにインスタンスが作れるのです。

PHP5から__constructでコンストラクタが書ける様になりました。あれはあれでクラス名に依存しないので便利なんですけど、それのお陰でコピペのコンストラクタが増えたと思うのは僕だけでしょうか?
そういう問題には本来「親クラスを作って必要な処理はそこにまとめて、、、」やるべきなのでしょうが、「それが面倒だけど、コンストラクタの余分な処理をなんとかしたい!」って時に使えます。

例えば下の様なクラス

class MyClass
{
    private $lang;

    public function __construct() 
    {
        $this->lang = $_SERVER[HTTP_ACCEPT_LANGUAGE];
    }

    public function getLang() 
    {
        return $this->lang;
    }

    //意味ねーよ!
    public function setLang($lang) 
    {
        if ($this->lang == null) {
            $this->lang = $lang;
        }
    }
}

気持ちは分かるけどsetLangの意味がねーよ!と。

それもReflectionClass::newInstanceWithoutConstructorでなんとか出来ます。

$_SERVER[HTTP_ACCEPT_LANGUAGE] = 'ja';
$obj = new MyClass();
$obj->setLang('en');
echo $obj->getLang(), PHP_EOL; //jaのまま

$obj = (new ReflectionClass('MyClass'))->newInstanceWithoutConstructor();
$obj->setLang('en');
echo $obj->getLang(), PHP_EOL; //enと表示

個人的にはPHPは[スクリプト=コードが書き換えられる]ので、あまりReflectionに頼るのは如何なものかと思いますが、(Javaみたいにバイナリしかない場合はReflectionも必要だけど)
応急処置として頼りになるので、覚えておいて損はないと思います。

明日15日目は@srea2431さんです!お楽しみに!
あと、PHP5.4 ADVENTカレンダーまだまだ参加者募集中です!

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中