Рекомендации для статических конструкторов
Я хочу создать экземпляр класса и вызвать метод в этом экземпляре в одной строке кода.
PHP не позволит вызывать метод на регулярном конструкторе:
new Foo()->set_sth(); // Outputs an error.
Итак, я использую, если можно так выразиться, статический конструктор:
Foo::construct()->set_sth();
Вот мой вопрос:
Использует статические конструкторы, подобные рассмотренным как хорошая практика, и если да, как бы вы рекомендовали называть методы для этих статических конструкторов?
Я колебался в следующих вариантах:
Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
Ответы
Ответ 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.
Это мой первый пост, и я надеюсь, что у меня получится трюки.