web-dev-qa-db-ja.com

新しく作成されたオブジェクトのメソッドをチェーンする方法は?

PHPで新しく作成されたオブジェクトのメソッドをチェーンする方法があるかどうかを知りたいですか?

何かのようなもの:

class Foo {
    public function xyz() { ... return $this; }
}

$my_foo = new Foo()->xyz();

これを達成する方法を知っている人はいますか?

55
aefxx

PHP 5.4+では、パーサーが変更されているため、次のようなことができます

(new Foo())->xyz();

インスタンス化を括弧で囲み、チェーンします。

PHP 5.4より前は、

new Classname();

構文では、インスタンス化からメソッド呼び出しをチェーンすることはできません。これはPHP 5.3の構文の制限です。オブジェクトがインスタンス化されると、連鎖することができます。

これを回避するために私が見た1つの方法は、ある種の静的インスタンス化メソッドです。

class Foo
{
    public function xyz()
    {
        echo "Called","\n";
        return $this;
    }

    static public function instantiate()
    {
        return new self();
    }
}


$a = Foo::instantiate()->xyz();

Newへの呼び出しを静的メソッドでラップすることにより、メソッド呼び出しを使用してクラスをインスタンス化でき、自由にチェーンを解除できます。

99
Alan Storm

次のようなグローバル関数を定義します。

function with($object){ return $object; }

その後、次の番号を呼び出すことができます。

with(new Foo)->xyz();
23
Kenaniah

PHP 5.4では、新しくインスタンス化されたオブジェクトをチェーンオフできます:

http://docs.php.net/manual/en/migration54.new-features.php

古いバージョンのPHPでは、Alan Stormのソリューションを使用できます。

11
Jackson

この回答は古くなっているため、修正したい。

PHP 5.4.xでは、メソッドをnew-callにチェーンできます。このクラスを例に取ってみましょう:

_<?php class a {
    public function __construct() { echo "Constructed\n"; }
    public function foo() { echo "Foobar'd!\n"; }
}
_

これで、これを使用できます:$b = (new a())->foo();

そして出力は:

_Constructed
Foobar'd!
_

詳細はマニュアルにあります: http://www.php.net/manual/en/migration54.new-features.php

6
Ingwie Phoenix

まあ、これは古い質問かもしれませんが、プログラミングの多くのものと同じように-最終的に答えが変わります。

PHP 5.3に関しては、いいえ、コンストラクタから直接チェーンすることはできません。ただし、受け入れられた答えを拡張するために、継承に適切に対応するために、以下を行うことができます。

abstract class Foo 
{    
    public static function create() 
    {
        return new static;
    }
}

class Bar extends Foo
{
    public function chain1()
    {
        return $this;
    }

    public function chain2()
    {
        return $this;
    }
}

$bar = Bar::create()->chain1()->chain2();

これは問題なく動作し、新しいBar()インスタンスを返します。

PHP 5.4では、次のようにすることができます:

$bar = (new Bar)->chain1()->chain2();

うまくいけば、これは私が持っているような誰かが質問に出くわすのを助けるでしょう!

3
Lukey

彼らが将来のリリースで「これを修正する」ならば、それは本当に役に立ちます。チェインする機能に特に感謝します(特にコレクションを作成する場合)。

フレームワークの基本クラスにcreate()と呼ばれるメソッドを追加しました。すべての子孫クラスで自動的に動作するはずです。

class baseClass
{
    ...
    public final static function create()
    {
        $class = new \ReflectionClass(get_called_class());
        return $class->newInstance(func_get_args());
    }
    ...
    public function __call($method, $args)
    {
        $matches = array();
        if (preg_match('/^(?:Add|Set)(?<prop>.+)/', $method, $matches) > 0)
        {
            //  Magic chaining method
            if (property_exists($this, $matches['prop']) && count($args) > 0)
            {
                $this->$matches['prop'] = $args[0];
                return $this;
            }
        }
    }
    ...
}

クラス:: create()-> SetName( 'Kris')-> SetAge(36);

1
Kris

完全を期すために(そしてそれを楽しむために...)、誰も誰も最短の(そして最も洗練されていない)コードを使用したソリューションに言及していないようです。

頻繁に使用される寿命の短いオブジェクトの場合、特に多くのオブジェクト作成を通常行うテストケースを作成する場合は、入力の利便性を(純粋度ではなく)最適化し、Alan StormのFoo::instantiate()を組み合わせるとよいでしょう。ファクトリメソッドとケニアニアのwith()グローバル関数テクニック。

ファクトリメソッドをクラスと同じ名前のグローバル関数にするだけです。 ; -o(適切なstatic Foo::instantiate()の便利なラッパーとして追加するか、誰も見ないでそこに移動します。)

class Foo
{
    public function xyz()
    {
        echo "Called","\n";
        return $this;
    }
}

function Foo()
{
    return new Foo();
}

$a = Foo()->xyz();

注意:

  • 量産コードではこれを実行しません。ちょっとセクシーですが、これは基本的なコーディング原則の乱用です(「驚きの原則」(これは実際にはかなり直感的な構文です)など)、または実際のファクトリメソッドをいくつかでラップする場合は「自分自身を繰り返さないでください」パラメータ自体、BTWはすでにDRYの乱用です...)、さらにPHPは将来、このようなコードをおかしな方法で壊すように変更される可能性があります。
0
Sz.