我想创建一个类的实例,并在一行代码中调用该实例上的方法。
PHP不允许在常规构造函数上调用方法:
new Foo()->set_sth(); // Outputs an error.
所以我正在使用,如果我可以称之为静态构造函数:
Foo::construct()->set_sth();
这是我的问题:
使用像这样的静态构造函数是一种很好的做法,如果是的话,你会如何为这些静态构造函数命名方法?
我一直在犹豫以下选项:
Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
答案 0 :(得分:11)
任何方法的命名都应该是意图揭示名称。我无法告诉Foo :: factory'确实。尝试构建更高级别的语言:
User::with100StartingPoints();
这与:
相同$user = new User();
$user->setPointsTo(100);
您还可以轻松测试User :: with100StartingPoints()是否与此相等。
答案 1 :(得分:9)
静态构造函数(或#34;命名构造函数")仅有助于证明其意图,正如@koen所说。
从5.4开始,有人称之为"解除引用"出现了,它允许您使用方法调用直接内联类实例化。
(new MyClass($arg1))->doSomething(); // works with newer versions of php
因此,只有在有多种方法实例化对象时,静态构造函数才有用。 如果你只有一个(总是相同类型的参数和args数),则不需要静态构造函数。
但是如果你有多种实例化方法,那么静态构造函数非常有用,因为它可以避免使用无用的参数检查来污染你的主构造函数,从而削弱语言约束。
示例:
<?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/
答案 2 :(得分:8)
如果您不需要对新构建的Foo
的引用,为什么不简单地使set_sth
成为static
函数(并让它创建一个新的Foo
内部如果需要)?
如果你做需要掌握参考资料,你会怎么做? return $this
中的set_sth
?但是,无论如何set_sth
都可以成为工厂职能。
我能想到的唯一情况是,如果你想在一个表达式中的新构造的实例上调用可链接的方法(比如在流畅的界面中)。那是你想要做的吗?
无论如何,您可以为所有类型的对象使用通用工厂函数,例如
function create_new($type) {
return new $type;
}
create_new('Foo')->set_sth();
答案 3 :(得分:5)
它可能不是一个最佳实践,但您可以使用函数和类具有两个不同命名空间的事实:您可以拥有一个与类同名的函数。
这允许人们编写这种代码,例如:
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
答案 4 :(得分:4)
添加到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();
答案 5 :(得分:4)
这些名为creation methods,我通常将其命名为createXXX()
,例如createById()
或createEmptyCatalog()
。它们不仅提供了一种很好的方式来揭示对象构造函数的不同意图,而且它们可以在流畅的界面中实现即时方法链接。
echo Html_Img::createStatic('/images/missing-image.jpg')
->setSize(60, 90)
->setTitle('No image for this article')
->setClass('article-thumbnail');
答案 6 :(得分:1)
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()
{
}
}
在任何一种情况下,您都可以在创建方法
之后立即调用myMethod<?php
MyClass::create()->myMethod();
// or
MyClass::create($param1, $param2)->myMethod();
答案 7 :(得分:-2)
派对有点晚,但我认为这可能会有所帮助。
class MyClass
{
function __construct() {
// constructor initializations here
}
public static myMethod($set = null) {
// if myclass is not instantiated
if (is_null($set)) {
// return new instance
$d = new MyClass();
return $d->Up('s');
} else {
// myclass is instantiated
// my method code goes here
}
}
}
然后可以将其用作
$result = MyClass::myMethod();
可选参数可以通过__constructor或myMethod传递 这是我的第一篇文章,我希望我能得到正确的噱头