Идиома, обычно используемая в языках 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 (), но мне интересно, какие решения я попросил выше.
Все эти предлагаемые решения усложняют ваш код, чтобы сгибать PHP, чтобы выполнить некоторые синтаксические тонкости. Желание PHP быть чем-то не таким (как хороший) – это путь к безумию.
Я бы просто использовал:
$u = new User(); $s = $u->login()->get_db_data()->get_session_data();
Это ясно, относительно лаконично и не содержит черной магии, которая может вводить ошибки.
И, конечно же, вы всегда можете перейти на Ruby или Python. Это изменит вашу жизнь.
<?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); ?>
Единственный способ получить что-то подобное – это статический метод фабрики или одиночного старта. Например:
class User { //... /** * * @return User */ public static function instance() { $args = func_get_args(); $class = new ReflectionClass(__CLASS__); return $class->newInstanceArgs($args); } //... }
Это использует API-интерфейс отражения PHP5 для создания нового экземпляра (с использованием любых аргументов, переданных в :: instance ()), и возвращает его, что позволяет выполнять цепочку:
$s = User::instance()->login()->get_db_data()->get_session_data();
Кстати, этот код достаточно гибкий, что единственное, что вам придется изменить при копировании этого статического метода, – это комментарий @Durnurn от 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();