No PHP, você pode instanciar um objeto e chamar um método na mesma linha?

126

O que eu gostaria de fazer é algo como isto:

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

Em vez de ter que fazer:

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

O resultado realmente não importa para mim no meu caso específico. Mas, existe uma maneira de fazer isso?

weotch
fonte
4
btw, se você não estiver usando o 5.4 (o que provavelmente não está), você pode definir uma função auxiliar que apenas retorna um objeto para encadear coisas ... função com ($ obj) {return $ obj; } (Escolheu o truque de laravel: P) .. então você pode fazer com (novo Obj) -> () método
kapv89
BTW, se você se encontra fazendo isso com frequência, vale a pena considerar se my_methoddeve ou não ser declarado static.
ToolmakerSteve

Respostas:

166

O recurso que você solicitou está disponível no PHP 5.4. Aqui está a lista de novos recursos no PHP 5.4:

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

E a parte relevante da lista de novos recursos:

O acesso de membro da classe por instanciação foi adicionado, por exemplo , (novo Foo) -> bar ().

Delian Krustev
fonte
9
Observe que isso também significa que você pode fazer (new Foo)->propertyse quiser.
precisa saber é o seguinte
1
Observe que você ainda não pode atribuir propriedades dessa maneira. (novo Foo) -> propriedade = 'propriedade';
CMCDragonkai
7
@CMCDragonkai logicamente isso faz sentido; o objeto existe apenas durante a duração da instrução (new Foo)->property- o valor que você está armazenando não tem para onde ir porque o objeto não existirá mais depois disso, pois não será armazenado em nenhum lugar.
thomasrutter
1
@CMCDragonkai Você pode atribuir propriedades dessa maneira chamando os setters correspondentes , tudo que você precisa fazer é adicionar return $thisaos seus setters. Isso também permitirá que você encadeie os setters.
Iloo
Eu tenho uma pergunta. Existe algum benefício em declarar o objeto em uma linha separada e salvá-lo em uma variável, além de poder reutilizá-lo?
Tyler Swartzenburg
37

Você não pode fazer o que está pedindo; mas você pode "trapacear", usando o fato de que, no PHP, você pode ter uma função que tem o mesmo nome que uma classe; esses nomes não entrarão em conflito.

Portanto, se você declarou uma classe como esta:

class Test {
    public function __construct($param) {
        $this->_var = $param;
    }
    public function myMethod() {
        return $this->_var * 2;
    }
    protected $_var;
}

Você pode declarar uma função que retorna uma instância dessa classe - e tem exatamente o mesmo nome da classe:

function Test($param) {
    return new Test($param);
}

E agora, torna-se possível usar uma linha, como você perguntou - a única coisa é que você está chamando a função, portanto, não usando new:

$a = Test(10)->myMethod();
var_dump($a);

E funciona: aqui estou recebendo:

int 20

como saída.


E, melhor, você pode colocar algum phpdoc em sua função:

/**
 * @return Test
 */
function Test($param) {
    return new Test($param);
}

Dessa forma, você ainda terá dicas em seu IDE - pelo menos, com o Eclipse PDT 2.x; veja o screeshot:



Edit 30/11/2010: Apenas para informação, um novo RFC foi enviado há alguns dias atrás que propõe adicionar esse recurso a uma das futuras versões do PHP.

Consulte: Solicitação de comentários: acesso à instância e chamada de método / propriedade

Então, talvez fazer coisas como essas seja possível no PHP 5.4 ou em outra versão futura:

(new foo())->bar()
(new $foo())->bar
(new $bar->y)->x
(new foo)[0]
Pascal MARTIN
fonte
19

Você pode fazer isso de maneira mais universal, definindo uma função de identidade:

function identity($x) {
    return $x;
}

identity(new Obj)->method();

Dessa forma, você não precisa definir uma função para cada classe.

Tom Pažourek
fonte
10
Boa solução, uma vez que enfatiza a estupidez dessa limitação :)
Ole
19

E se:

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

: P

Jeff
fonte
16

Não, isso não é possível.
Você precisa atribuir a instância a uma variável antes de poder chamar qualquer um de seus métodos.

Se você realmente não quiser fazer isso, poderá usar uma fábrica, como sugere a ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Pim Jager
fonte
4
A resposta de Pim está correta. Alternativamente, você pode usar funções estáticas se você não deseja criar uma instância do objeto
Mark
usando isso, somos forçados a usar em public static functionvez de public function. É recomendado o uso de estática?
Ichimaru
6

Você pode usar um método estático de fábrica para produzir o objeto:

ObjectFactory::NewObj()->method();
Ropstah
fonte
3
Não há necessidade de uma fábrica separada; um método estático na mesma classe realizará a mesma coisa.
Brilliand
3

Eu também estava procurando uma linha única para fazer isso como parte de uma única expressão para converter datas de um formato para outro. Eu gosto de fazer isso em uma única linha de código, porque é uma única operação lógica. Portanto, isso é um pouco enigmático, mas permite instanciar e usar um objeto de data em uma única linha:

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

Outra maneira de converter em uma linha as seqüências de datas de um formato para outro é usar uma função auxiliar para gerenciar as partes OO do código:

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

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

Eu acho que a abordagem orientada a objetos é legal e necessária, mas às vezes pode ser entediante, exigindo muitas etapas para realizar operações simples.

CodeCavalier
fonte
0

Vejo que isso é bastante antigo quanto às perguntas, mas aqui está algo que acho que deve ser mencionado:

O método de classe especial chamado "__call ()" pode ser usado para criar novos itens dentro de uma classe. Você o usa assim:

<?php
class test
{

function __call($func,$args)
{
    echo "I am here - $func\n";
}

}

    $a = new test();
    $a->new( "My new class" );
?>

A saída deve ser:

I am here - new

Assim, você pode enganar o PHP para criar um comando "novo" dentro de sua classe de nível superior (ou qualquer classe realmente) e colocar seu comando de inclusão na função __call () para incluir a classe que você solicitou. Obviamente, você provavelmente desejaria testar o $ func para se certificar de que é um comando "novo" enviado ao comando __call () e (é claro) que você poderia ter outros comandos também por causa do funcionamento do __call ().

Mark Manning
fonte
0

Simplesmente podemos fazer isso

$method_result = (new Obj())->method();
Aruna Perera
fonte