Рекомендации для статических конструкторов

Я хочу создать экземпляр класса и вызвать метод в этом экземпляре в одной строке кода.

PHP не позволит вызывать метод на регулярном конструкторе:

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

Поэтому я использую, если можно так выразиться, статический конструктор:

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

Вот мой вопрос:

Является ли использование статических конструкторов такими, которые считаются хорошей практикой, и если да, как бы вы рекомендовали называть методы для этих статических конструкторов?

Я колебался в следующих вариантах:

 Foo::construct(); Foo::create(); Foo::factory() Foo::Foo(); constructor::Foo(); 

Именование любого метода должно быть с намерением раскрывать имена . Я не могу сказать, что делает Foo :: factory. Попытайтесь создать язык более высокого уровня:

 User::with100StartingPoints(); 

Это будет то же самое, что:

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

Вы также можете легко проверить, равен ли пользователь :: with100StartingPoints ().

Если вам не нужна ссылка на недавно созданный Foo , почему бы вам просто не сделать set_sth static функцией (и если это необходимо, чтобы создать новый Foo если это необходимо)?

Если вам нужно получить ссылку, как бы вы это сделали? return $this в set_sth ? Но тогда set_sth можно превратить в фабричную функцию.

Единственная ситуация, о которой я могу подумать, – это если вы хотите называть цепочки (как в свободном интерфейсе) цельносвязанные методы для вновь созданного экземпляра в одном выражении. Это то, что вы пытаетесь сделать?

Во всяком случае, вы можете использовать универсальную фабричную функцию для всех типов объектов, например

 function create_new($type) { return new $type; } create_new('Foo')->set_sth(); 

Статические конструкторы (или «названные конструкторы») полезны только для доказательства намерения, как говорит @koen.

Начиная с 5.4, однако, появился вызов, называемый «разыменованием», который позволяет вам непосредственно встроить экземпляр класса с вызовом метода.

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

Таким образом, статические конструкторы полезны, если у вас есть несколько способов создания объектов. Если у вас есть только один (всегда один и тот же тип аргументов и количество аргументов), нет необходимости в статических конструкторах.

Но если у вас есть несколько способов создания экземпляров, то статические конструкторы очень полезны, поскольку он позволяет избежать загрязнения вашего основного конструктора бесполезной проверкой аргументов, ослабляя ограничения языков.

Пример:

 <?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/

Это, вероятно, не совсем лучшая практика , но вы можете использовать тот факт, что функции и классы имеют два разных пространства имен: у вас может быть функция с тем же именем, что и класс.

Это позволяет написать такой код, например:

 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 

Добавление к ответу Джона : для разрешения аргументов конструктора используйте следующее:

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

Документация: ReflectionClass -> newInstanceArgs

Они называются методами создания , и я обычно createXXX() их createXXX() например createById() или createEmptyCatalog() . Мало того, что они обеспечивают хороший способ выявления различных намерений конструкторов объекта, но они позволяют немедленную цепочку методов в свободном интерфейсе.

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

Propel использует статический метод «create». Я бы пошел с этим. Этот метод упрощает тестирование кода, а не просто использует статические методы для выполнения бизнес-логики.

 <?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 сразу после метода create

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

Немного поздно, но я думаю, что это может помочь.

 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.
Это мой первый пост, и я надеюсь, что у меня есть трюки