En PHP, ¿puedes crear una instancia de un objeto y llamar a un método en la misma línea?

126

Lo que me gustaría hacer es algo como esto:

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

En lugar de tener que hacer:

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

El resultado no me importa en mi caso específico. Pero, ¿hay alguna manera de hacer esto?

weotch
fuente
44
por cierto, si no está utilizando 5.4 (que probablemente no esté utilizando), puede definir una función auxiliar que simplemente devuelva un objeto para encadenar cosas ... función con ($ obj) {return $ obj; } (recogió el truco de laravel: P) .. entonces puede hacerlo con (nuevo Obj) -> método ()
kapv89
Por cierto, si te encuentras haciendo esto a menudo, vale la pena considerar si my_methoddebería declararse static.
ToolmakerSteve

Respuestas:

167

La función que ha solicitado está disponible en PHP 5.4. Aquí está la lista de nuevas características en PHP 5.4:

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

Y la parte relevante de la lista de nuevas características:

Se ha agregado el acceso del miembro de la clase en la instanciación, por ejemplo (nuevo Foo) -> bar ().

Delian Krustev
fuente
9
Tenga en cuenta que esto también significa que puede hacerlo (new Foo)->propertysi lo desea.
dave1010
1
Tenga en cuenta que todavía no puede asignar propiedades de esta manera. (nuevo Foo) -> propiedad = 'propiedad';
CMCDragonkai
77
@CMCDragonkai lógicamente eso tiene sentido; el objeto solo existe durante la duración de la declaración (new Foo)->property; el valor que está almacenando no tiene a dónde ir porque el objeto ya no existirá después de eso, ya que no se almacena en ningún lado.
thomasrutter
1
@CMCDragonkai Puede asignar propiedades de esta manera llamando a los setters correspondientes , todo lo que necesita hacer es agregar return $thisa sus setters. Esto también te permitirá encadenar setters.
iloo
Tengo una pregunta. ¿Hay algún beneficio en declarar el objeto en una línea separada y guardarlo en una variable, además de poder reutilizar el objeto?
Tyler Swartzenburg
37

No puedes hacer lo que pides; pero puede "hacer trampa", usando el hecho de que, en PHP, puede tener una función que tenga el mismo nombre que una clase; esos nombres no entrarán en conflicto.

Entonces, si declaraste una clase como esta:

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

Luego puede declarar una función que devuelve una instancia de esa clase, y tiene exactamente el mismo nombre que la clase:

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

Y ahora, es posible usar un one-liner, como usted pidió: lo único es que está llamando a la función, por lo tanto, no está usando new:

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

Y funciona: aquí estoy obteniendo:

int 20

como salida


Y, mejor, puedes poner algo de phpdoc en tu función:

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

De esta manera, incluso tendrá pistas en su IDE, al menos, con Eclipse PDT 2.x; ver el disparo:



Editar 2010-11-30: Solo para información, se envió un nuevo RFC, hace unos días, que propone agregar esta característica a una de las futuras versiones de PHP.

Ver: Solicitud de comentarios: Llamada a la instancia y método / acceso a la propiedad

Entonces, tal vez sea posible hacer cosas como estas en PHP 5.4 u otra versión futura:

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

Puede hacerlo de manera más universal definiendo una función de identidad:

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

identity(new Obj)->method();

De esa manera, no necesita definir una función para cada clase.

Tom Pažourek
fuente
10
Buena solución ya que enfatiza la estupidez de esta limitación :)
Ole
19

Qué tal si:

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

:PAGS

Jeff
fuente
16

No, esto no es posible.
Debe asignar la instancia a una variable antes de poder llamar a cualquiera de sus métodos.

Si realmente no quieres hacer esto, puedes usar una fábrica como sugiere ropstah:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();
Pim Jager
fuente
44
La respuesta de Pim es correcta. Alternativamente, podría usar funciones estáticas si no desea crear una instancia del objeto
Marque el
usando esto, estamos obligados a usar en public static functionlugar de public function. ¿Se recomienda usar estática?
ichimaru
6

Podría usar un método de fábrica estático para producir el objeto:

ObjectFactory::NewObj()->method();
Ropstah
fuente
3
No hay necesidad de una fábrica separada; Un método estático en la misma clase logrará lo mismo.
Brilliand
3

Yo también estaba buscando una frase para lograr esto como parte de una sola expresión para convertir fechas de un formato a otro. Me gusta hacer esto en una sola línea de código porque es una operación lógica única. Entonces, esto es un poco críptico, pero le permite crear instancias y usar un objeto de fecha dentro de una sola línea:

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

Otra forma de convertir en una línea las cadenas de fecha de un formato a otro es usar una función auxiliar para administrar las partes OO del código:

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

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

Creo que el enfoque orientado a objetos es genial y necesario, pero a veces puede ser tedioso y requiere demasiados pasos para realizar operaciones simples.

CodeCavalier
fuente
0

Veo que esto es bastante antiguo a medida que van las preguntas, pero aquí hay algo que creo que debería mencionarse:

El método de clase especial llamado "__call ()" se puede utilizar para crear nuevos elementos dentro de una clase. Lo usas así:

<?php
class test
{

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

}

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

La salida debe ser:

I am here - new

Por lo tanto, puede engañar a PHP para que cree un "nuevo" comando dentro de su clase de nivel superior (o cualquier clase realmente) y poner su comando de inclusión en la función __call () para incluir la clase que ha solicitado. Por supuesto, es probable que desee probar $ func para asegurarse de que es un comando "nuevo" que se envió al comando __call () y (por supuesto) podría tener otros comandos también debido a cómo funciona __call ().

Mark Manning
fuente
0

Simplemente podemos hacer esto

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