“インライン” PHPでのクラスのインスタンス化? (メソッド連鎖の容易さのため)
-
06-07-2019 - |
質問
PythonやRubyなどのオブジェクト指向言語で一般的に使用されているイディオムは、オブジェクトをインスタンス化し、次のようなオブジェクト自体への参照を返すメソッドをチェーンします。
s = User.new.login.get_db_data.get_session_data
PHPでは、この動作を次のように複製できます。
$u = new User();
$s = $u->login()->get_db_data()->get_session_data();
次の結果を試みると、構文エラー、予期しないT_OBJECT_OPERATOR
が発生します:
$s = new User()->login()->get_db_data()->get_session_data();
これはおそらく静的メソッドを使用して達成できるようですが、これはおそらく私がやることになりますが、lazywebを確認したかったのです。実際には、PHPクラスをインスタンス化するクリーンでシンプルな方法があります"インライン" (上記のスニペットに示されているように)この目的のためですか?
静的メソッドを使用することに決めた場合、クラスの静的メソッドがクラス自体のインスタンス化を返すのはあまりにも熱狂的ですか? (実際には、コンストラクターではないコンストラクターを作成しますか?)それはちょっと汚い感じがしますが、怖い副作用があまりない場合は、ただやるだけです。
get_user()メソッドを使用してUserFactoryを事前にインスタンス化することもできると思いますが、上記の質問に対する解決策に興味があります。
解決
これらの提案されたソリューションはすべて、PHPを曲げて構文をうまく実現するためにコードを複雑にします。 PHPを(良いような)ものではないものにしたいのは、狂気への道です。
私はただ使用します:
$u = new User();
$s = $u->login()->get_db_data()->get_session_data();
明確で、比較的簡潔で、エラーを引き起こす可能性のあるブラックマジックは含まれていません。
そしてもちろん、いつでもRubyまたはPythonに移行できます。それはあなたの人生を変えます。
- そしてええ、私はPHPに厳しいです。毎日使っています。何年も使用しています。現実には、設計されているのではなく、付加されたということです。
他のヒント
<?php
class User
{
function __construct()
{
}
function Login()
{
return $this;
}
function GetDbData()
{
return $this;
}
function GetSession()
{
return array("hello" => "world");
}
}
function Create($name)
{
return new $name();
}
$s = Create("User")->Login()->GetDbData()->GetSession();
var_dump($s);
?>
これは可能な解決策です:)もちろん、関数にはより良い名前を選択する必要があります...
またはオーバーヘッドを気にしない場合:
<?php
class User
{
function __construct($test)
{
echo $test;
}
...
}
function CreateArgs($name)
{
$ref = new ReflectionClass($name);
return $ref->newInstanceArgs(array_slice(func_get_args(), 1));
}
$s = CreateArgs("User", "hi")->Login()->GetDbData()->GetSession();
var_dump($s);
?>
同様のものを取得できる唯一の方法は、ファクトリまたはシングルトン静的メソッドを使用することです。例:
class User
{
//...
/**
*
* @return User
*/
public static function instance()
{
$args = func_get_args();
$class = new ReflectionClass(__CLASS__);
return $class->newInstanceArgs($args);
}
//...
}
PHP5のリフレクションAPIを使用して(:instance()に送信された引数を使用して)新しいインスタンスを作成し、それを返すことで、チェーンを実行できます:
$s = User::instance()->login()->get_db_data()->get_session_data();
コードが十分に柔軟であるため、その静的メソッドをコピーするときに変更する必要があるのは、PHPDocコメントの@returnだけです。
友人ネルソンのようにコードを時期尚早に最適化する場合は、User :: instance()の内容を次のように置き換えることができます:
return new self();
(構文の問題を回避するために)ハックとオブジェクト作成コード自体を結び付ける理由はありません。
new-expressionはオブジェクト演算子の左メンバーとしては使用できませんが、関数呼び出し式では使用できるため、オブジェクトをラップする必要があるのは、独自の引数を返す関数の呼び出しです:
function hack($obj) { return $obj; }
$mail = hack(new Zend_Mail())
-> setBodyText('This is the text of the mail.')
-> setFrom('somebody@example.com', 'Some Sender')
-> addTo('somebody_else@example.com', 'Some Recipient')
-> setSubject('TestSubject');
への簡単なショートカット
$Obj = new ClassName();
$result = $Obj->memberFunction();
is
$result = (new ClassName())->memberFunction();
<?php
//PHP 5.4+ class member access on instantiation support.
$s = (new User())->login()->get_db_data()->get_session_data();