¿Es un principio básico, o altamente deseable, tener métodos de clase que devuelvan "$ this" en lugar de un valor?


8

Realmente acabo de comenzar a aprender POO. Comencé hace aproximadamente un año y escribí probablemente 15,000 líneas. Pero lo escribí todo con poca experiencia mirando la POO de otras personas.

La mayoría de las funciones de mi clase devuelven un valor o hacen un cambio en las propiedades de la clase y devuelven verdadero / falso. Algunos de los que devuelven un valor también guardan ese valor en una propiedad de clase (después de comprobar primero si la propiedad de clase ya está establecida, lo que puede evitar una llamada a la base de datos).

Ahora estoy investigando mucho en Magento / Zend y noto que muchos de sus métodos de clase devuelven "$ this". Según tengo entendido, a diferencia de las funciones regulares, los métodos de clase que devuelven $ this act por referencia, no por valor, para que pueda recuperar el mismo objeto con el que comenzó en lugar de una copia.

¿Devuelve $thisalgo de lo que debería estar haciendo mucho más? ¿Hace que el código sea más fácil de mantener y usar? ¿Es $thisnecesario regresar para encadenar los métodos de clase?


12
Esta es una técnica empleada para crear interfaces fluidas. Si una interfaz fluida no es su objetivo, entonces no necesita regresar $this. en.wikipedia.org/wiki/Fluent_interface
Robert Harvey

1
Es posible que desee especificar PHP aquí ...
Nathan C. Tresch

44
@Robert, deberías hacer eso una respuesta.
Karl Bielefeldt

He aquí una muestra de la interfaz fluida en PHP ( devzone.zend.com/777/fluent-interfaces-in-php )
OnesimusUnbound

2
¿Son necesarios los métodos encadenados? no();¿Son a veces muy convenientes? yes().yes().yes().yes().yes();: D
Viliam Búr

Respuestas:


14

Esta es una técnica empleada para crear interfaces fluidas. Si una interfaz fluida no es su objetivo, entonces no necesita devolver $ this.

Las interfaces fluidas le permiten escribir código que se ve así (pseudocódigo):

private void makeFluent(Customer customer) {
    customer.newOrder()
            .with(6, "TAL")
            .with(5, "HPK").skippable()
            .with(3, "LGV")
            .priorityRush();
}

Funciona, porque cada llamada al método tiene acceso al objeto original, en virtud del retorno de la llamada al método anterior this. El código anterior es más o menos equivalente a:

private void makeFluent(Customer customer) {
    var newOrder = customer.newOrder()
    newOrder.with(6, "TAL");
    newOrder.with(5, "HPK", skippable := true);
    newOrder.with(3, "LGV");
    newOrder.priorityRush();
    ...
}

thisNo siempre se devuelve. A veces se devuelve un objeto diferente. Linq funciona así, devolviendo un IEnumerable(una representación perezosa de una colección, un motor de estado modificado, básicamente) de cada método Linq en la cadena.

Se requiere más esfuerzo y previsión para crear una interfaz fluida que simplemente para establecer todos los parámetros en un constructor. Debe averiguar si el objeto tiene todo lo que necesita para ser completamente funcional, y no siempre está claro exactamente qué hace un método determinado, o en qué orden necesita llamar a los métodos. Por ejemplo:

20.minutes.ago

se ve limpio, pero ¿cómo funciona exactamente?

http://en.wikipedia.org/wiki/Fluent_interface
http://www.martinfowler.com/bliki/FluentInterface.html


2

Devolver $ this devuelve una instancia del objeto del que es miembro el método. Hay muchos casos en los que desearía hacer esto, pero hasta que comprenda exactamente lo que acabo de decir y pueda identificar un caso de uso, realmente no lo necesita.

Ejemplos de cuándo usar esto:

Un btree es un ejemplo en PHP de donde devolvería un hijo de $ this, que no es exactamente lo mismo, pero creo que tiene relación con esta discusión.

Al escribir su propio constructor, siempre devolvería $ this

Para aclarar las referencias, cuando devuelve $ this, está pasando una referencia al objeto del que forma parte el método en ejecución. Creo que las reglas de PHP para cuando está operando en una referencia frente a un valor a veces son poco claras, pero en este caso $ esto siempre es una referencia. Para ser claros: una referencia es siempre 'la instancia que tenía' y nunca una copia, mientras que un 'valor' es una copia. Estos son dos tipos de semántica de argumentos.


Entiendo Returning $this returns an instance of the object that the method is a member of.Y en PHP OOP creo, como dije en mi pregunta y usted dice en su respuesta, que la instancia que devuelve es en realidad la misma instancia que es ... es decir, no devuelve una copia de sí misma sino de sí misma. Si estoy entendiendo correctamente.
Buttle Butkus

@ButtleButkus Sí, una referencia es siempre 'la instancia que tenía' y nunca una copia, mientras que un 'valor' es una copia. Estos son dos tipos de semántica de argumentos.
Nathan C. Tresch

@ButtleButkus Modifiqué mi respuesta con esa información
Nathan C. Tresch el

1

"Una referencia de PHP es un alias, que permite que dos variables diferentes escriban en el mismo valor. A partir de PHP 5, una variable de objeto ya no contiene el objeto como valor. Solo contiene un identificador de objeto que permite a los accesores de objetos encuentre el objeto real. Cuando un objeto es enviado por argumento, devuelto o asignado a otra variable, las diferentes variables no son alias: contienen una copia del identificador, que apunta al mismo objeto ".

La verdadera ventaja de devolver $ this está en los patrones de diseño de composición de objetos, especialmente en Magento. Tomemos, por ejemplo, Mage_Core_Sales_Order_Invoice-> capture () que devuelve $ this. Este método se ve así:

  public function capture()
    {
        $this->getOrder()->getPayment()->capture($this);
        if ($this->getIsPaid()) {
            $this->pay();
        }
        return $this;
    }

la línea:

$this->getOrder()->getPayment()->capture($this);

Pasa el modelo de factura como referencia, muy útil en los patrones de composición de objetos. La devolución de $ this también es una referencia. Entonces, el método que llama -> capture () en un modelo de factura puede continuar trabajando con una llamada de objeto encadenado a continuación para facilitar la lectura del código contextual.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.