静态构造函数的最佳实践

Ema*_*sev 22 php coding-style

我想创建一个类的实例,并在一行代码中调用该实例上的方法.

PHP不允许在常规构造函数上调用方法:

new Foo()->set_sth(); // Outputs an error.
Run Code Online (Sandbox Code Playgroud)

所以我正在使用,如果我可以称之为静态构造函数:

Foo::construct()->set_sth();
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

使用像这样的静态构造函数是一种很好的实践,如果是的话,你会如何为这些静态构造函数命名方法?

我一直在犹豫以下选项:

Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
Run Code Online (Sandbox Code Playgroud)

koe*_*oen 11

任何方法的命名都应该有意图揭示名称.我不知道'Foo :: factory'是做什么的.尝试构建更高级别的语言:

User::with100StartingPoints();
Run Code Online (Sandbox Code Playgroud)

这将是:

$user = new User();
$user->setPointsTo(100);
Run Code Online (Sandbox Code Playgroud)

您还可以轻松测试User :: with100StartingPoints()是否与此相等.


Flo*_*ian 9

正如@koen所说,静态构造函数(或"命名构造函数")仅有助于证明其意图.

从5.4开始,出现了一些名为"dereferencing"的东西,它允许你直接用方法调用来内联类实例化.

(new MyClass($arg1))->doSomething(); // works with newer versions of php
Run Code Online (Sandbox Code Playgroud)

因此,只有在有多种方法实例化对象时,静态构造函数才有用.如果只有一个(总是相同类型的参数和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;
}

}
Run Code Online (Sandbox Code Playgroud)

如您所见oneDayStartingToday,静态方法可以访问实例的私有字段!疯了不是吗?:)

有关更好的解释,请参阅http://verraes.net/2014/06/named-constructors-in-php/


Jon*_*Jon 8

如果你不需要对新构造的引用Foo,为什么不简单地创建set_sth一个static函数(Foo如果需要的话,让它在内部创建一个新函数)?

如果你确实需要掌握参考,你会怎么做?return $thisset_sth?但set_sth无论如何都可以制成工厂功能.

我能想到的唯一情况是,如果要在一个表达式中对新构造的实例调用可链接方法(如在流畅的界面中).那是你想要做的吗?

无论如何,您可以为所有类型的对象使用通用工厂函数,例如

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

create_new('Foo')->set_sth();
Run Code Online (Sandbox Code Playgroud)


Pas*_*TIN 6

它可能不是最佳实践,但您可以使用函数和类具有两个不同命名空间的事实:您可以拥有一个与类同名的函数.

这允许人们编写这种代码,例如:

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

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

请注意,我已经定义了一个名为的函数MyClass,以及一个具有相同名称的类.


然后,你可以这样写:

MyClass()->test();
Run Code Online (Sandbox Code Playgroud)

这将完美地工作,并没有给你任何错误 - 在这里,你将得到以下输出:

plop
Run Code Online (Sandbox Code Playgroud)