Создание экземпляра класса "Inline" в PHP? (Для простоты цепочкой)

идиома, обычно используемая в языках OO, таких как Python и Ruby, создает экземпляр объекта и методы цепочки, которые возвращают ссылку на сам объект, например:

s = User.new.login.get_db_data.get_session_data

в PHP можно реплицировать это поведение следующим образом:

$u = new User();
$s = $u->login()->get_db_data()->get_session_data();

попытка получения следующих результатов в syntax error, unexpected T_OBJECT_OPERATOR:

$s = new User()->login()->get_db_data()->get_session_data();

похоже, что это может быть достигнуто с помощью статических методов, что, вероятно, я в конечном итоге сделаю, но я хотел проверить lazyweb: есть ли на самом деле чистый, простой способ создания экземпляра классов PHP "inline" (как показано в приведенном выше фрагменте) для этой цели?

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

Я думаю, что я также мог бы предварительно создать экземпляр UserFactory с помощью метода get_user (), но мне любопытно о решениях того, что я спросил выше.

6 ответов


все эти предлагаемые решения усложняют ваш код, чтобы согнуть PHP для достижения некоторой синтаксической тонкости. Желание, чтобы PHP был чем-то, что это не так (например, хорошо), - это путь к безумию.

Я бы просто использовать:

$u = new User();
$s = $u->login()->get_db_data()->get_session_data();

это ясно, относительно лаконично и не включает в себя черная магия это может привести к ошибкам.

и, конечно, вы всегда можете перейти на Ruby или Python. Это изменит вашу жизнь.

  • и да, я я суров к PHP. Я пользуюсь им каждый день. Использую его в течение многих лет. Реальность такова, что она имеет наращенная, а не был разработан, и это видно.

<?php

    class User
    {
        function __construct()
        {
        }

        function Login()
        {
            return $this;
        }

        function GetDbData()
        {
            return $this;
        }

        function GetSession()
        {
            return array("hello" => "world");
        }
    }

    function Create($name)
    {
        return new $name();
    }

    $s = Create("User")->Login()->GetDbData()->GetSession();

    var_dump($s);
?>

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

или если вы не возражаете немного накладные расходы:

<?php

    class User
    {
        function __construct($test)
        {
            echo $test;
        }
...
    }

    function CreateArgs($name)
    {
        $ref = new ReflectionClass($name);
        return $ref->newInstanceArgs(array_slice(func_get_args(), 1));
    }

    $s = CreateArgs("User", "hi")->Login()->GetDbData()->GetSession();

    var_dump($s);
?>

единственный способ получить что-то подобное-это использовать статический метод factory или singleton. Например:

class User
{
    //...
    /**
     *
     * @return User
     */
    public static function instance()
    {
        $args = func_get_args();
        $class = new ReflectionClass(__CLASS__);
        return $class->newInstanceArgs($args);
    }
    //...
}

который использует API отражения PHP5 для создания нового экземпляра (используя любые args, отправленные в:: instance ()) и возвращает его, позволяя вам выполнять цепочку:

$s = User::instance()->login()->get_db_data()->get_session_data();

кстати, этот код достаточно гибкий, что единственное, что вам нужно будет изменить при копировании этого статического метода, - это @return комментария PHPDoc.


Если вы хотите преждевременно оптимизируйте свой код, как наш друг Нельсон, вы можете заменить содержимое User:: instance() на:

return new self();

нет причин склеивать хак (чтобы обойти проблему синтаксиса) и сам код создания объекта.

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

function hack($obj) { return $obj; }

$mail = hack(new Zend_Mail())
  -> setBodyText('This is the text of the mail.')
  -> setFrom('somebody@example.com', 'Some Sender')
  -> addTo('somebody_else@example.com', 'Some Recipient')
  -> setSubject('TestSubject');

простой ярлык

$Obj = new ClassName();
$result = $Obj->memberFunction();

и

$result = (new ClassName())->memberFunction();

<?php 
//PHP 5.4+ class member access on instantiation support.
$s = (new User())->login()->get_db_data()->get_session_data();