Чи можна в PHP створити об'єкт і викликати метод у тому ж рядку?


126

Я хотів би зробити щось подібне:

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

Замість того, щоб робити:

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

Результат насправді для мене не має значення в моєму конкретному випадку. Але, чи є спосіб це зробити?


4
btw, якщо ви не використовуєте 5.4 (який, мабуть, не є), ви можете визначити хелперну функцію, яка просто повертає об'єкт до ланцюжка речей ... функція з ($ obj) {return $ obj; } (вибрав трюк з laravel: P) .. тоді ви можете зробити з (новий Obj) -> метод ()
kapv89

До речі, якщо ви часто це робите, варто подумати, чи my_methodпотрібно натомість заявляти static.
ToolmakerSteve

Відповіді:


166

Функція, яку ви попросили, доступна на PHP 5.4. Ось перелік нових функцій PHP 5.4:

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

І відповідна частина нового списку функцій:

Доступ учасників класу до інстанціївання, наприклад (новий Foo) -> bar ().


9
Зауважте, що це також означає, що ви можете робити, (new Foo)->propertyякщо хочете.
dave1010

1
Зверніть увагу, що ви ще не можете призначити властивості таким чином. (новий Foo) -> свойство = 'властивість';
CMCDragonkai

7
@CMCDragonkai логічно, що має сенс; об’єкт існує лише протягом тривалості оператора (new Foo)->property- значення, яке ви зберігаєте, нікуди не дінеться, оскільки об’єкт після цього більше не буде існувати, оскільки він ніде не зберігається.
thomasrutter

1
@CMCDragonkai Ви можете призначити властивості таким чином, зателефонувавши до відповідних сетерів. Все, що вам потрібно зробити, - це додати return $thisдо своїх сетерів. Це також дозволить ланцюжком сетерів.
iloo

У мене є питання. Чи є якась користь оголошення об’єкта в окремому рядку та збереження його до змінної, окрім можливості повторного використання об'єкта?
Tyler Swartzenburg

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

І тепер стає можливим використовувати однолінійний лайнер, як ви просили - єдине, що ви викликаєте функцію, таким чином, не використовуючи нову:

$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
Приємне рішення, оскільки воно підкреслює дурість цього обмеження :)
Оле


16

Ні, це неможливо.
Вам потрібно призначити екземпляр змінній, перш ніж ви зможете викликати будь-який із його методів.

Якщо ви дійсно не хочете цього робити, ви можете використовувати завод, як пропонує ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();

4
Відповідь Піма правильна. Крім того, ви можете використовувати статичні функції, якщо не хочете створити екземпляр об’єкта
Марк

використовуючи це, ми змушені використовувати public static functionзамість цього public function. Рекомендується використовувати статичний?
ічімару

6

Ви можете використовувати статичний заводський метод для отримання об'єкта:

ObjectFactory::NewObj()->method();

3
Не потрібно окремої фабрики; статичний метод у тому ж класі виконає те саме.
Brilliand

3

Я теж шукав однолінійку, щоб виконати це як частину одного виразу для перетворення дат з одного формату в інший. Мені подобається робити це в одному рядку коду, тому що це єдина логічна операція. Таким чином, це трохи загадково, але це дозволяє інстанціювати та використовувати об'єкт дати в одному рядку:

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

Ще одним способом однолінійного перетворення рядків дат з одного формату в інший є використання допоміжної функції для управління частинами OO коду:

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

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

Я думаю, що об'єктно-орієнтований підхід є крутим і необхідним, але іноді він може бути виснажливим, вимагаючи занадто багато кроків для виконання простих операцій.


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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.