¿Cómo encadenar el método en un objeto recién creado?


Me gustaría saber si hay una manera de encadenar métodos en un objeto recién creado en PHP?

Algo como:

class Foo {
    public function xyz() { ... return $this; }
}

$my_foo = new Foo()->xyz();

¿Alguien sabe de una manera de lograr esto?

Author: user2864740, 2010-02-03

7 answers

En PHP 5.4+, el analizador se ha modificado para que pueda hacer algo como esto

(new Foo())->xyz();

Envuelva la instanciación entre paréntesis y encadénela.

Antes de PHP 5.4, cuando está utilizando el

new Classname();

Sintaxis, no se puede encadenar un método de llamada de la instanciación. Es una limitación de la sintaxis de PHP 5.3. Una vez que se crea una instancia de un objeto, puede encadenarlo.

Un método que he visto utilizado para evitar esto es un método de instanciación estática de algún tipo.

class Foo
{
    public function xyz()
    {
        echo "Called","\n";
        return $this;
    }

    static public function instantiate()
    {
        return new self();
    }
}


$a = Foo::instantiate()->xyz();

Al empaquetar la llamada a new en un método estático, puede crear una instancia de una clase con la llamada al método, y luego es libre de encadenarla.

 95
Author: Alan Storm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-09 14:29:26

Defina una función global como esta:

function with($object){ return $object; }

Entonces podrás llamar:

with(new Foo)->xyz();
 23
Author: Kenaniah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 18:32:15

En PHP 5.4 puede encadenar un objeto recién instanciado:

Http://docs.php.net/manual/en/migration54.new-features.php

Para versiones anteriores de PHP, puede usar la solución de Alan Storm.

 11
Author: Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-10 16:42:35

Esta respuesta está desactualizada - por lo tanto queremos corregirla.

En PHP 5.4.x puede encadenar un método a una nueva llamada. Tomemos esta clase como ejemplo:

<?php class a {
    public function __construct() { echo "Constructed\n"; }
    public function foo() { echo "Foobar'd!\n"; }
}

Ahora, podemos usar esto: $b = (new a())->foo();

Y la salida es:

Constructed
Foobar'd!

Se puede encontrar más información en el manual: http://www.php.net/manual/en/migration54.new-features.php

 5
Author: Ingwie Phoenix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-26 22:40:18

Bueno, esta puede ser una vieja pregunta, pero al igual que con muchas cosas en la programación, eventualmente la respuesta cambia.

Con respecto a PHP 5.3, no, no se puede encadenar directamente desde el constructor. Para ampliar la respuesta aceptada sin embargo, con el fin de acomodar adecuadamente para la herencia, puede hacer:

abstract class Foo 
{    
    public static function create() 
    {
        return new static;
    }
}

class Bar extends Foo
{
    public function chain1()
    {
        return $this;
    }

    public function chain2()
    {
        return $this;
    }
}

$bar = Bar::create()->chain1()->chain2();

Eso funcionará bien y te devolverá una nueva instancia de Bar ().

En PHP 5.4, sin embargo, simplemente puede hacer:

$bar = (new Bar)->chain1()->chain2();

Esperemos que esto ayude a alguien a tropezar a través de la pregunta como tengo!

 2
Author: Lukey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-30 09:23:57

Sería realmente útil si 'arreglar esto' en una versión futura. Realmente aprecio la capacidad de encadenar (especialmente cuando se llenan colecciones):

Agregué un método a la clase base de mi framework llamado create() que puede ser encadenado. Debería funcionar con todas las clases descendientes automáticamente.

class baseClass
{
    ...
    public final static function create()
    {
        $class = new \ReflectionClass(get_called_class());
        return $class->newInstance(func_get_args());
    }
    ...
    public function __call($method, $args)
    {
        $matches = array();
        if (preg_match('/^(?:Add|Set)(?<prop>.+)/', $method, $matches) > 0)
        {
            //  Magic chaining method
            if (property_exists($this, $matches['prop']) && count($args) > 0)
            {
                $this->$matches['prop'] = $args[0];
                return $this;
            }
        }
    }
    ...
}

Class:: create () - >setName ('Kris') - >SetAge (36);

 1
Author: Kris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-14 06:58:31

Solo por el bien de la integridad (y por la diversión de ello...), ya que nadie parece haber mencionado la solución con el código más corto (y menos sofisticado).

Para objetos de corta duración utilizados con frecuencia, especialmente cuando se escriben casos de prueba, donde normalmente se crea un montón de objetos, es posible que desee optimizar para la comodidad de escritura (en lugar de pureza), y sorta combina el método de fábrica de Alan Storm Foo::instantiate() y la técnica de función global de Kenaniah with().

Simplemente hacer el método de fábrica a función global con el mismo nombre que la clase!. ;- o (O bien agregarlo como un envoltorio de conveniencia alrededor de la estática adecuada Foo::instantiate() o simplemente moverlo hacia fuera allí mientras nadie está mirando.)

class Foo
{
    public function xyz()
    {
        echo "Called","\n";
        return $this;
    }
}

function Foo()
{
    return new Foo();
}

$a = Foo()->xyz();

NOTA:

  • YO NO HARÍA ESTO en código de producción. Aunque un poco' sexy, esto es un abuso de los principios básicos de codificación (como "principio de menor sorpresa" (aunque esto es en realidad una sintaxis bastante intuitiva), o "no te repitas", esp. si envolver un método de fábrica real con algunos parámetros, que en sí mismo, por cierto, ya es un abuso de SECO...), además PHP puede cambiar en el futuro para romper código como este de maneras divertidas.
 0
Author: Sz.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-24 08:32:53