2008-10-10 2 views
9

Идиома обычно используется в объектно-ориентированных языков, таких как Python и Ruby, является создание экземпляра объекта и цепочки методы, которые возвращают ссылку на сам объект, такие как:"Inline" Класс Instantiation в PHP? (Для простоты метода Chaining)

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(), но мне интересно, какие решения я попросил выше.

+4

С PHP 5.4 следующие работы: `(new User()) -> login() -> ...`, см. [PHP changelog] (http://php.net/ChangeLog-5.php) для 5.4 .0 * "Добавлен доступ к члену класса при создании экземпляра (например, (new foo) -> bar()) поддержка "* – hakre 2012-11-01 20:44:47

ответ

12

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

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

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

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

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

  • И да, я суров на PHP. Я использую это каждый день. Использул его в течение многих лет. Реальность такова, что она имеет нарисована, а не была спроектирована и показана.
8
<?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); 
?> 
+0

Спасибо, я принял ответ другого человека, но если бы я мог принять два, я бы принял и ваш. Тобидэ сказал о том, чтобы сгибать PHP, чтобы что-то сделать, созданный для того, чтобы сделать это особенно ощутимым для меня. – 2008-10-10 04:07:40

5

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

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

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

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

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


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

return new self(); 
+1

Использование рефлексии не стоит накладных расходов при применении метода статического метода. Не следует добавлять накладные расходы, когда накладные расходы не требуются;) – nlaq 2008-10-10 03:38:00

+0

Или мы можем следовать стандартам для отправки аргументов вам не нужно постоянно обновлять метод instance() при изменении __construct() – dcousineau 2008-10-10 03:56:07

+0

Просто идиот, чтобы что-то делать, зная, что то же самое можно сделать быстрее. «преждевременная оптимизация» отличается от «использования здравого смысла». «И мое решение не требует копирования и вставки кода. Однако - я уверен, мы оба можем согласиться с тем, что фабричный шаблон должен был использоваться в любом случае :) – nlaq 2008-10-10 04:12:07

5

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

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

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

$mail = hack(new Zend_Mail()) 
    -> setBodyText('This is the text of the mail.') 
    -> setFrom('[email protected]', 'Some Sender') 
    -> addTo('[email protected]', 'Some Recipient') 
    -> setSubject('TestSubject'); 
3

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

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

является

$result = (new ClassName())->memberFunction(); 
1
<?php 
//PHP 5.4+ class member access on instantiation support. 
$s = (new User())->login()->get_db_data()->get_session_data(); 
Смежные вопросы