& # 8220; En línea & # 8221; ¿Instanciación de clase en PHP? (Para facilitar el método de encadenamiento)

StackOverflow https://stackoverflow.com/questions/189988

  •  06-07-2019
  •  | 
  •  

Pregunta

Un idioma comúnmente usado en lenguajes OO como Python y Ruby es instanciar un objeto y encadenar métodos que devuelven una referencia al objeto en sí, como:

s = User.new.login.get_db_data.get_session_data

En PHP, es posible replicar este comportamiento así:

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

Intentando los siguientes resultados en el error de sintaxis , T_OBJECT_OPERATOR inesperado :

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

Parece que esto podría lograrse utilizando métodos estáticos, que probablemente es lo que terminaré haciendo, pero quería comprobar lazyweb: ¿Existe realmente una manera limpia y simple de crear instancias de clases PHP " en línea " (como se muestra en el fragmento anterior) para este propósito?

Si decido usar métodos estáticos, ¿es demasiado hechicero para que el método estático de una clase devuelva una instancia de la clase misma ? (¿Escribiendo efectivamente mi propio constructor que no es un constructor?) Se siente un poco sucio, pero si no hay demasiados efectos secundarios de miedo, podría hacerlo.

Supongo que también podría crear una instancia previa de una UserFactory con un método get_user (), pero tengo curiosidad sobre las soluciones a lo que pregunté anteriormente.

¿Fue útil?

Solución

Todas estas soluciones propuestas complican su código con el fin de doblar PHP para lograr cierta sutileza sintáctica. Querer que PHP sea algo que no es (como bueno) es el camino a la locura.

Simplemente usaría:

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

Es claro, relativamente conciso y no implica magia negra que pueda introducir errores.

Y, por supuesto, siempre puedes pasar a Ruby o Python. Cambiará tu vida.

  • Y sí, soy duro con PHP. Lo uso todos los dias. Lo he estado usando por años. La realidad es que se ha acumulado , en lugar de haber sido diseñado y se nota.

Otros consejos

<?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);
?>

Esta es una posible solución :) Por supuesto, debe elegir un nombre mejor para la función ...

O si no le importa un poco de gastos generales:

<?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);
?>

La única forma de obtener algo similar es con un método estático de fábrica o singleton. Por ejemplo:

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

Que usa la API de reflexión PHP5 para crear una nueva instancia (usando cualquier argumento enviado a :: instancia ()) y lo devuelve permitiéndole hacer el encadenamiento:

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

Por cierto, ese código es lo suficientemente flexible como para que lo único que tenga que cambiar al copiar ese método estático sea el @return del comentario de PHPDoc.


Si desea optimizar prematuramente su código como nuestro amigo Nelson, puede reemplazar el contenido de Usuario :: instancia () con:

return new self();

No hay ninguna razón para mantener un truco (para solucionar el problema de sintaxis) y el código de creación de objetos en sí.

Dado que una nueva expresión no puede usarse como el miembro izquierdo de su operador de objeto, pero una expresión de llamada de función sí puede, solo necesita ajustar su objeto en una llamada a una función que devuelve su propio argumento:

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');

Un atajo simple para

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

es

$result = (new ClassName())->memberFunction();
<?php 
//PHP 5.4+ class member access on instantiation support.
$s = (new User())->login()->get_db_data()->get_session_data();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top