Чи можна в 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.