Подтвердить что ты не робот

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

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

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

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

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

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

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

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

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

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

Ответ 1

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

User::with100StartingPoints();

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

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

Вы также можете легко проверить, соответствует ли User:: with100StartingPoints() этому.

Ответ 2

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

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

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

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

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

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

Ответ 3

Статические конструкторы (или "названные конструкторы" ) полезны только для доказательства намерения, как говорит @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/

Ответ 4

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

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

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

Ответ 5

Дополнение к Jon 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

Ответ 6

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

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

Ответ 7

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();

Ответ 8

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

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