web-dev-qa-db-ja.com

静的コンストラクターのベストプラクティス

クラスのインスタンスを作成し、そのインスタンスのメソッドを1行のコードで呼び出します。

PHPでは、通常のコンストラクターでメソッドを呼び出すことはできません。

new Foo()->set_sth(); // Outputs an error.

だから私はそれを呼び出すことができるなら、静的コンストラクタを使用しています:

Foo::construct()->set_sth();

これが私の質問です:

そのような静的コンストラクタを使用することは良い習慣と考えられていますか?そうであれば、これらの静的コンストラクタのメソッドに名前を付けることをどのようにすすめますか?

私は次のオプションをためらっています。

Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
23
Emanuil Rusev

メソッドの命名には、意図を明らかにする名前を使用する必要があります。 「Foo :: factory」が何をするのか分かりません。より高いレベルの言語にビルドしてみてください:

User::with100StartingPoints();

これは次と同じです。

$user = new User();
$user->setPointsTo(100);

また、User :: with100StartingPoints()がこれと等しいかどうかも簡単にテストできます。

11
koen

静的コンストラクター(または「名前付きコンストラクター」)は、@ koenが言うように、意図を証明するためにのみ有益です。

しかし5.4以降、「逆参照」と呼ばれる方法が登場し、メソッドの呼び出しで直接クラスのインスタンス化をインライン化できるようになりました。

(new MyClass($arg1))->doSomething(); // works with newer versions of php

したがって、静的コンストラクターは、オブジェクトをインスタンス化する方法が複数ある場合にのみ役立ちます。 1つしかない場合(常に同じタイプの引数と数の引数)、静的コンストラクターは必要ありません。

しかし、インスタンス化の方法が複数ある場合、静的コンストラクターは非常に便利です。静的コンストラクターは、無効な引数チェックでメインコンストラクターを汚染することを回避し、言語の制約を弱めます。

例:

<?php

class Duration
{
private $start;
private $end;

// or public depending if you still want to allow direct instantiation
private function __construct($startTimeStamp = null, $endTimestamp = null)
{
   $this->start = $startTimestamp;
   $this->end   = $endTimestamp;
}

public static function fromDateTime(\DateTime $start, \DateTime $end)
{
    return new self($start->format('U'), $end->format('U'));
}

public static function oneDayStartingToday()
{
    $day = new self;
    $day->start = time();
    $day->end = (new \DateTimeImmutable)->modify('+1 day')->format('U');

    return $day;
}

}

oneDayStartingTodayを見るとわかるように、静的メソッドはインスタンスのプライベートフィールドにアクセスできます。クレイジーじゃないですか? :)

より良い説明については、 http://verraes.net/2014/06/named-constructors-in-php/ を参照してください

11
Florian Klein

新しく構築されたFooへの参照が必要ない場合は、単にset_sthstatic関数(必要に応じて内部で新しいFooを作成します)?

do参照を取得する必要がある場合、どのように実行しますか? return $thisset_sth?しかしその後 set_sthとにかくファクトリ関数にすることができます。

私が考えることができる唯一の状況は、新しく構成されたインスタンスのチェーン可能なメソッド(Fluentインターフェイスなど)をすべて1つの式で呼び出す場合です。それはあなたがやろうとしていることですか?

とにかく、すべてのタイプのオブジェクトに汎用ファクトリ関数を使用できます。

function create_new($type) {
    return new $type;
}

create_new('Foo')->set_sth();
8
Jon

これはおそらくベストプラクティスとは言えませんが、関数とクラスに2つの異なる名前空間があるという事実を利用できます。クラスと同じ名前の関数を持つことができます。

これにより、次のようなコードを記述できます。

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

class MyClass {
    public function __construct() {
        $this->a = "plop";
    }
    public function test() {
        echo $this->a;
    }
    protected $a;
}

MyClassという関数と、同じ名前のクラスを定義したことに注意してください。


次に、これを書くことができます:

MyClass()->test();

これは完全に機能し、エラーは発生しません-ここでは、次の出力が得られます。

plop
6
Pascal MARTIN

これらは 作成メソッド と呼ばれ、createXXX()createById()などのように、通常createEmptyCatalog()と名付けます。これらは、オブジェクトのコンストラクターのさまざまな意図を明らかにするための優れた方法を提供するだけでなく、Fluentインターフェイスですぐにメソッドチェーンを実行できるようにします。

echo Html_Img::createStatic('/images/missing-image.jpg')
        ->setSize(60, 90)
        ->setTitle('No image for this article')
        ->setClass('article-thumbnail');
4
David Harkness

Jon's answer への追加:コンストラクター引数を許可するには、以下を使用します。

function create($type) {
    $args = func_get_args();
    $reflect = new ReflectionClass(array_shift($args));
    return $reflect->newInstanceArgs($args);
}
create('Foo', 'some', 'args')->bar();

ドキュメント: ReflectionClass->newInstanceArgs

4
NikiC

Propelは静的メソッド「作成」を使用します。私はそれで行きます。このメソッドを使用すると、静的メソッドを使用してビジネスロジックを実行するだけでなく、コードを簡単にテストできます。

<?php 
class MyClass
{
  public static function create()
  {
    return new MyClass();
  }
  public function myMethod()
  {
  }
}

さらに、コンストラクターにパラメーターを渡すこともできます。例えば:

<?php 
class MyClass
{
  public function __construct($param1, $param2)
  {
   //initialization using params
  }

  public static function create($param1, $param2)
  {
    return new MyClass($param1, $param2); // return new self($param1, $param2); alternative ;)
  }

  public function myMethod()
  {
  }
}

どちらの場合でも、createメソッドの直後にmyMethodを呼び出すことができます。

<?php
MyClass::create()->myMethod();
// or
MyClass::create($param1, $param2)->myMethod();
1
Hezuo