2008-10-10 9 views
9

Un modismo usado comúnmente en lenguajes orientados a objetos como Python y Ruby se instancias de un objeto y el encadenamiento de métodos que devuelven una referencia al objeto en sí mismo, tales como:Instanciación de clase "en línea" en PHP? (Para facilitar la método de encadenamiento)

s = User.new.login.get_db_data.get_session_data 

En PHP, se es posible replicar este comportamiento como tan:

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

Intentar los siguientes resultados en syntax error, unexpected T_OBJECT_OPERATOR:

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

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

Si decido usar métodos estáticos, es demasiado mágico tener el método estático de una clase para devolver una instanciación de la clase en sí? (¿Escribir mi propio constructor-que-no-es-un-constructor efectivamente?) 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 de UserFactory con un método get_user(), pero tengo curiosidad acerca de las soluciones a lo que pregunté anteriormente.

+4

Desde PHP 5.4, funciona lo siguiente: '(new User()) -> login() -> ...', ver [PHP changelog] (http://php.net/ChangeLog-5.php) para 5.4 .0 * "Se agregó el acceso de miembro de clase en instanciación (por ejemplo, (nuevo foo) -> barra()) support "* – hakre

Respuesta

12

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

me acaba de utilizar:

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

Está claro, relativamente concisa y no implica ningún negro magia que puede introducir errores.

Y, por supuesto, siempre puedes moverte 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 tiene acrecido, en lugar de haber sido diseñado y se nota.
+0

Prefiero Ruby, luego Python, luego PHP, pero programo regularmente en los tres. –

+1

Sí ... la lección MÁS GRANDE que he aprendido con PHP es que tienes que cortar con el grano. Trabaja con PHP y es increíble, pero comienza a querer que sea diferente y vas a cavar tu propio agujero. –

+0

Bueno, al menos ahora tengo confirmación de que no puedes hacer esto. ¿Puede indicarme en qué parte de la referencia del lenguaje PHP dice por qué no puede hacer esto? Argh. –

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

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

O si no te importa un poco de sobrecarga:

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

Gracias. Acepté la respuesta del otro compañero, pero si podía aceptar dos, también aceptaría la tuya. El punto de Tobyhede sobre doblar PHP para hacer algo que no era diseñado para hacer lo que me pareció especialmente importante. –

5

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

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

que utiliza la API PHP5 reflexión para crear una nueva instancia (utilizando cualquier argumentos enviados a :: ejemplo()) y lo devuelve lo que le permite 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 deba cambiar al copiar ese método estático sea @return, el comentario de PHPDoc.


Si desea optimizar prematuramente su código como nuestro amigo Nelson se puede sustituir el contenido de usuario :: ejemplo() con:

return new self(); 
+1

Usar el reflejo no vale la pena cuando se hace el enfoque de método estático. No debe agregar sobrecarga cuando no se requiere sobrecarga;) – nlaq

+0

O podemos seguir los estándares para enviar argumentos de manera no tiene que actualizar constantemente el método instance() cuando altera __construct() – dcousineau

+0

. Es simplemente idiota hacer algo sabiendo que lo mismo se puede hacer más rápido. "Optimizar prematuramente" es diferente de "usar el sentido común. "Y mi solución tampoco requiere copiar y pegar el código. Sin embargo, apuesto a que ambos podemos estar de acuerdo en que se debe haber usado un patrón de fábrica de todos modos :) – nlaq

5

No hay ninguna razón para unir un hack (para evitar el problema de la sintaxis) y el código de creación del objeto en sí.

Desde una nueva expresión no puede ser utilizado como el miembro izquierdo de su operador de objeto, sino una expresión de llamada a función puede, sólo es necesario para envolver 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('[email protected]', 'Some Sender') 
    -> addTo('[email protected]', 'Some Recipient') 
    -> setSubject('TestSubject'); 
+0

Este método funciona bastante bien ... – Nick

3

Un simple acceso directo a

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

es

$result = (new ClassName())->memberFunction(); 
1
<?php 
//PHP 5.4+ class member access on instantiation support. 
$s = (new User())->login()->get_db_data()->get_session_data(); 
Cuestiones relacionadas