Можно ли в PHP создать экземпляр объекта и вызвать метод в той же строке?

126

Я бы хотел сделать что-то вроде этого:

$method_result = new Obj()->method();

Вместо того, чтобы делать:

$obj = new Obj();
$method_result = $obj->method();

В моем конкретном случае результат для меня не имеет значения. Но есть ли способ сделать это?

weotch
источник
4
кстати, если вы не используете версию 5.4 (а вы, вероятно, не используете ее), вы можете определить вспомогательную функцию, которая просто возвращает объект в цепочку ... функция с ($ obj) {return $ obj; } (взял трюк из laravel: P) .. тогда вы можете использовать (новый Obj) -> method ()
kapv89
Кстати, если вы обнаружите, что делаете это часто, стоит подумать, my_methodследует ли вместо этого декларировать static.
ToolmakerSteve

Ответы:

167

Запрошенная вами функция доступна в PHP 5.4. Вот список новых возможностей PHP 5.4:

http://php.net/manual/en/migration54.new-features.php

И соответствующая часть из списка новых функций:

Добавлен доступ к членам класса при создании экземпляра, например (new Foo) -> bar ().

Делиан Крустев
источник
9
Обратите внимание, что это также означает, что вы можете сделать это, (new Foo)->propertyесли захотите.
dave1010 07
1
Обратите внимание, что вы пока не можете назначать свойства таким способом. (новый Foo) -> свойство = 'свойство';
CMCDragonkai
7
@CMCDragonkai логически это имеет смысл; объект существует только на время действия оператора (new Foo)->property- сохраненному вами значению некуда деваться, потому что после этого объект больше не будет существовать, поскольку он нигде не хранится.
thomasrutter
1
@CMCDragonkai Вы можете назначать свойства таким образом, вызывая соответствующие сеттеры , все, что вам нужно сделать, это добавить return $thisв свои сеттеры. Это также позволит вам подключать сеттеры.
iloo 05
У меня есть вопрос. Есть ли какие-либо преимущества в объявлении объекта в отдельной строке и сохранении его в переменной, кроме возможности повторно использовать объект?
Тайлер
37

Вы не можете делать то, о чем просите; но вы можете «обмануть», используя тот факт, что в PHP вы можете иметь функцию с тем же именем, что и класс; эти имена не будут конфликтовать.

Итак, если вы объявили такой класс:

class Test {
    public function __construct($param) {
        $this->_var = $param;
    }
    public function myMethod() {
        return $this->_var * 2;
    }
    protected $_var;
}

Затем вы можете объявить функцию, которая возвращает экземпляр этого класса и имеет то же имя, что и класс:

function Test($param) {
    return new Test($param);
}

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

$a = Test(10)->myMethod();
var_dump($a);

И это работает: вот, я получаю:

int 20

как выход.


И, что еще лучше, вы можете добавить в свою функцию какой-нибудь phpdoc:

/**
 * @return Test
 */
function Test($param) {
    return new Test($param);
}

Таким образом, у вас даже будут подсказки в вашей IDE - по крайней мере, с Eclipse PDT 2.x; см. снимок:



Изменить 2010-11-30: просто для информации, несколько дней назад был представлен новый RFC, в котором предлагается добавить эту функцию в одну из будущих версий PHP.

См .: Запрос комментариев: вызов экземпляра и метода / доступ к свойству

Так что, возможно, такие вещи будут возможны в PHP 5.4 или другой будущей версии:

(new foo())->bar()
(new $foo())->bar
(new $bar->y)->x
(new foo)[0]
Паскаль МАРТИН
источник
19

Вы можете сделать это более универсально, определив функцию идентификации:

function identity($x) {
    return $x;
}

identity(new Obj)->method();

Таким образом, вам не нужно определять функцию для каждого класса.

Том Пажоурек
источник
10
Хорошее решение, так как оно подчеркивает глупость этого ограничения :)
Ole
19

Как насчет:

$obj = new Obj(); $method_result = $obj->method(); // ?

Джефф
источник
16

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

Если вы действительно не хотите этого делать, вы можете использовать фабрику, как предлагает ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Пим Ягер
источник
4
Ответ Пима правильный. В качестве альтернативы вы можете использовать статические функции, если не хотите создавать экземпляр объекта
Марк,
используя это, мы вынуждены использовать public static functionвместо public function. Рекомендуется использовать статику?
ichimaru 06
6

Вы можете использовать статический фабричный метод для создания объекта:

ObjectFactory::NewObj()->method();
Ropstah
источник
3
Нет необходимости в отдельном заводе; статический метод того же класса выполнит то же самое.
Brilliand
3

Я тоже искал однострочник, чтобы выполнить это как часть одного выражения для преобразования дат из одного формата в другой. Мне нравится делать это одной строчкой кода, потому что это единственная логическая операция. Это немного загадочно, но позволяет создавать и использовать объект даты в одной строке:

$newDateString = ($d = new DateTime('2011-08-30') ? $d->format('F d, Y') : '');

Другой способ однострочного преобразования строк даты из одного формата в другой - использовать вспомогательную функцию для управления ОО-частями кода:

function convertDate($oldDateString,$newDateFormatString) {
    $d = new DateTime($oldDateString);
    return $d->format($newDateFormatString);
}

$myNewDate = convertDate($myOldDate,'F d, Y');

Я считаю, что объектно-ориентированный подход - это круто и необходимо, но иногда он может быть утомительным, требуя слишком много шагов для выполнения простых операций.

CodeCavalier
источник
0

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

Специальный метод класса «__call ()» может использоваться для создания новых элементов внутри класса. Вы используете это так:

<?php
class test
{

function __call($func,$args)
{
    echo "I am here - $func\n";
}

}

    $a = new test();
    $a->new( "My new class" );
?>

Результат должен быть:

I am here - new

Таким образом, вы можете обманом заставить PHP создать «новую» команду внутри вашего класса верхнего уровня (или любого другого класса на самом деле) и поместить свою команду include в функцию __call (), чтобы включить класс, который вы просили. Конечно, вы, вероятно, захотите протестировать $ func, чтобы убедиться, что это «новая» команда, которая была отправлена ​​команде __call (), и (конечно) у вас могут быть другие команды также из-за того, как работает __call ().

Марк Мэннинг
источник
0

Просто мы можем это сделать

$method_result = (new Obj())->method();
Аруна Перера
источник